Skip to content
Snippets Groups Projects
Commit f2a69c27 authored by Johan de Klerk's avatar Johan de Klerk
Browse files

docs: Populated response

parent 9fc0b76d
Branches
Tags
No related merge requests found
......@@ -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 DocMethodInfo struct {
Summary string `json:"summary"`
Tags []string `json:"tags"`
Parameters []DocParam `json:"parameters,omitempty"`
Responses map[string]DocResponseValue `json:"responses,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 := DocMethodInfo{}
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
// }
......@@ -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
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment