From 2adc085102d2a4151b55ffc5d3dafa5a81e8f683 Mon Sep 17 00:00:00 2001 From: Johan de Klerk <jdeklerk00@gmail.com> Date: Wed, 11 May 2022 10:43:13 +0200 Subject: [PATCH] docs - fill object schemas --- api_documentation/api_documentation.go | 68 ++++++++++++++++++++------ 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/api_documentation/api_documentation.go b/api_documentation/api_documentation.go index ef371c7..360039b 100644 --- a/api_documentation/api_documentation.go +++ b/api_documentation/api_documentation.go @@ -66,8 +66,16 @@ type DocSchemaResponse struct { func GetDocs(endpointHandlers map[string]map[string]interface{}, corePath string) (Docs, error) { docs := Docs{ - Paths: map[string]DocPath{}, - Components: DocSchemas{Schemas: map[string]interface{}{}}, + Paths: map[string]DocPath{}, + Components: DocSchemas{ + Schemas: map[string]interface{}{}, + }, + } + + // Add default error + docs.Components.Schemas["error"] = map[string]string{ + "type": "string", + "format": "string", } var validationError error @@ -90,7 +98,7 @@ func GetDocs(endpointHandlers map[string]map[string]interface{}, corePath string docMethod.Tags = []string{path} // Parameters - docParameters, err := FillParameters(handler) + docParameters, err := FillParameters(&docs, handler) if err != nil { return Docs{}, err } @@ -101,12 +109,12 @@ func GetDocs(endpointHandlers map[string]map[string]interface{}, corePath string bodyTypeString, requestBody := GetRequestBody(handler, functionDocs) docMethod.RequestBody = &requestBody + // Fill Component schemas if handler.RequestBodyType.Kind() == reflect.Struct && handler.RequestBodyType.NumField() > 0 { - schema, err := StructSchema(handler.RequestBodyType) + err := FillStructSchema(&docs, handler.RequestBodyType.Field(0).Type, bodyTypeString) if err != nil { return Docs{}, err } - docs.Components.Schemas[bodyTypeString] = schema } } @@ -114,12 +122,13 @@ func GetDocs(endpointHandlers map[string]map[string]interface{}, corePath string if handler.ResponseType != nil { response, responseBodyTypeString := GetResponse(handler) docMethod.Responses = &response + + // Fill Component schemas if handler.ResponseType.Kind() == reflect.Struct && handler.ResponseType.NumField() > 0 { - schema, err := StructSchema(handler.ResponseType) + err := FillStructSchema(&docs, handler.ResponseType, responseBodyTypeString) if err != nil { return Docs{}, err } - docs.Components.Schemas[responseBodyTypeString] = schema } } } @@ -132,7 +141,7 @@ func GetDocs(endpointHandlers map[string]map[string]interface{}, corePath string return docs, nil } -func FillParameters(handler handler_utils.Handler) ([]DocParam, error) { +func FillParameters(docs *Docs, handler handler_utils.Handler) ([]DocParam, error) { docParameters := []DocParam{} for i := 0; i < handler.RequestParamsType.NumField(); i++ { @@ -143,7 +152,7 @@ func FillParameters(handler handler_utils.Handler) ([]DocParam, error) { continue } - schema, err := StructSchema(structField.Type) + schema, err := StructSchema(docs, structField.Type) if err != nil { return nil, err } @@ -218,7 +227,7 @@ func getType(myvar interface{}) string { } } -func StructSchema(t reflect.Type) (interface{}, error) { +func StructSchema(docs *Docs, t reflect.Type) (interface{}, error) { if t == nil { return nil, nil } @@ -277,7 +286,7 @@ func StructSchema(t reflect.Type) (interface{}, error) { if fieldDesc == "" { fieldDesc = description + "." + fieldName } - properties[fieldName], err = StructSchema(f.Type) + properties[fieldName], err = StructSchema(docs, f.Type) if err != nil { return nil, errors.Wrapf(err, "failed to document %v.%s", t, fieldName) } @@ -289,12 +298,30 @@ func StructSchema(t reflect.Type) (interface{}, error) { schema["type"] = "object" case reflect.Slice: schema["type"] = "array" - element := reflect.TypeOf(t).Elem() - items, err := StructSchema(element) - if err != nil { - return nil, errors.Wrapf(err, "failed to document") + element := t.Elem() + + if element.Kind() == reflect.Struct || element.Kind() == reflect.Ptr { + elementName := getType(t) + if elementName == "" || elementName == "error" { + return schema, nil + } + schema["items"] = map[string]string{"$ref": "#/components/schemas/" + elementName} + + // Check if object is already in the struct schema + _, containsValue := docs.Components.Schemas[elementName] + if !containsValue { + err := FillStructSchema(docs, element, elementName) + if err != nil { + return nil, err + } + } + } else { + items, err := StructSchema(docs, element) + if err != nil { + return nil, errors.Wrapf(err, "failed to document") + } + schema["items"] = items } - schema["items"] = items default: return nil, errors.Errorf("cannot generate schema for %v kind=%v", t, t.Kind()) } @@ -302,6 +329,15 @@ func StructSchema(t reflect.Type) (interface{}, error) { return schema, nil } +func FillStructSchema(docs *Docs, element reflect.Type, elementName string) error { + schema, err := StructSchema(docs, element) + if err != nil { + return errors.Wrapf(err, "failed to fill struct schema for %v", elementName) + } + docs.Components.Schemas[elementName] = schema + return nil +} + func GetStructDocs(corePath string) map[string]string { docs := map[string]string{} -- GitLab