Specification
One of Gleece's powerful features is its automatic OpenAPI specification generation directly from your codebase.
This ensures that the specification will always be up-to-date with the code and can be integrated into the CI/CD pipeline to maintain consistently documented APIs.
OpenAPI Version Support
Gleece fully supports both OpenAPI versions:
Configuration
In the gleece.config.json, define the following:
- openapiGeneratorConfig->openapi: The OpenAPI version (- 3.0.0or- 3.1.0)
- openapiGeneratorConfig->specGeneratorConfig->outputPath: The generated specification file path
- openapiGeneratorConfig->info: The metadata to be added to the generated specification
- openapiGeneratorConfig->baseUrl: The base URL of the API
- openapiGeneratorConfig->securitySchemes: The security schema collection to be used in the API, which will be exposed in the OpenAPI specification and whose- namewill be used in the routes'- @Securityannotation
- openapiGeneratorConfig->defaultSecurity: The default security setting for routes without a security annotation on the route or controller, used as a fallback
See a full example below:
"openapiGeneratorConfig": {
    "openapi": "3.0.0", // Mandatory - The OpenAPI specification version to generate. Available options: "3.0.0", "3.1.0"
    "info": { // Mandatory - Metadata that will be added to the generated specification
        "title": "Sample API", // Mandatory
        "description": "This is a sample API", // Optional
        "termsOfService": "http://example.com/terms/", // Optional
        "contact": { // Optional
            "name": "API Support", // Optional
            "url": "http://www.example.com/support", // Optional
            "email": "support@example.com" // Mandatory
        },
        "license": { // Optional
            "name": "Apache 2.0", // Optional
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html" // Mandatory
        },
        "version": "1.0.0" // Mandatory - The API project version (it's the project's API version, not OpenAPI spec version)
    },
    "baseUrl": "https://api.example.com", // Mandatory 
    "securitySchemes": [ // Optional - The security schema in the API, will be exposed to the OpenAPI specification AND the "name" will be used in the routes Security annotation
        {
            "description": "API Key for accessing the API", // Mandatory
            "name": "securitySchemaName", // Mandatory - The name of the Security schema, this field will be used in the relevant Security annotations
            "fieldName": "x-header-name", // Mandatory - The name of the field in the HTTP request
            "type": "apiKey", // Mandatory - The type of authorization, see OpenAPI spec for options
            "in": "header" // Mandatory - Where the authentication data will be held - see OpenAPI spec for options
        }
    ],
    "defaultSecurity": { // Optional - The default security to set for routes without a security annotation on the route or the controller. Used as a fallback
        "name": "securitySchemaName", // Mandatory - A security schema name (defined in securitySchemes) to be used as default
        "scopes": [ // Mandatory - Collection of the scopes to be used as default
            "read:all"
        ]
    },
    "specGeneratorConfig": { // Mandatory
        "outputPath": "./openapi3.0.json" // Mandatory - The path of the generated OpenAPI specification file
    }
}
Define the API
Let's demonstrate the specification generated for a simple controller:
example.ctrl.go
package controllers
import (
    "github.com/google/uuid"
    "github.com/gopher-fleece/runtime"
)
// @Description Example object
type Example struct {
    // @Description Some text
    Text string `json:"text" validate:"required"`
    // @Description Some number
    Number int `json:"number" validate:"gte=1"`
}
// @Tag(Example)
// @Route(/base-path)
// @Security(securitySchemaName, { scopes: ["read"] })
// @Description The Example API
type ExampleController struct {
    runtime.GleeceController
}
// @Description Create an example
// @Method(POST)
// @Route(/logic/{example_name}/{example_id})
// @Query(email, { validate: "required,email" }) The exampler email
// @Path(id, { name: "example_id", validate:"gt=1" }) The example ID
// @Path(name, { name: "example_name" }) The example's name
// @Body(example) The example object
// @Header(origin, { name: "x-origin" }) The request origin
// @Header(trace) The trace ID
// @Response(200) The new ID of the example
// @ErrorResponse(500) Error when processing fails
// @Security(securitySchemaName, { scopes: ["read", "write"] })
func (ec *ExampleController) ExampleLogic(
    id int,
    email string,
    name string,
    origin string,
    trace *string,
    example Example) (string, error) {
    newId := uuid.New()
    return example.Text + " " + newId.String(), nil
}
The OpenAPI Specification
Run the Gleece command to generate the specification.
OpenAPI 3.0.0
This is how the results should look:
openapi3.0.json
{
  "openapi": "3.0.0",
  "info": {
    "contact": {
      "email": "support@example.com",
      "name": "API Support",
      "url": "http://www.example.com/support"
    },
    "description": "This is a sample API",
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "termsOfService": "http://example.com/terms/",
    "title": "Sample API",
    "version": "1.0.0"
  },
  "components": {
    "schemas": {
      "Example": {
        "description": "Example object",
        "properties": {
          "number": {
            "description": "Some number",
            "minimum": 1,
            "type": "integer"
          },
          "text": {
            "description": "Some text",
            "type": "string"
          }
        },
        "required": [
          "text"
        ],
        "title": "Example",
        "type": "object"
      },
      "Rfc7807Error": {
        "description": "A standard RFC-7807 error",
        "properties": {
          "detail": {
            "description": "A human-readable explanation specific to this occurrence of the problem.",
            "type": "string"
          },
          "error": {
            "description": "Error message",
            "type": "string"
          },
          "extensions": {
            "description": "Additional metadata about the error.",
            "type": "object"
          },
          "instance": {
            "description": "A URI reference that identifies the specific occurrence of the problem.",
            "type": "string"
          },
          "status": {
            "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
            "type": "integer"
          },
          "title": {
            "description": "A short, human-readable summary of the problem type.",
            "type": "string"
          },
          "type": {
            "description": "A URI reference that identifies the problem type.",
            "type": "string"
          }
        },
        "required": [
          "type",
          "title",
          "status"
        ],
        "title": "Rfc7807Error",
        "type": "object"
      }
    },
    "securitySchemes": {
      "securitySchemaName": {
        "description": "API Key for accessing the API",
        "in": "header",
        "name": "x-header-name",
        "type": "apiKey"
      }
    }
  },
  "paths": {
    "/base-path/logic/{example_name}/{example_id}": {
      "post": {
        "description": "Create an example",
        "operationId": "ExampleLogic",
        "parameters": [
          {
            "description": "The example ID",
            "in": "path",
            "name": "example_id",
            "required": true,
            "schema": {
              "exclusiveMinimum": true,
              "minimum": 1,
              "type": "integer"
            }
          },
          {
            "description": "The exampler email",
            "in": "query",
            "name": "email",
            "required": true,
            "schema": {
              "format": "email",
              "type": "string"
            }
          },
          {
            "description": "The example's name",
            "in": "path",
            "name": "example_name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The request origin",
            "in": "header",
            "name": "x-origin",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The trace ID",
            "in": "header",
            "name": "trace",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Example"
              }
            }
          },
          "description": "The example object",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "The new ID of the example"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rfc7807Error"
                }
              }
            },
            "description": "Error when processing fails"
          },
          "default": {
            "description": ""
          }
        },
        "security": [
          {
            "securitySchemaName": [
              "read",
              "write"
            ]
          }
        ],
        "summary": "Create an example",
        "tags": [
          "Example"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://api.example.com"
    }
  ]
}
OpenAPI 3.1.0
Changing the openapiGeneratorConfig->openapi to 3.1.0 will result in:
openapi3.1.json
{
    "openapi": "3.1.0",
    "info": {
        "title": "Sample API",
        "description": "This is a sample API",
        "termsOfService": "http://example.com/terms/",
        "contact": {
            "name": "API Support",
            "url": "http://www.example.com/support",
            "email": "support@example.com"
        },
        "license": {
            "name": "Apache 2.0",
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
        },
        "version": "1.0.0"
    },
    "servers": [
        {
            "url": "https://api.example.com"
        }
    ],
    "paths": {
        "/base-path/logic/{example_name}/{example_id}": {
            "post": {
                "tags": [
                    "Example"
                ],
                "summary": "Create an example",
                "description": "Create an example",
                "operationId": "ExampleLogic",
                "parameters": [
                    {
                        "name": "example_id",
                        "in": "path",
                        "description": "The example ID",
                        "required": true,
                        "schema": {
                            "exclusiveMinimum": 1,
                            "type": "integer"
                        }
                    },
                    {
                        "name": "email",
                        "in": "query",
                        "description": "The exampler email",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "email"
                        }
                    },
                    {
                        "name": "example_name",
                        "in": "path",
                        "description": "The example's name",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "x-origin",
                        "in": "header",
                        "description": "The request origin",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "trace",
                        "in": "header",
                        "description": "The trace ID",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "description": "The example object",
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Example"
                            }
                        }
                    },
                    "required": true
                },
                "responses": {
                    "500": {
                        "description": "Error when processing fails",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Rfc7807Error"
                                }
                            }
                        }
                    },
                    "200": {
                        "description": "The new ID of the example",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "security": [
                    {
                        "securitySchemaName": [
                            "read",
                            "write"
                        ]
                    }
                ]
            }
        }
    },
    "components": {
        "schemas": {
            "Example": {
                "type": "object",
                "properties": {
                    "text": {
                        "type": "string",
                        "description": "Some text"
                    },
                    "number": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Some number"
                    }
                },
                "title": "Example",
                "required": [
                    "text"
                ],
                "description": "Example object"
            },
            "Rfc7807Error": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "description": "A URI reference that identifies the problem type."
                    },
                    "title": {
                        "type": "string",
                        "description": "A short, human-readable summary of the problem type."
                    },
                    "status": {
                        "type": "integer",
                        "description": "The HTTP status code generated by the origin server for this occurrence of the problem."
                    },
                    "detail": {
                        "type": "string",
                        "description": "A human-readable explanation specific to this occurrence of the problem."
                    },
                    "instance": {
                        "type": "string",
                        "description": "A URI reference that identifies the specific occurrence of the problem."
                    },
                    "error": {
                        "type": "string",
                        "description": "Error message"
                    },
                    "extensions": {
                        "type": "object",
                        "description": "Additional metadata about the error."
                    }
                },
                "title": "Rfc7807Error",
                "required": [
                    "type",
                    "title",
                    "status"
                ],
                "description": "A standard RFC-7807 error"
            }
        },
        "securitySchemes": {
            "securitySchemaName": {
                "type": "apiKey",
                "description": "API Key for accessing the API",
                "name": "x-header-name",
                "in": "header"
            }
        }
    }
}