Skip to content

dongjwwang/my-swagger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-swagger使用说明

安装

Homebrew/Linuxbrew

brew tap go-swagger/go-swagger
brew install go-swagger

编辑OpenAPI文档

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]

生成Models

# 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

operation/policy/add_policy.go分析

// 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)

}

add_policy_parameters.go分析

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
}

add_policy_responses.go分析

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
		}
	}
}

configure_ced.go文件分析

// 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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published