Go-swagger 的安裝與使用

目錄

1、安裝與配置html

  1. 下載與安裝
  2. 添加環境變量

2、開始第一個 swagger 案例git

  1. swagger 初始化
  2. 聲明 API 接口
  3. 生成接口代碼
  4. 添加新的功能接口
  5. 代碼完善

1、安裝與配置

1.下載與安裝

附件中下載 swagger 執行包,或者從 go-swaager 官網下載,根據 OS 選擇合適的版本:github

這裏咱們下載Windows 64版本的 swagger_windows_amd64.exejson

2. 添加環境變量

swagger_windows_amd64.exe 重命名成 swagger.exe, 而後將該軟件放到 Go 安裝的根目錄的 bin下 $GOROOT/binwindows

2、開始第一個 Swagger 案例

1. swagger 初始化

新建一個 swagger_uac 空文件夾,進入文件夾中(PS:如下命令都在 Git 中運行,Git 配置):api

$ mkdir swagger_uac
$ cd swagger_uac

在 Git 中輸入如下命令:服務器

$ swagger init spec \
>   --title "User Alarm Center" \
>   --description "A Swagger Example" \
>   --version 1.0.0 \
>   --scheme http \
>   --consumes application/io.goswagger.examples.uac.v1+json \
>   --produces application/io.goswagger.examples.uac.v1+json

初始化成功:app

2020/12/17 15:05:16 creating specification document in D:\runtime\0others\swagger_uac\swagger.yml

此時, swagger_uac 文件夾中自動生成了一個 swagger.yml 文件:框架

consumes:
- application/io.goswagger.examples.uac.v1+json
info:
  description: A Swagger Example
  title: User Alarm Center
  version: 1.0.0
paths: {}
produces:
- application/io.goswagger.examples.uac.v1+json
schemes:
- http
swagger: "2.0"

無論是手動修改,仍是自動生成的 yam 文件,都須要用 $ swagger validate ./swagger.yml 檢查一下是否規範:dom

$ swagger validate ./swagger.yml
2020/12/17 15:13:14
The swagger spec at "./swagger.yml" is valid against swagger specification 2.0

2. 聲明 API 接口

上面咱們已經生成了一個框架 yam 文件,如今向文件中加入結構體對象信息:

---
definitions:
  item:
    type: object
    required:
      - description
    properties:
      id:
        type: integer
        format: int64
        readOnly: true
      description:
        type: string
        minLength: 1
      completed:
        type: boolean

item 中定義了 3 個字段:id,description,completed。上面對它們的數據類型和字段限制進行了基本定義:readOnly 是否只讀,minLength 最小長度。

而後,咱們再向 yam 文件中加入 API 接口信息:

---
paths:
  /:
    get:
      tags:
        - alarms
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list of alarm operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"

UAC 是告警模塊,因此咱們定義一個 GET/ 方法的 API 接口,標籤爲 alarms 。入參 since 爲告警查詢的最小 ID 值, limit 限制查詢的條數,默認一次查詢 20 條。響應碼定義爲 200,返回體是一個 array,這個 array 引用了咱們剛纔定義的結構體對象 $ref: "#/definitions/item"

爲了實現接口的最小功能集,咱們還應該捕獲接口的錯誤返回。接下來,咱們再定義一個 error 結構體對象,對象中有錯誤碼和錯誤信息兩個字段:

---
definitions:
  error:
    type: object
    required:
      - message
    properties:
      code:
        type: integer
        format: int64
      message:
        type: string

修改接口的 yam 定義,當響應碼不爲 200 時,返回 error 對象:

---
paths:
  /:
    get:
      tags:
        - alarms
      parameters:
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list of alarm operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"
        default:
          description: generic error response
          schema:
            $ref: "#/definitions/error"

此時,swagger.yam 中的全部代碼爲:

consumes:
- application/io.goswagger.examples.uac.v1+json
info:
  description: A Swagger Example
  title: User Alarm Center
  version: 1.0.0
paths: {}
produces:
- application/io.goswagger.examples.uac.v1+json
schemes:
- http
swagger: "2.0"
paths:
  /:
    get:
      tags:
        - alarms
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list of alarm operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"
        default:
          description: generic error response
          schema:
            $ref: "#/definitions/error"
definitions:
  item:
    type: object
    required:
      - description
    properties:
      id:
        type: integer
        format: int64
        readOnly: true
      description:
        type: string
        minLength: 1
      completed:
        type: boolean
  error:
    type: object
    required:
      - message
    properties:
      code:
        type: integer
        format: int64
      message:
        type: string

