brew tap go-swagger/go-swagger
brew install go-swagger
swagger: "2.0"
info:
title: CED API
description: These APIs provide services for manipulating Cloud Edge Distribution (aka CED) project.
version: "1.0"
host: local.noip.site
schemes:
- http
basePath: "/api/ced/v1/"
produces:
- application/json
consumes:
- application/json
securityDefinitions:
basic:
type: basic
security:
- basic: [ ]
- { }
paths:
# ---==== policy api ====---
/policies:
post:
summary: Create policy
description: Create policy
operationId: addPolicy
tags:
- Policy
parameters:
- $ref: "#/parameters/requestId"
- name: policy
in: body
description: The policy to create
schema:
$ref: "#/definitions/Policy"
responses:
"200":
$ref: "#/responses/200"
"500":
$ref: "#/responses/500"
parameters:
id:
name: id
description: An unique ID for specific resource
in: path
type: string
required: true
minLength: 1
requestId:
name: X-Request-Id
description: An unique ID for the request
in: header
type: string
required: false
minLength: 1
responses:
"200":
description: Success
headers:
X-Request-Id:
description: The ID of the corresponding request for the response
type: string
"500":
description: Internal server error
headers:
X-Request-Id:
description: The ID of the corresponding request for the response
type: string
schema:
$ref: "#/definitions/Errors"
definitions:
Errors:
description: The error array that describe the errors got during the handling of request
type: object
properties:
errors:
type: array
items:
$ref: "#/definitions/Error"
Error:
description: a model for all the error response coming from harbor
type: object
properties:
code:
type: string
description: The error code
message:
type: string
description: The error message
Policy:
type: object
description: The model for policy
properties:
id:
type: integer
description: The policy id
name:
type: string
description: The policy name
不再赘述OpenAPI,编写可参考参考资料[1]
# swagger generate models会生成在OpenAPI definitions定义的models
# -q静默输出,不输出日志
# -t指定生成代码的位置
# -f指定使用的OpenAPI文件
$swagger generate model -q -t src/pkg/v1 -f apis/swagger.yaml
$tree src/pkg/v1/models
src/pkg/v1/models
├── error.go
├── errors.go
└── policy.go
# swagger generate server会生成server端代码
# path下每个具体接口的tags指定方法所在目录,此例为policy
# path下每个具体接口的operationId指定方法名、入参、返回值、urlbuilder
# -q静默输出,不输出日志
# -A应用名
# -t指定生成代码的位置
# -f指定使用的OpenAPI文件
# existing-models使用已经生成models的位置,import的路径
# model-package使用的model的包名
# --exclude-main不生成main文件
# --server-package生成server包名,默认为openapi
$swagger generate server -q -A ced -t src/pkg/v1 -f ./apis/swagger.yaml --existing-models=ced/src/pkg/v1/models --model-package=models --skip-models --exclude-main --server-package=server
$tree src/pkg/v1/server
src/pkg/v1/server
├── configure_ced.go
├── doc.go
├── embedded_spec.go
├── operations
│ ├── ced_api.go
│ └── policy
│ ├── add_policy.go
│ ├── add_policy_parameters.go
│ ├── add_policy_responses.go
│ └── add_policy_urlbuilder.go
└── server.go
文件说明
文件 | 说明 |
---|---|
server.go | server端代码,可以集成在其他应用中 |
docs.go | OpenAPI定义文件,swagger客户根据此处注释生成OpenAPI文档 |
embedded_spec.go | Json格式OpenAPI文档,用于 |
configure_ced.go | 此文件不会被swagger generate server再次生成,可以进行编辑,用于填充具体实现 |
operations/ced_api.go | 组合所有的API接口 |
operation/policy/add_policy.go | addPolicy方法 |
operation/policy/add_policy_parameters.go | addPolicy方法的入参 |
operation/policy/add_policy_responses.go | addPolicy方法的返回值 |
operation/policy/add_policy_urlbuilder.go | addPolicy方法的urlbuilder |
// Code generated by go-swagger; DO NOT EDIT.
package policy
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
)
// AddPolicyHandlerFunc用于将具体的实现转为下文的Handler接口
// AddPolicyHandlerFunc turns a function with the right signature into a add policy handler
type AddPolicyHandlerFunc func(AddPolicyParams, interface{}) middleware.Responder
// Handle executing the request and returning a response
func (fn AddPolicyHandlerFunc) Handle(params AddPolicyParams, principal interface{}) middleware.Responder {
return fn(params, principal)
}
// 声明了一个Handler接口,用于实现具体的业务逻辑
// AddPolicyHandler interface for that can handle valid add policy params
type AddPolicyHandler interface {
Handle(AddPolicyParams, interface{}) middleware.Responder
}
// NewAddPolicy creates a new http.Handler for the add policy operation
func NewAddPolicy(ctx *middleware.Context, handler AddPolicyHandler) *AddPolicy {
return &AddPolicy{Context: ctx, Handler: handler}
}
/* AddPolicy swagger:route POST /policies Policy addPolicy
Create policy
Create policy
*/
type AddPolicy struct {
Context *middleware.Context
Handler AddPolicyHandler
}
func (o *AddPolicy) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewAddPolicyParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal interface{}
if uprinc != nil {
principal = uprinc.(interface{}) // this is really a interface{}, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
// 此处最重要,实际处理request
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}
path下每个具体接口的parameters字段将生成此文件
// Code generated by go-swagger; DO NOT EDIT.
package policy
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
"ced/src/pkg/v1/models"
)
// NewAddPolicyParams creates a new AddPolicyParams object
//
// There are no default values defined in the spec.
func NewAddPolicyParams() AddPolicyParams {
return AddPolicyParams{}
}
// AddPolicyParams contains all the bound params for the add policy operation
// typically these are obtained from a http.Request
//
// swagger:parameters addPolicy
type AddPolicyParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*An unique ID for the request
Min Length: 1
In: header
*/
XRequestID *string
/*The policy to create
In: body
*/
Policy *models.Policy
}
// 从Headers、Body提取Parameter信息,并进行校验
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewAddPolicyParams() beforehand.
func (o *AddPolicyParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if err := o.bindXRequestID(r.Header[http.CanonicalHeaderKey("X-Request-Id")], true, route.Formats); err != nil {
res = append(res, err)
}
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.Policy
if err := route.Consumer.Consume(r.Body, &body); err != nil {
res = append(res, errors.NewParseError("policy", "body", "", err))
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
ctx := validate.WithOperationRequest(context.Background())
if err := body.ContextValidate(ctx, route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Policy = &body
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindXRequestID binds and validates parameter XRequestID from header.
func (o *AddPolicyParams) bindXRequestID(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: false
if raw == "" { // empty values pass all other validations
return nil
}
o.XRequestID = &raw
if err := o.validateXRequestID(formats); err != nil {
return err
}
return nil
}
// validateXRequestID carries on validations for parameter XRequestID
func (o *AddPolicyParams) validateXRequestID(formats strfmt.Registry) error {
if err := validate.MinLength("X-Request-Id", "header", *o.XRequestID, 1); err != nil {
return err
}
return nil
}
path下每个具体接口的parameters字段将生成此文件,在此例中addPolicy方法有两种输出,故此文件有两个结构体,分别是状态吗200对应的结构体AddPolicyOK,状态码500对应结构体AddPolicyInternalServerError
AddPolicyOK、AddPolicyInternalServerError的方法包含两类:参数填充方法、WriteResponse方法。
因为有WriteResponse方法, 故生成的结构体都符合middleware.Responder,故可以当作实际返回值
// Code generated by go-swagger; DO NOT EDIT.
package policy
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"ced/src/pkg/v1/models"
)
// AddPolicyOKCode is the HTTP code returned for type AddPolicyOK
const AddPolicyOKCode int = 200
/*AddPolicyOK Success
swagger:response addPolicyOK
*/
type AddPolicyOK struct {
/*The ID of the corresponding request for the response
*/
XRequestID string `json:"X-Request-Id"`
}
// NewAddPolicyOK creates AddPolicyOK with default headers values
func NewAddPolicyOK() *AddPolicyOK {
return &AddPolicyOK{}
}
// WithXRequestID adds the xRequestId to the add policy o k response
func (o *AddPolicyOK) WithXRequestID(xRequestID string) *AddPolicyOK {
o.XRequestID = xRequestID
return o
}
// SetXRequestID sets the xRequestId to the add policy o k response
func (o *AddPolicyOK) SetXRequestID(xRequestID string) {
o.XRequestID = xRequestID
}
// WriteResponse to the client
func (o *AddPolicyOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
// response header X-Request-Id
xRequestID := o.XRequestID
if xRequestID != "" {
rw.Header().Set("X-Request-Id", xRequestID)
}
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(200)
}
// AddPolicyInternalServerErrorCode is the HTTP code returned for type AddPolicyInternalServerError
const AddPolicyInternalServerErrorCode int = 500
/*AddPolicyInternalServerError Internal server error
swagger:response addPolicyInternalServerError
*/
type AddPolicyInternalServerError struct {
/*The ID of the corresponding request for the response
*/
XRequestID string `json:"X-Request-Id"`
/*
In: Body
*/
Payload *models.Errors `json:"body,omitempty"`
}
// NewAddPolicyInternalServerError creates AddPolicyInternalServerError with default headers values
func NewAddPolicyInternalServerError() *AddPolicyInternalServerError {
return &AddPolicyInternalServerError{}
}
// WithXRequestID adds the xRequestId to the add policy internal server error response
func (o *AddPolicyInternalServerError) WithXRequestID(xRequestID string) *AddPolicyInternalServerError {
o.XRequestID = xRequestID
return o
}
// SetXRequestID sets the xRequestId to the add policy internal server error response
func (o *AddPolicyInternalServerError) SetXRequestID(xRequestID string) {
o.XRequestID = xRequestID
}
// WithPayload adds the payload to the add policy internal server error response
func (o *AddPolicyInternalServerError) WithPayload(payload *models.Errors) *AddPolicyInternalServerError {
o.Payload = payload
return o
}
// SetPayload sets the payload to the add policy internal server error response
func (o *AddPolicyInternalServerError) SetPayload(payload *models.Errors) {
o.Payload = payload
}
// WriteResponse to the client
func (o *AddPolicyInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
// response header X-Request-Id
xRequestID := o.XRequestID
if xRequestID != "" {
rw.Header().Set("X-Request-Id", xRequestID)
}
rw.WriteHeader(500)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
// This file is safe to edit. Once it exists it will not be overwritten
package server
import (
"crypto/tls"
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"my-chartmuseum/src/pkg/v1/server/operations"
"my-chartmuseum/src/pkg/v1/server/operations/policy"
)
//go:generate swagger generate server --target ../../v1 --name Ced --spec ../../../../apis/swagger.yaml --server-package server --principal interface{} --skip-models --exclude-main
func configureFlags(api *operations.CedAPI) {
// api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... }
}
func configureAPI(api *operations.CedAPI) http.Handler {
// configure the api here
api.ServeError = errors.ServeError
// Set your custom logger if needed. Default one is log.Printf
// Expected interface func(string, ...interface{})
//
// Example:
// api.Logger = log.Printf
api.UseSwaggerUI()
// To continue using redoc as your UI, uncomment the following line
// api.UseRedoc()
api.JSONConsumer = runtime.JSONConsumer()
api.JSONProducer = runtime.JSONProducer()
// Applies when the Authorization header is set with the Basic scheme
if api.BasicAuth == nil {
api.BasicAuth = func(user string, pass string) (interface{}, error) {
return nil, errors.NotImplemented("basic auth (basic) has not yet been implemented")
}
}
// Set your custom authorizer if needed. Default one is security.Authorized()
// Expected interface runtime.Authorizer
//
// Example:
// api.APIAuthorizer = security.Authorized()
// 指定实际的业务逻辑
if api.PolicyAddPolicyHandler == nil {
api.PolicyAddPolicyHandler = policy.AddPolicyHandlerFunc(func(params policy.AddPolicyParams, principal interface{}) middleware.Responder {
return middleware.NotImplemented("operation policy.AddPolicy has not yet been implemented")
})
}
api.PreServerShutdown = func() {}
api.ServerShutdown = func() {}
return setupGlobalMiddleware(api.Serve(setupMiddlewares))
}
// The TLS configuration before HTTPS server starts.
func configureTLS(tlsConfig *tls.Config) {
// Make all necessary changes to the TLS configuration here.
}
// As soon as server is initialized but not run yet, this function will be called.
// If you need to modify a config, store server instance to stop it individually later, this is the place.
// This function can be called multiple times, depending on the number of serving schemes.
// scheme value will be set accordingly: "http", "https" or "unix".
func configureServer(s *http.Server, scheme, addr string) {
}
// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
// The middleware executes after routing but before authentication, binding and validation.
func setupMiddlewares(handler http.Handler) http.Handler {
return handler
}
// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
// So this is a good place to plug in a panic handling middleware, logging and metrics.
func setupGlobalMiddleware(handler http.Handler) http.Handler {
return handler
}
基于上文的分析可知,只需按照格式实现具体的业务逻辑,在configure_ced文件中指定
// pkg/handler/policy.go
package handler
import (
"ced/src/pkg/v1/server/operations/policy"
"github.com/go-openapi/runtime/middleware"
)
type PolicyHandler interface {
// 必须为此入参和出参
AddPolicy(params policy.AddPolicyParams, principal interface{}) middleware.Responder
}
type policyHandler struct {
}
func NewPolicyHandle() PolicyHandler {
return &policyHandler{}
}
func (p *policyHandler) AddPolicy(params policy.AddPolicyParams, principal interface{}) middleware.Responder {
if 添加失败 {
// 使用生成的response内生成的结构,填充具体字段
return policy.NewAddPolicyInternalServerError().
WithXRequestID(*params.XRequestID).
WithPayload(errorList)
}
// 使用生成的response内生成的结构,填充具体字段
return policy.NewAddPolicyInternalServerError().
WithXRequestID(*params.XRequestID)
}
configure_ced.go
···
myPolicyHandler := handler.NewPolicyHandle()
api.PolicyGetPoliciesHandler = policy.GetPoliciesHandlerFunc(myPolicyHandler.GetPolicies)
····
$ go run src/pkg/v1/cmd/ced-server/main.go
# 访问api/ced/v1/docs,可以看到对应的OpenAPI调试界面
# 使用curl模拟访问
# 测试逻辑,X-Request-Id为500时返回码为500
curl -X 'POST' \
'http://127.0.0.1:52097/api/ced/v1/policies' \
-H 'accept: application/json' \
-H 'X-Request-Id: 500' \
-H 'Content-Type: application/json' \
-d '{
"id": 0,
"name": "string"
}'
[1] https://blog.csdn.net/lucky373125/article/details/80471525
[2] https://github.com/go-swagger/go-swagger/tree/master/examples/auto-configure