2017年2月22日水曜日

go-swagger を使ってみた

概要

swagger は REST API を開発するためのフレームワークで YAML ファイルに定義した内容からコードを生成してくれるものです
今回はその golang 版である go-swagger というものがあるので使ってみました
とりあえず YAML ファイルを定義してコードを生成して、サーバを起動するところまでになります

環境

  • CentOS 6.7 64bit
  • go-swagger dev
  • golang 1.6

インストール

  • go get -u github.com/go-swagger/go-swagger/cmd/swagger

GOPATH の設定と PATH に GOPATH/bin を追加しておいてください
インストールが完了すると swagger コマンドが使えるようになっています
あとから PATH に追加した場合は一度ログアウトして再度ログインするとコマンドが使えるようになっていると思います

プロジェクトの作成

  • mkdir -p $GOPATH/src/github.com/hawksnowlog/todo-list
  • cd $GOPATH/src/github.com/hawksnowlog/todo-list
  • swagger init spec --title "A To Do list application" --description "The product of a tutorial on goswagger.io" --version 1.0.0 --scheme http --consumes application/io.goswagger.examples.todo-list.v1+json --produces application/io.goswagger.examples.todo-list.v1+json
    • -> 2017/02/21 15:14:19 creating specification document in root/swagger.yml
  • swagger validate swagger.yml
    • -> The swagger spec at “swagger.yml” is valid against swagger specification 2.0

swagger init で雛形となる swagger.yml ファイルを作成することができます
オプションをいろいろと設定することでデフォルトの YAML ファイルに記載する内容を指定できます
作成したファイルを swagger validate でフォーマットの確認ができます
今回は作成したばかりなので特にエラーにはならないと思います

設定を追記する

swagger.yml に REST API に必要となる設定を追記していきます
追記の内容ごとに説明しており最後に YAML ファイルの全容があるので、全体はそちらを確認してください

basePath

  • emacs swagger.yml
basePath: /v1

まず初めに basePath を設定します
基本はここで設定したパス配下に対していろいろな API を生やしていきます

definitions

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

definitions でレスポンスに含まれるフィールド情報などを定義します
item というオブジェクトには id, description, completed というフィールドが含まれています
それぞれには型やフォーマットを設定することができます
生成された swagger.yml の下に追記すれば OK です

paths

  • emacs swagger.yml
paths:
  /:
    get:
      tags:
        - todos
      operationId: findTodos
      responses:
        200:
          description: list the todo operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"

次に paths を追記します
paths は「このパスに来たら」「このオブジェクトを返します」という定義をすることができます
上記の場合「/」に GET でアクセスが来たら 200 を返すという定義をしています
そしてレスポンス情報に先程定義した #/definitions/item を配列に突っ込んで返却するようにしています
tags は公式を見ると後々幸せになれるらしいので今回はおまじないとして付与しておきましょう

paths -> parameters

  • emacs swagger.yml
paths:
  /:
    get:
      tags:
        - todos
      operationId: findTodos
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list the todo operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"

先程の paths に parameters という項目を追記します
これはユーザから送信される所謂クエリパラメータ or リクエストボティ情報になります
今回追記したのはページネイト用のパラメータで「ここから何件取得する」というパラメータになります

definitions -> error

  • emacs swagger.yml
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

definitions にエラー用のレスポンス定義を追記します
definitions に error という項目を追加します
error はステータスコード (code) とエラーメッセージ (message) をレスポンスの内容に含めるように定義します

paths -> responses -> default

  • emacs swagger.yml
paths:
  /:
    get:
      tags:
        - todos
      operationId: findTodos
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list the todo operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"
        default:
          description: generic error response
          schema:
            $ref: "#/definitions/error"

「/」にアクセスしたときに default でエラーを返却するように追加します
返却するエラーオブジェクトは先程追記した #/definitions/error になります

編集後の swagger.yml

全体として以下のようになれば OK です (ちょっと長いですが)

consumes:
- application/io.goswagger.examples.todo-list.v1+json
info:
  description: The product of a tutorial on goswagger.io
  title: A To Do list application
  version: 1.0.0
produces:
- application/io.goswagger.examples.todo-list.v1+json
schemes:
- http
swagger: "2.0"
basePath: /v1
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
paths:
  /:
    get:
      tags:
        - todos
      operationId: findTodos
      parameters:
        - name: since
          in: query
          type: integer
          format: int64
        - name: limit
          in: query
          type: integer
          format: int32
          default: 20
      responses:
        200:
          description: list the todo operations
          schema:
            type: array
            items:
              $ref: "#/definitions/item"
        default:
          description: generic error response
          schema:
            $ref: "#/definitions/error"

サーバを作成する

記載した swagger.yml を元にサーバを生成します

  • swagger generate server -A TodoList -f swagger.yml

成功すると以下のファイル郡が生成されます

  • tree -a .
.
├── cmd
│   └── todo-list-server
│       └── main.go
├── models
│   ├── error.go
│   └── item.go
├── restapi
│   ├── configure_todo_list.go
│   ├── doc.go
│   ├── embedded_spec.go
│   ├── operations
│   │   ├── todo_list_api.go
│   │   └── todos
│   │       ├── get.go
│   │       ├── get_parameters.go
│   │       ├── get_responses.go
│   │       └── get_urlbuilder.go
│   └── server.go
└── swagger.yml

インストールする

サーバコードの生成が成功すると動作させたのでバイナリも作成しましょう
依存するパッケージがないといろいろとエラーになったので go get でインストールします

  • go get github.com/go-openapi/runtime
  • go get github.com/tylerb/graceful
  • go get github.com/jessevdk/go-flags
  • go get golang.org/x/net/context
  • go get github.com/docker/go-units
  • go get github.com/go-openapi/analysis
  • go get github.com/go-openapi/spec
  • go get github.com/go-openapi/validate
  • go get github.com/gorilla/context

それぞれ個別でインストールしても OK ですが面倒な場合は go-swagger リポジトリにある Gopkg.toml を使いましょう

  • wget https://raw.githubusercontent.com/go-swagger/go-swagger/master/Gopkg.toml
  • dep ensure

依存ライブラリがインストールできたらバイナリを生成しましょう

  • go install ./cmd/todo-list-server/

インストールに成功したら todo-list-server を実行すればサーバが起動します
デフォルトだと localhost からのアクセスしか受け付けていないのでホスト名やポートを指定したい場合には

  • todo-list-server --host 0.0.0.0 --port 18080

とします
起動したらルートにアクセスしてみると

  • curl localhost:18080
{"code":404,"message":"path / was not found"}

というエラーが返ってくると思います
また basePath で指定したパスにアクセスすると

  • curl localhost:18080/v1
"operation todos.Get has not yet been implemented"

が返ってきます
これを返しているのが restapi/configure_todo_list.go というファイルになっておりここを編集することでレスポンスを制御できるようになっています

最後に

go-swagger を使ってとりあえずサーバが起動するところまでやってみました
まだまだ swagger の良さを体験できるレベルではないですが、これだけでも簡単な JSON API を作れることは体験できたので、その片鱗は見れたかなと思います

次は実際にコードをいじって、動作させるところまでやってみます

参考サイト

0 件のコメント:

コメントを投稿