再次校驗:

$ swagger validate ./swagger.yml
2020/12/17 16:11:16
The swagger spec at "./swagger.yml" is valid against swagger specification 2.0

3. 生成接口代碼

先引入 gomod 模塊依賴管理工具, 而後經過 yam 文件生成框架代碼:

$ go mod init uac
go: creating new go.mod: module uac
$ swagger generate server -A uac -f ./swagger.yml
2020/12/17 17:06:45 validating spec D:\runtime\0others\swagger_uac\swagger.yml
2020/12/17 17:06:45 preprocessing spec with option:  minimal flattening
2020/12/17 17:06:45 building a plan for generation
2020/12/17 17:06:45 generation target ./
...
2020/12/17 17:06:45 Generation completed!

For this generation to compile you need to have some packages in your GOPATH:

        * github.com/go-openapi/runtime
        * github.com/jessevdk/go-flags

You can get these now with: go get -u -f ./...

取文末的附件安裝包,或從官網下載。安裝 tree,將安裝文件夾 /bin/ 目錄下的 tree.exe 複製到 Git 安裝的 usr 目錄的 bin下:

從新打開 Git,查看 tree 是否安裝成功:

$ tree --version
tree v1.5.2.2 (c) 1996 - 2009 by Steve Baker, Thomas Moore, Francesc Rocher, Kyosuke Tokoro

查看當前的目錄結構:

