Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
bobgroup-go-utils
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Bob Public Utils
bobgroup-go-utils
Commits
f2a69c27
Commit
f2a69c27
authored
3 years ago
by
Johan de Klerk
Browse files
Options
Downloads
Patches
Plain Diff
docs: Populated response
parent
9fc0b76d
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
api_documentation/api_documentation.go
+154
-107
154 additions, 107 deletions
api_documentation/api_documentation.go
handler_utils/handler.go
+5
-0
5 additions, 0 deletions
handler_utils/handler.go
with
159 additions
and
107 deletions
api_documentation/api_documentation.go
+
154
−
107
View file @
f2a69c27
...
...
@@ -2,55 +2,74 @@ package api_documentation
import
(
"fmt"
"reflect"
"strings"
"gitlab.com/uafrica/go-utils/handler_utils"
"gitlab.com/uafrica/go-utils/errors"
)
type
NoParams
struct
{}
type
DocPath
map
[
string
]
DocMethodInfo
type
Docs
struct
{
Paths
map
[
string
]
DocPath
`json:"paths"`
}
type
DocPath
struct
{
Methods
map
[
string
]
DocMethod
`json:"methods"`
}
type
DocMethod
struct
{
Description
string
`json:"
description
"`
Parameters
map
[
string
]
DocParam
`json:"parameters,omitempty
"`
Request
interface
{}
`json:"request
,omitempty"`
Response
interface
{}
`json:"response,omitempty"`
type
DocMethod
Info
struct
{
Summary
string
`json:"
summary
"`
Tags
[]
string
`json:"tags
"`
Parameters
[]
DocParam
`json:"parameters
,omitempty"`
Response
s
map
[
string
]
DocResponseValue
`json:"response
s
,omitempty"`
}
type
DocParam
struct
{
Name
string
In
string
Type
string
Description
string
Schema
DocSchema
}
type
DocSchema
struct
{
Ref
string
`json:"$ref"`
}
type
DocResponseValue
struct
{
Description
string
`json:"description"`
Schema
*
DocSchemaResponse
`json:"schema,omitempty"`
}
type
DocSchemaResponse
struct
{
Type
*
string
`json:"type,omitempty"`
Items
DocSchema
`json:"items"`
}
func
GetDocs
(
endpointHandlers
map
[
string
]
map
[
string
]
interface
{})
(
Docs
,
error
)
{
docs
:=
Docs
{
Paths
:
map
[
string
]
DocPath
{},
}
for
path
,
methods
:=
range
endpointHandlers
{
docPath
:=
DocPath
{
Methods
:
map
[
string
]
DocMethod
{},
var
validationError
error
if
endpointHandlers
,
validationError
=
handler_utils
.
ValidateAPIEndpoints
(
endpointHandlers
);
validationError
!=
nil
{
return
Docs
{},
validationError
}
for
path
,
methods
:=
range
endpointHandlers
{
docPath
:=
DocPath
{}
for
method
,
methodHandler
:=
range
methods
{
docMethod
:=
DocMethod
{}
docMethod
:=
DocMethod
Info
{}
if
handler
,
ok
:=
methodHandler
.
(
handler_utils
.
Handler
);
!
ok
{
docMethod
.
Description
=
"Not available"
docMethod
.
Summary
=
"Not available"
}
else
{
//purpose
docMethod
.
Description
=
"Not available - see request and response structs"
docMethod
.
Summary
=
"Not available - see request and response structs"
docMethod
.
Tags
=
[]
string
{
path
}
//describe parameters
docMethod
.
Parameters
=
map
[
string
]
DocParam
{}
docMethod
.
Parameters
=
[
]
DocParam
{}
for
i
:=
0
;
i
<
handler
.
RequestParamsType
.
NumField
();
i
++
{
f
:=
handler
.
RequestParamsType
.
Field
(
i
)
...
...
@@ -59,108 +78,136 @@ func GetDocs(endpointHandlers map[string]map[string]interface{}) (Docs, error) {
name
=
f
.
Name
}
docMethod
.
Parameters
[
f
.
Name
]
=
DocParam
{
parameter
:
=
DocParam
{
Name
:
name
,
Type
:
fmt
.
Sprintf
(
"%v"
,
f
.
Type
),
Description
:
f
.
Tag
.
Get
(
"doc"
),
}
}
//describe request schema
var
err
error
docMethod
.
Request
,
err
=
DocSchema
(
fmt
.
Sprintf
(
"%s %s %s"
,
method
,
path
,
"request"
),
handler
.
RequestBodyType
)
if
err
!=
nil
{
return
Docs
{},
errors
.
Wrapf
(
err
,
"failed to document request"
)
}
docMethod
.
Response
,
err
=
DocSchema
(
fmt
.
Sprintf
(
"%s %s %s"
,
method
,
path
,
"response"
),
handler
.
ResponseType
)
if
err
!=
nil
{
return
Docs
{},
errors
.
Wrapf
(
err
,
"failed to document response"
)
}
docMethod
.
Parameters
=
append
(
docMethod
.
Parameters
,
parameter
)
}
docPath
.
Methods
[
method
]
=
docMethod
}
docs
.
Paths
[
path
]
=
docPath
}
return
docs
,
nil
if
handler
.
RequestBodyType
!=
nil
{
parameter
:=
DocParam
{
Name
:
"body"
,
In
:
"body"
,
Schema
:
DocSchema
{
Ref
:
"#/definitions/Pet"
},
}
func
DocSchema
(
description
string
,
t
reflect
.
Type
)
(
interface
{},
error
)
{
if
t
==
nil
{
return
nil
,
nil
}
schema
:=
map
[
string
]
interface
{}{
"description"
:
description
,
docMethod
.
Parameters
=
append
(
docMethod
.
Parameters
,
parameter
)
}
if
t
.
Kind
()
==
reflect
.
Ptr
{
schema
[
"optional"
]
=
true
t
=
t
.
Elem
()
}
if
handler
.
ResponseType
!=
nil
{
responses
:=
map
[
string
]
DocResponseValue
{}
switch
t
.
Kind
()
{
case
reflect
.
Int64
,
reflect
.
Int32
,
reflect
.
Int16
,
reflect
.
Int8
,
reflect
.
Int
,
reflect
.
Uint64
,
reflect
.
Uint32
,
reflect
.
Uint16
,
reflect
.
Uint8
,
reflect
.
Uint
,
reflect
.
Float64
,
reflect
.
Float32
,
reflect
.
Bool
,
reflect
.
String
:
schema
[
"type"
]
=
fmt
.
Sprintf
(
"%v"
,
t
)
responses
[
"200"
]
=
DocResponseValue
{
Description
:
"successful operation"
,
Schema
:
&
DocSchemaResponse
{
Items
:
DocSchema
{
Ref
:
"#/definitions/Pet"
},
},
}
case
reflect
.
Interface
:
schema
[
"type"
]
=
"interface{}"
//any value...?
docMethod
.
Responses
=
responses
case
reflect
.
Struct
:
schema
[
"type"
]
=
"object"
properties
:=
map
[
string
]
interface
{}{}
for
i
:=
0
;
i
<
t
.
NumField
();
i
++
{
f
:=
t
.
Field
(
i
)
if
!
f
.
Anonymous
{
fieldName
:=
f
.
Tag
.
Get
(
"json"
)
if
fieldName
==
""
{
fieldName
=
f
.
Name
}
if
fieldName
==
"-"
{
continue
//json does not marshal these
}
fieldName
=
strings
.
Replace
(
fieldName
,
",omitempty"
,
""
,
-
1
)
var
err
error
fieldDesc
:=
f
.
Tag
.
Get
(
"doc"
)
if
fieldDesc
==
""
{
fieldDesc
=
description
+
"."
+
fieldName
}
properties
[
fieldName
],
err
=
DocSchema
(
fieldDesc
,
f
.
Type
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrapf
(
err
,
"failed to document %v.%s"
,
t
,
fieldName
)
}
}
}
schema
[
"properties"
]
=
properties
case
reflect
.
Map
:
schema
[
"type"
]
=
"map"
keySchema
,
err
:=
DocSchema
(
"key"
,
t
.
Key
())
if
err
!=
nil
{
return
nil
,
errors
.
Wrapf
(
err
,
"cannot make schema for %v map key"
,
t
)
}
schema
[
"key"
]
=
keySchema
elemSchema
,
err
:=
DocSchema
(
"items"
,
t
.
Elem
())
if
err
!=
nil
{
return
nil
,
errors
.
Wrapf
(
err
,
"cannot make schema for %v map elem"
,
t
)
}
schema
[
"items"
]
=
elemSchema
case
reflect
.
Slice
:
schema
[
"type"
]
=
"array"
elemSchema
,
err
:=
DocSchema
(
"items"
,
t
.
Elem
())
if
err
!=
nil
{
return
nil
,
errors
.
Wrapf
(
err
,
"cannot make schema for %v slice elem"
,
t
)
//describe request schema
// var err error
// docMethod.Request, err = DocSchema(fmt.Sprintf("%s %s %s", method, path, "request"), handler.RequestBodyType)
// if err != nil {
// return Docs{}, errors.Wrapf(err, "failed to document request")
// }
// docMethod.Response, err = DocSchema(fmt.Sprintf("%s %s %s", method, path, "response"), handler.ResponseType)
// if err != nil {
// return Docs{}, errors.Wrapf(err, "failed to document response")
// }
}
schema
[
"items"
]
=
elemSchema
default
:
return
nil
,
errors
.
Errorf
(
"cannot generate schema for %v kind=%v"
,
t
,
t
.
Kind
())
docPath
[
strings
.
ToLower
(
method
)]
=
docMethod
}
return
schema
,
nil
docs
.
Paths
[
path
]
=
docPath
}
return
docs
,
nil
}
//
// func DocSchema(description string, t reflect.Type) (interface{}, error) {
// if t == nil {
// return nil, nil
// }
// schema := map[string]interface{}{
// "description": description,
// }
//
// if t.Kind() == reflect.Ptr {
// schema["optional"] = true
// t = t.Elem()
// }
//
// switch t.Kind() {
// case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int,
// reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint,
// reflect.Float64, reflect.Float32,
// reflect.Bool,
// reflect.String:
// schema["type"] = fmt.Sprintf("%v", t)
//
// case reflect.Interface:
// schema["type"] = "interface{}" //any value...?
//
// case reflect.Struct:
// schema["type"] = "object"
// properties := map[string]interface{}{}
// for i := 0; i < t.NumField(); i++ {
// f := t.Field(i)
// if !f.Anonymous {
// fieldName := f.Tag.Get("json")
// if fieldName == "" {
// fieldName = f.Name
// }
// if fieldName == "-" {
// continue //json does not marshal these
// }
// fieldName = strings.Replace(fieldName, ",omitempty", "", -1)
//
// var err error
// fieldDesc := f.Tag.Get("doc")
// if fieldDesc == "" {
// fieldDesc = description + "." + fieldName
// }
// properties[fieldName], err = DocSchema(fieldDesc, f.Type)
// if err != nil {
// return nil, errors.Wrapf(err, "failed to document %v.%s", t, fieldName)
// }
// }
// }
// schema["properties"] = properties
//
// case reflect.Map:
// schema["type"] = "map"
// // keySchema, err := DocSchema("key", t.Key())
// // if err != nil {
// // return nil, errors.Wrapf(err, "cannot make schema for %v map key", t)
// // }
// // schema["key"] = keySchema
// // // elemSchema, err := DocSchema("items", t.Elem())
// // if err != nil {
// // return nil, errors.Wrapf(err, "cannot make schema for %v map elem", t)
// // }
// // schema["items"] = elemSchema
//
// case reflect.Slice:
// schema["type"] = "array"
// // elemSchema, err := DocSchema("items", t.Elem())
// // if err != nil {
// // return nil, errors.Wrapf(err, "cannot make schema for %v slice elem", t)
// // }
// // schema["items"] = elemSchema
//
// default:
// return nil, errors.Errorf("cannot generate schema for %v kind=%v", t, t.Kind())
// }
//
// return schema, nil
// }
This diff is collapsed.
Click to expand it.
handler_utils/handler.go
+
5
−
0
View file @
f2a69c27
...
...
@@ -62,6 +62,11 @@ func NewHandler(handlerFunction interface{}) (Handler, error) {
return
h
,
errors
.
Errorf
(
"last result %v is not error type"
,
handlerFunctionType
.
Out
(
handlerFunctionType
.
NumOut
()
-
1
))
}
// First result is the response object
if
handlerFunctionType
.
NumOut
()
>
0
{
h
.
ResponseType
=
handlerFunctionType
.
Out
(
0
)
}
h
.
FuncValue
=
reflect
.
ValueOf
(
handlerFunction
)
return
h
,
nil
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment