tip
The OpenAPIv3
protocol is mainly used in standardized routing. Before reading the introduction to the API documentation protocol, please familiarize yourself with the standardized routing: Standard Router
I. OpenAPIv3
For a detailed introduction to the OpenAPIv3
protocol, please refer to: https://swagger.io/specification/
II. g.Meta
Metadata
API metadata information can be implemented by embedding the g.Meta
structure in the input struct and using its attribute tags.
For an introduction to the metadata component, please refer to the section: Metadata
III. Common Protocol Tags
The attribute tags in input and output structs fully support the OpenAPIv3
protocol. Once the corresponding protocol tags are added, the generated OpenAPIv3
information will automatically include the attribute.
Most tag attributes are automatically generated by the Server
component, and there are not many tags that developers need to set manually.
1. Basic Tags
Commonly used basic tags include:
Common OpenAPIv3 Tags | Description | Remarks |
---|---|---|
path | Combined with the prefix at registration to form the API URI path | Used for g.Meta to mark API metadata |
tags | The tag to which the API belongs for API classification | Used for g.Meta to mark API metadata |
method | The request method for the API: GET/PUT/POST/DELETE…(case insensitive) | Used for g.Meta to mark API metadata |
deprecated | Marks the API as deprecated | Used for g.Meta to mark API metadata |
summary | Brief description of the API/parameter | Abbreviation sm |
description | Detailed description of the API/parameter | Abbreviation dc |
in | Parameter submission method | header/path/query/cookie |
default | Default value for the parameter | Abbreviation d |
mime | The MIME type of the API, such as multipart/form-data , generally set globally, defaults to application/json . | Used for g.Meta to mark API metadata |
type | The type of the parameter, generally not needed, special parameters may require manual setting, such as file | Only applicable to parameter attributes |
tip
For more tags, please refer to the standard OpenAPIv3
protocol: https://swagger.io/specification/
In addition to the above tags, the g.Meta
of the response structure also supports additional tags to set more detailed documentation information:
Tag | Description | Remarks |
---|---|---|
status | Set the default return status code of the response | Used for g.Meta to mark API metadata, default value is 200 |
responseExample | Set the json file path of the default return example of the response | Used for g.Meta to mark API metadata, abbreviation resEg |
The json
file formats supported by responseExample
are as follows:
- Array
- Object
[
{
"code": 0,
"message": "Success",
"data": null
},
{
"code": 1,
"message": "Internal Server Error",
"data": null
}
]
{
"success": {
"code": 0,
"message": "Success",
"data": null
},
"error": {
"code": 1,
"message": "Internal Server Error",
"data": null
}
}
2. Extension Tags
In the OpenAPI
specification, all tags prefixed with x-
are customizable extension tags by developers. Extension tags can be defined in any API or attribute using Golang struct tag
format, and during the generation of API documentation, they will be returned as independent fields. For example:
package main
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type GetListReq struct {
g.Meta `path:"/user" tags:"User" method:"get" x-group:"User/Info" summary:"Get user list with basic info."`
Page int `dc:"Page number" d:"1" x-sort:"1"`
Size int `dc:"Size for per page." d:"10" x-sort:"2"`
}
type GetListRes struct{}
type Controller struct{}
func (c *Controller) GetList(ctx context.Context, req *GetListReq) (res *GetListRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
func main() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Bind(new(Controller))
})
s.SetOpenApiPath("/api.json")
s.SetSwaggerPath("/swagger")
s.SetPort(8199)
s.Run()
}
After execution, visit the address http://127.0.0.1:8199/swagger to view the swagger ui
, and visit http://127.0.0.1:8199/api.json to view the corresponding OpenAPIv3
documentation. The generated OpenAPIv3
documentation is as follows:
{
"openapi": "3.0.0",
"components": {
"schemas": {
"main.GetListReq": {
"properties": {
"Page": {
"default": 1,
"description": "Page number",
"format": "int",
"properties": {},
"type": "integer",
"x-sort": "1"
},
"Size": {
"default": 10,
"description": "Size for per page.",
"format": "int",
"properties": {},
"type": "integer",
"x-sort": "2"
}
},
"type": "object",
"x-group": "User/Info"
},
"main.GetListRes": {
"properties": {},
"type": "object"
}
}
},
"info": {
"title": "",
"version": ""
},
"paths": {
"/user": {
"get": {
"parameters": [
{
"description": "Page number",
"in": "query",
"name": "Page",
"schema": {
"default": 1,
"description": "Page number",
"format": "int",
"properties": {},
"type": "integer",
"x-sort": "1"
},
"x-sort": "1"
},
{
"description": "Size for per page.",
"in": "query",
"name": "Size",
"schema": {
"default": 10,
"description": "Size for per page.",
"format": "int",
"properties": {},
"type": "integer",
"x-sort": "2"
},
"x-sort": "2"
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/main.GetListRes"
}
}
},
"description": ""
}
},
"summary": "Get user list with basic info.",
"tags": [
"User"
],
"x-group": "User/Info"
},
"x-group": "User/Info"
}
}
}
As you can see, the extension tags have been included in the API documentation.
IV. Extending Response Structure Information
For requests that require multiple response status codes, the framework provides the IEnhanceResponseStatus
interface in the goai
component, and developers can extend the information of the response structure by implementing this interface. The related definitions are as follows:
type EnhancedStatusCode = int
type EnhancedStatusType struct {
Response any
Examples any
}
type IEnhanceResponseStatus interface {
EnhanceResponseStatus() map[EnhancedStatusCode]EnhancedStatusType
}
Response
is a response structure similar to a normal response structure, you can also add a g.Meta
tag to add documentation information, and after setting the mime
tag, the structure will also override the content of the general response structure. Examples
is a response example, you can use the error code list to automatically generate example content and display it in the document, so as to ensure the synchronization of document content and actual business content. For example:
package main
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/goai"
)
type StoreMessageReq struct {
g.Meta `path:"/messages" method:"post" summary:"Store a message"`
Content string `json:"content"`
}
type StoreMessageRes struct {
g.Meta `status:"201"`
Id string `json:"id"`
}
type EmptyRes struct {
g.Meta `mime:"application/json"`
}
type CommonRes struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
var StoreMessageErr = map[int]gcode.Code{
500: gcode.New(1, "Server Dead", nil),
}
func (r StoreMessageRes) EnhanceResponseStatus() (resList map[int]goai.EnhancedStatusType) {
examples := []interface{}{}
example500 := CommonRes{
Code: StoreMessageErr[500].Code(),
Message: StoreMessageErr[500].Message(),
Data: nil,
}
examples = append(examples, example500)
return map[int]goai.EnhancedStatusType{
403: {
Response: EmptyRes{},
},
500: {
Response: struct{}{},
Examples: examples,
},
}
}
type Controller struct{}
func (c *Controller) StoreMessage(ctx context.Context, req *StoreMessageReq) (res *StoreMessageRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
func main() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Bind(new(Controller))
})
oai := s.GetOpenApi()
oai.Config.CommonResponse = CommonRes{}
oai.Config.CommonResponseDataField = `Data`
s.SetOpenApiPath("/api.json")
s.SetSwaggerPath("/swagger")
s.SetPort(8199)
s.Run()
}
After execution, visit the address http://127.0.0.1:8199/swagger to view the swagger ui
, and visit http://127.0.0.1:8199/api.json to view the corresponding OpenAPIv3
documentation. The generated OpenAPIv3
documentation is as follows:
{
"openapi": "3.0.0",
"components": {
"schemas": {
"main.StoreMessageReq": {
"properties": {
"content": {
"format": "string",
"type": "string"
}
},
"type": "object"
},
"main.StoreMessageRes": {
"properties": {
"id": {
"format": "string",
"type": "string"
}
},
"type": "object"
},
"interface": {
"properties": {},
"type": "object"
},
"main.EmptyRes": {
"properties": {},
"type": "object"
},
"struct": {
"properties": {},
"type": "object"
}
}
},
"info": {
"title": "",
"version": ""
},
"paths": {
"/messages": {
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/main.StoreMessageReq"
}
}
}
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"properties": {
"code": {
"format": "int",
"type": "integer"
},
"message": {
"format": "string",
"type": "string"
},
"data": {
"properties": {
"id": {
"format": "string",
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
}
}
},
"description": ""
},
"403": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/main.EmptyRes"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"properties": {
"code": {
"format": "int",
"type": "integer"
},
"message": {
"format": "string",
"type": "string"
},
"data": {
"properties": {},
"type": "object"
}
},
"type": "object"
},
"examples": {
"example 1": {
"value": {
"code": 1,
"message": "Server Dead",
"data": null
}
}
}
}
},
"description": ""
}
},
"summary": "Store a message"
}
}
}
}
As you can see, the default response status code has been changed to 201
, and the response example has also been automatically generated.
V. Expanding OpenAPIv3
Information
The core API information has already been automatically generated. If developers want to further complete the API information, they can obtain the OpenAPIv3
struct object via s.GetOpenApi()
and manually fill in the corresponding attribute content. Let’s look at an example where we design a common data structure around each API:
From this, we can see that with the general OpenAPIv3
object, we can customize its content and generate various other types of custom API documentation based on it.
VI、Add api.json(swagger) custom authentication
For situations where api document authentication is required, you can use the ghttp.BindHookHandler
method to authenticate the s.GetOpenApiPath()
routing binding pre-method. The example is as follows:
func main() {
s := g.Server()
// if api.json requires authentication, add openApiBasicAuth handler
s.BindHookHandler(s.GetOpenApiPath(), ghttp.HookBeforeServe, openApiBasicAuth)
s.Run()
}
func openApiBasicAuth(r *ghttp.Request) {
if !r.BasicAuth("OpenApiAuthUserName", "OpenApiAuthPass", "Restricted") {
r.ExitAll()
return
}
}