$ tree
.
|-- cmd
|   `-- uac-server
|       `-- main.go
|-- go.mod
|-- models
|   |-- error.go
|   `-- item.go
|-- restapi
|   |-- configure_uac.go
|   |-- doc.go
|   |-- embedded_spec.go
|   |-- operations
|   |   |-- alarms
|   |   |   |-- get.go
|   |   |   |-- get_parameters.go
|   |   |   |-- get_responses.go
|   |   |   `-- get_urlbuilder.go
|   |   `-- uac_api.go
|   `-- server.go
`-- swagger.yml

6 directories, 14 files

一個個文件夾看:

cmd/uac-server:文件夾名稱根據上面命令的 -A 後的參數 uac 加上 server 生成
models:yam 文件中定義的結構體對象
restapi:根據 swagger 規範中的 paths 屬性生成,tags 將操做分組到包中

此時能夠啓動服務器,首先安裝二進制文件:

$ go install ./cmd/uac-server/
go: finding module for package github.com/jessevdk/go-flags
go: finding module for package github.com/go-openapi/loads
...

運行前, 咱們先用 help 命令看一下這個服務的功能:

$ uac-server --help
Usage:
  C:\Users\y30002195\go\bin\uac-server.exe [OPTIONS]

A Swagger Example

Application Options:
      /scheme:             the listeners to enable, this can be repeated and
                           defaults to the schemes in the swagger spec
      /cleanup-timeout:    grace period for which to wait before killing idle
                           connections (default: 10s)
      /graceful-timeout:   grace period for which to wait before shutting down
                           the server (default: 15s)
      /max-header-size:    controls the maximum number of bytes the server will
                           read parsing the request header's keys and values,
                           including the request line. It does not limit the
                           size of the request body. (default: 1MiB)
      /socket-path:        the unix socket to listen on (default:
                           /var/run/uac.sock)
      /host:               the IP to listen on (default: localhost) [%HOST%]
      /port:               the port to listen on for insecure connections,
                           defaults to a random value [%PORT%]
      /listen-limit:       limit the number of outstanding requests
      /keep-alive:         sets the TCP keep-alive timeouts on accepted
                           connections. It prunes dead TCP connections ( e.g.
                           closing laptop mid-download) (default: 3m)
      /read-timeout:       maximum duration before timing out read of the
                           request (default: 30s)
      /write-timeout:      maximum duration before timing out write of the
                           response (default: 60s)
      /tls-host:           the IP to listen on for tls, when not specified it's
                           the same as --host [%TLS_HOST%]
      /tls-port:           the port to listen on for secure connections,
                           defaults to a random value [%TLS_PORT%]
      /tls-certificate:    the certificate to use for secure connections
                           [%TLS_CERTIFICATE%]
      /tls-key:            the private key to use for secure connections
                           [%TLS_PRIVATE_KEY%]
      /tls-ca:             the certificate authority file to be used with
                           mutual tls auth [%TLS_CA_CERTIFICATE%]
      /tls-listen-limit:   limit the number of outstanding requests
      /tls-keep-alive:     sets the TCP keep-alive timeouts on accepted
                           connections. It prunes dead TCP connections ( e.g.
                           closing laptop mid-download)
      /tls-read-timeout:   maximum duration before timing out read of the
                           request
      /tls-write-timeout:  maximum duration before timing out write of the
                           response

Help Options:
  /?                       Show this help message
  /h, /help                Show this help message

若是咱們如今運行應用程序,默認狀況下,它將在隨機端口啓動。咱們也能夠經過命令行參數或 port env 變量配置端口(見下文)。

$ uac-server
2020/12/17 17:53:36 Serving uac at http://127.0.0.1:57294

另起一個 Git,或者使用接口調用工具訪問服務地址:

$ curl -i http://127.0.0.1:53472
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    52  100    52    0     0  52000      0 --:--:-- --:--:-- --:--:-- 52000HTTP/1.1 501 Not Implemented
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Thu, 17 Dec 2020 11:06:36 GMT
Content-Length: 52

"operation alarms.Get has not yet been implemented"

4. 添加新的功能接口

正如你看到的那樣,調用該接口會返回 501 (接口未實現)。爲了讓當前 API 實現真正的可用性,咱們須要從邏輯上實現它。與此同時,咱們還能夠加一個告警新增的功能 post

---
paths:
  /:
    post:
      tags:
        - alarms
      operationId: addAlarm
      parameters:
        - name: body
          in: body
          schema:
            $ref: "#/definitions/item"
      responses:
        201:
          description: Created
          schema:
            $ref: "#/definitions/item"
        default:
          description: error
          schema:
            $ref: "#/definitions/error"

注意,咱們新增了 operationId 屬性,它能夠在 tags 包下面生成帶屬性名稱的 Go 文件。

接下來,咱們再定義一個刪除的功能:

---
paths:
  /{id}:
    delete:
      tags:
        - alarms
      operationId: deleteAlarm
      parameters:
        - type: integer
          format: int64
          name: id
          in: path
          required: true
      responses:
        204:
          description: Deleted
        default:
          description: error
          schema:
            $ref: "#/definitions/error"

最後,定義修改的功能(因爲/{id} 路徑是 DELETE 和 PUT 共享的,所以它們能夠共享一個參數定義):

---
paths:
	/{id}:
    parameters:
      - type: integer
        format: int64
        name: id
        in: path
        required: true 
	put:
      tags:
        - alarms
      operationId: updateAlarm
      parameters:
        - name: body
          in: body
          schema:
            $ref: "#/definitions/item"
      responses:
        '200':
          description: OK
          schema:
            $ref: "#/definitions/item"
        default:
          description: error
          schema:
            $ref: "#/definitions/error"
    delete:
      # elided for brevity

再來看看完整的 API 規範(注意縮進不要弄錯):

consumes:
- application/io.goswagger.examples.uac.v1+json
info:
  description: A Swagger Example
  title: User Alarm Center
  version: 1.0.0
paths: {}
produces:
- application/io.goswagger.examples.uac.v1+json
schemes:
- http
- https
swagger: "2.0"
paths:
  /:
    get:
      tags:
        - alarms
      operationId: getAlarms
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list of alarm operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"
        default:
          description: generic error response
          schema:
            $ref: "#/definitions/error"
    post:
      tags:
        - alarms
      operationId: addAlarm
      parameters:
        - name: body
          in: body
          schema:
            $ref: "#/definitions/item"
      responses:
        201:
          description: Created
          schema:
            $ref: "#/definitions/item"
        default:
          description: error
          schema:
            $ref: "#/definitions/error"
  /{id}:
    parameters:
      - type: integer
        format: int64
        name: id
        in: path
        required: true 
    put:
      tags:
        - alarms
      operationId: updateAlarm
      parameters:
        - name: body
          in: body
          schema:
            $ref: "#/definitions/item"
      responses:
        '200':
          description: OK
          schema:
            $ref: "#/definitions/item"
        default:
          description: error
          schema:
            $ref: "#/definitions/error"
    delete:
      tags:
        - alarms
      operationId: deleteAlarm
      parameters:
        - type: integer
          format: int64
          name: id
          in: path
          required: true
      responses:
        204:
          description: Deleted
        default:
          description: error
          schema:
            $ref: "#/definitions/error"
definitions:
  item:
    type: object
    required:
      - description
    properties:
      id:
        type: integer
        format: int64
        readOnly: true
      description:
        type: string
        minLength: 1
      completed:
        type: boolean
  error:
    type: object
    required:
      - message
    properties:
      code:
        type: integer
        format: int64
      message:
        type: string

swagger.yam 文件校驗:

$ swagger validate ./swagger.yml
2020/12/17 21:35:42
The swagger spec at "./swagger.yml" is valid against swagger specification 2.0

再次生成 API 代碼文件:

$ swagger generate server -A uac -f ./swagger.yml
2020/12/17 21:37:14 validating spec D:\runtime\0others\swagger_uac\swagger.yml
2020/12/17 21:37:14 preprocessing spec with option:  minimal flattening
...
2020/12/17 21:37:14 Generation completed!

For this generation to compile you need to have some packages in your GOPATH:

        * github.com/go-openapi/runtime
        * github.com/jessevdk/go-flags

You can get these now with: go get -u -f ./...

查看文件目錄:

$ tree
.
|-- cmd
|   `-- uac-server
|       `-- main.go
|-- go.mod
|-- go.sum
|-- models
|   |-- error.go
|   `-- item.go
|-- restapi
|   |-- configure_uac.go
|   |-- doc.go
|   |-- embedded_spec.go
|   |-- operations
|   |   |-- alarms
|   |   |   |-- add_alarm.go
|   |   |   |-- add_alarm_parameters.go
|   |   |   |-- add_alarm_responses.go
|   |   |   |-- add_alarm_urlbuilder.go
|   |   |   |-- delete_alarm.go
|   |   |   |-- delete_alarm_parameters.go
|   |   |   |-- delete_alarm_responses.go
|   |   |   |-- delete_alarm_urlbuilder.go
|   |   |   |-- get.go
|   |   |   |-- get_alarms.go
|   |   |   |-- get_alarms_parameters.go
|   |   |   |-- get_alarms_responses.go
|   |   |   |-- get_alarms_urlbuilder.go
|   |   |   |-- get_parameters.go
|   |   |   |-- get_responses.go
|   |   |   |-- get_urlbuilder.go
|   |   |   |-- update_alarm.go
|   |   |   |-- update_alarm_parameters.go
|   |   |   |-- update_alarm_responses.go
|   |   |   `-- update_alarm_urlbuilder.go
|   |   `-- uac_api.go
|   `-- server.go
`-- swagger.yml

6 directories, 31 files

5. 代碼完善

新文件生成了,但咱們還須要作一點改動,打開 restapi/configure_todo_list.go 文件。首先,在第一個函數前新增兩個全局變量:

// API 全程須要的變量
var items = make(map[int64]*models.Item)
var lastID int64

先在 configureAPI 函數中實現最簡單的 delete 方法:

api.AlarmsDeleteAlarmHandler = alarms.DeleteAlarmHandlerFunc(func(params alarms.DeleteAlarmParams) middleware.Responder {
			delete(items, params.ID)
			return alarms.NewDeleteAlarmNoContent()
		})

如上所示:咱們雖然修改了查詢告警 getAlarm 接口的規範,可是舊的代碼不會被覆蓋,因此咱們先把以前的代碼刪除掉,並添加增、改、查的代碼。

新增的所有代碼:

// API 全程須要的變量
var items = make(map[int64]*models.Item)
var lastID int64

var itemsLock = &sync.Mutex{}

func newItemID() int64 {
	return atomic.AddInt64(&lastID, 1)
}

func addItem(item *models.Item) error {
	if item == nil {
		return errors.New(500, "item must be present")
	}

	itemsLock.Lock()
	defer itemsLock.Unlock()

	newID := newItemID()
	item.ID = newID
	items[newID] = item

	return nil
}

func updateItem(id int64, item *models.Item) error {
	if item == nil {
		return errors.New(500, "item must be present")
	}

	itemsLock.Lock()
	defer itemsLock.Unlock()

	_, exists := items[id]
	if !exists {
		return errors.NotFound("not found: item %d", id)
	}

	item.ID = id
	items[id] = item
	return nil
}

func deleteItem(id int64) error {
	itemsLock.Lock()
	defer itemsLock.Unlock()

	_, exists := items[id]
	if !exists {
		return errors.NotFound("not found: item %d", id)
	}

	delete(items, id)
	return nil
}

func allItems(since int64, limit int32) (result []*models.Item) {
	result = make([]*models.Item, 0)
	for id, item := range items {
		if len(result) >= int(limit) {
			return
		}
		if since == 0 || id > since {
			result = append(result, item)
		}
	}
	return
}

func configureAPI(api *operations.UacAPI) http.Handler {
    ...
    api.AlarmsAddAlarmHandler = alarms.AddAlarmHandlerFunc(func(params alarms.AddAlarmParams) middleware.Responder {
		if err := addItem(params.Body); err != nil {
			return alarms.NewAddAlarmDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
		}
		return alarms.NewAddAlarmCreated().WithPayload(params.Body)
	})
	api.AlarmsDeleteAlarmHandler = alarms.DeleteAlarmHandlerFunc(func(params alarms.DeleteAlarmParams) middleware.Responder {
		if err := deleteItem(params.ID); err != nil {
			return alarms.NewDeleteAlarmDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
		}
		return alarms.NewDeleteAlarmNoContent()
	})

	api.AlarmsUpdateAlarmHandler = alarms.UpdateAlarmHandlerFunc(func(params alarms.UpdateAlarmParams) middleware.Responder {
		if err := updateItem(params.ID, params.Body); err != nil {
			return alarms.NewUpdateAlarmDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
		}
		return alarms.NewUpdateAlarmOK().WithPayload(params.Body)
	})

	api.AlarmsGetAlarmsHandler = alarms.GetAlarmsHandlerFunc(func(params alarms.GetAlarmsParams) middleware.Responder {
		mergedParams := alarms.NewGetAlarmsParams()
		mergedParams.Since = swag.Int64(0)
		if params.Since != nil {
			mergedParams.Since = params.Since
		}
		if params.Limit != nil {
			mergedParams.Limit = params.Limit
		}
		return alarms.NewGetAlarmsOK().WithPayload(allItems(*mergedParams.Since, *mergedParams.Limit))
	})
    ...
}

再次安裝,運行服務:

$ go install ./cmd/uac-server/
$ uac-server
2020/12/17 22:25:00 Serving uac at http://127.0.0.1:63192

調用接口,查詢成功:

$ curl -i http://127.0.0.1:63192
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     3  100     3    0     0   3000      0 --:--:-- --:--:-- --:--:--  3000HTTP/1.1 200 OK
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Thu, 17 Dec 2020 14:25:30 GMT
Content-Length: 3

[]

向 uac 中連續添加 3 條告警信息,注意 json 格式爲 application/io.goswagger.examples.uac.v1+json

$ curl -i http://127.0.0.1:63192 -d "{\"description\":\"message $RANDOM\"}" -H 'Content-Type: application/io.goswagger.examples.uac.v1+json'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    68  100    38  100    30  38000  30000 --:--:-- --:--:-- --:--:-- 68000HTTP/1.1 201 Created
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Fri, 18 Dec 2020 01:31:23 GMT
Content-Length: 38

{"description":"message 9934","id":1}
// 繼續調用兩次添加命令

查詢:

$ curl -i localhost:63192
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   118  100   118    0     0     18      0  0:00:06  0:00:06 --:--:--    27HTTP/1.1 200 OK
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Fri, 18 Dec 2020 01:33:08 GMT
Content-Length: 118

[{"description":"message 9934","id":1},{"description":"message 19901","id":2},{"description":"message 16380","id":3}]

刪除 ID 爲 1 的告警消息:

$ curl -i localhost:63192/1 -X DELETE
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 204 No Content
Date: Fri, 18 Dec 2020 01:37:31 GMT

查詢:

$ curl -i localhost:63192
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    80  100    80    0     0     12      0  0:00:06  0:00:06 --:--:--    18HTTP/1.1 200 OK
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Fri, 18 Dec 2020 01:37:49 GMT
Content-Length: 80

[{"description":"message 19901","id":2},{"description":"message 16380","id":3}]

修改 ID 爲 3 的 message 信息:

$ curl -i localhost:63192/3 -d "{\"description\":\"message has been updated\"}" -X PUT -H 'Content-Type: application/io.goswagger.examples.uac.v1+json'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    92  100    50  100    42   3125   2625 --:--:-- --:--:-- --:--:--  5750HTTP/1.1 200 OK
Content-Type: application/io.goswagger.examples.uac.v1+json
Date: Fri, 18 Dec 2020 01:49:35 GMT
Content-Length: 50

{"description":"message has been updated","id":3}

PS:除了用命令的形式,也可用 postman 或 insomnia 調用接口:

相關文章
相關標籤/搜索