Swaggerをやる必要がでてきた。それもすぐ。
フロントとバックエンドで別れているAPI開発で、仕様書 からコード生成してレスポンスを返すモックサーバを作ってくれる。そのツールがSwagger Tools。
[amazon_link asins=’4297103249′ template=’ProductCarousel’ store=’izayoi55-22′ marketplace=’JP’ link_id=’162b7f3e-815c-4930-8cfe-d8e37d52cf65′]
お勉強しながらまとめます(。- .•)
もくじ
Swagger導入のメリット
フロントとバックエンドで別れているチームで効果を発揮する。
- APIの定義仕様をドキュメント化できる
- APIの定義からモックサーバを作れる
この機能によってフロント側の開発がバックエンドの進捗を待つ必要がなくなる。
バックエンド側もフロント側を待たせることがなくなる。
=>スキーマ駆動
用語
SOA
サービス志向アーキテクチャ
WSDL(ウィズダル)
WEBサービス記述言語。Web Service Description Language
SOAP
Simple Object Access Protocol.WEBサービス実装の通信プロトコルのこと。
RESTとか。
Swagger Tools
Swagger Spec
YamlやJSONで記述されたSwagger Spec(Swagger仕様)がSwaggerの中核
Swagger Core
API実装からSwagger Specで記載された設計を自動生成
Swagger UI
OpenAPIで記述されたスキーマをドキュメント化するツール
Swagger Editor
OpenAPIのスキーマを記述することに特化したオンラインエディタ
- 記述構文や記述形式にマッチしない記述に警告を出してくれる
Swagger Codegen
OpenAPIのスキーマからソースコードを生成するジェネレータ。
- 様々な言語に対応している。
- Swagger Editorの中に組み込まれている。Swagger Codegen自体にはUIは存在しない。
→Generate Server, Generate Clientのメニューからプログラミング言語を選択して自動生成することができる。 - APIクライアントを自動生成することで開発の手間を省き、フロントとサーバサイドの開発を平行して進められるので圧倒的な効率化の
ふむ。概要はわかった。
Swaggerを使ってみよう
ウィザードに沿ってCreate APIしたら生成されたサンプル
swagger: '2.0' info: description: | This is a sample Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). version: 1.0.0 title: Swagger Petstore termsOfService: http://swagger.io/terms/ contact: email: apiteam@swagger.io license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html # host: petstore.swagger.io # basePath: /v2 tags: - name: pet description: Everything about your Pets externalDocs: description: Find out more url: http://swagger.io - name: store description: Access to Petstore orders - name: user description: Operations about user externalDocs: description: Find out more about our store url: http://swagger.io # schemes: # - http paths: /pet: post: tags: - pet summary: Add a new pet to the store operationId: addPet consumes: - application/json - application/xml produces: - application/json - application/xml parameters: - in: body name: body description: Pet object that needs to be added to the store required: true schema: $ref: '#/definitions/Pet' responses: 405: description: Invalid input security: - petstore_auth: - write:pets - read:pets put: tags: - pet summary: Update an existing pet operationId: updatePet consumes: - application/json - application/xml produces: - application/json - application/xml parameters: - in: body name: body description: Pet object that needs to be added to the store required: true schema: $ref: '#/definitions/Pet' responses: 400: description: Invalid ID supplied 404: description: Pet not found 405: description: Validation exception security: - petstore_auth: - write:pets - read:pets /pet/findByStatus: get: tags: - pet summary: Finds Pets by status description: Multiple status values can be provided with comma separated strings operationId: findPetsByStatus produces: - application/json - application/xml parameters: - name: status in: query description: Status values that need to be considered for filter required: true type: array items: type: string enum: - available - pending - sold default: available collectionFormat: multi responses: 200: description: successful operation schema: type: array items: $ref: '#/definitions/Pet' 400: description: Invalid status value security: - petstore_auth: - write:pets - read:pets /pet/findByTags: get: tags: - pet summary: Finds Pets by tags description: Muliple tags can be provided with comma separated strings. Use\ \ tag1, tag2, tag3 for testing. operationId: findPetsByTags produces: - application/json - application/xml parameters: - name: tags in: query description: Tags to filter by required: true type: array items: type: string collectionFormat: multi responses: 200: description: successful operation schema: type: array items: $ref: '#/definitions/Pet' 400: description: Invalid tag value security: - petstore_auth: - write:pets - read:pets deprecated: true /pet/{petId}: get: tags: - pet summary: Find pet by ID description: Returns a single pet operationId: getPetById produces: - application/json - application/xml parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: 200: description: successful operation schema: $ref: '#/definitions/Pet' 400: description: Invalid ID supplied 404: description: Pet not found security: - api_key: [] post: tags: - pet summary: Updates a pet in the store with form data operationId: updatePetWithForm consumes: - application/x-www-form-urlencoded produces: - application/json - application/xml parameters: - name: petId in: path description: ID of pet that needs to be updated required: true type: integer format: int64 - name: name in: formData description: Updated name of the pet required: false type: string - name: status in: formData description: Updated status of the pet required: false type: string responses: 405: description: Invalid input security: - petstore_auth: - write:pets - read:pets delete: tags: - pet summary: Deletes a pet operationId: deletePet produces: - application/json - application/xml parameters: - name: api_key in: header required: false type: string - name: petId in: path description: Pet id to delete required: true type: integer format: int64 responses: 400: description: Invalid ID supplied 404: description: Pet not found security: - petstore_auth: - write:pets - read:pets /pet/{petId}/uploadImage: post: tags: - pet summary: uploads an image operationId: uploadFile consumes: - multipart/form-data produces: - application/json parameters: - name: petId in: path description: ID of pet to update required: true type: integer format: int64 - name: additionalMetadata in: formData description: Additional data to pass to server required: false type: string - name: file in: formData description: file to upload required: false type: file responses: 200: description: successful operation schema: $ref: '#/definitions/ApiResponse' security: - petstore_auth: - write:pets - read:pets /store/inventory: get: tags: - store summary: Returns pet inventories by status description: Returns a map of status codes to quantities operationId: getInventory produces: - application/json parameters: [] responses: 200: description: successful operation schema: type: object additionalProperties: type: integer format: int32 security: - api_key: [] /store/order: post: tags: - store summary: Place an order for a pet operationId: placeOrder produces: - application/json - application/xml parameters: - in: body name: body description: order placed for purchasing the pet required: true schema: $ref: '#/definitions/Order' responses: 200: description: successful operation schema: $ref: '#/definitions/Order' 400: description: Invalid Order /store/order/{orderId}: get: tags: - store summary: Find purchase order by ID description: For valid response try integer IDs with value >= 1 and <= 10.\ \ Other values will generated exceptions operationId: getOrderById produces: - application/json - application/xml parameters: - name: orderId in: path description: ID of pet that needs to be fetched required: true type: integer maximum: 10.0 minimum: 1.0 format: int64 responses: 200: description: successful operation schema: $ref: '#/definitions/Order' 400: description: Invalid ID supplied 404: description: Order not found delete: tags: - store summary: Delete purchase order by ID description: For valid response try integer IDs with positive integer value.\ \ Negative or non-integer values will generate API errors operationId: deleteOrder produces: - application/json - application/xml parameters: - name: orderId in: path description: ID of the order that needs to be deleted required: true type: integer minimum: 1.0 format: int64 responses: 400: description: Invalid ID supplied 404: description: Order not found /user: post: tags: - user summary: Create user description: This can only be done by the logged in user. operationId: createUser produces: - application/json - application/xml parameters: - in: body name: body description: Created user object required: true schema: $ref: '#/definitions/User' responses: default: description: successful operation /user/createWithArray: post: tags: - user summary: Creates list of users with given input array operationId: createUsersWithArrayInput produces: - application/json - application/xml parameters: - in: body name: body description: List of user object required: true schema: type: array items: $ref: '#/definitions/User' responses: default: description: successful operation /user/createWithList: post: tags: - user summary: Creates list of users with given input array operationId: createUsersWithListInput produces: - application/json - application/xml parameters: - in: body name: body description: List of user object required: true schema: type: array items: $ref: '#/definitions/User' responses: default: description: successful operation /user/login: get: tags: - user summary: Logs user into the system operationId: loginUser produces: - application/json - application/xml parameters: - name: username in: query description: The user name for login required: true type: string - name: password in: query description: The password for login in clear text required: true type: string responses: 200: description: successful operation schema: type: string headers: X-Rate-Limit: type: integer format: int32 description: calls per hour allowed by the user X-Expires-After: type: string format: date-time description: date in UTC when token expires 400: description: Invalid username/password supplied /user/logout: get: tags: - user summary: Logs out current logged in user session operationId: logoutUser produces: - application/json - application/xml parameters: [] responses: default: description: successful operation /user/{username}: get: tags: - user summary: Get user by user name operationId: getUserByName produces: - application/json - application/xml parameters: - name: username in: path description: The name that needs to be fetched. Use user1 for testing. required: true type: string responses: 200: description: successful operation schema: $ref: '#/definitions/User' 400: description: Invalid username supplied 404: description: User not found put: tags: - user summary: Updated user description: This can only be done by the logged in user. operationId: updateUser produces: - application/json - application/xml parameters: - name: username in: path description: name that need to be updated required: true type: string - in: body name: body description: Updated user object required: true schema: $ref: '#/definitions/User' responses: 400: description: Invalid user supplied 404: description: User not found delete: tags: - user summary: Delete user description: This can only be done by the logged in user. operationId: deleteUser produces: - application/json - application/xml parameters: - name: username in: path description: The name that needs to be deleted required: true type: string responses: 400: description: Invalid username supplied 404: description: User not found securityDefinitions: petstore_auth: type: oauth2 authorizationUrl: http://petstore.swagger.io/oauth/dialog flow: implicit scopes: write:pets: modify pets in your account read:pets: read your pets api_key: type: apiKey name: api_key in: header definitions: Order: type: object properties: id: type: integer format: int64 petId: type: integer format: int64 quantity: type: integer format: int32 shipDate: type: string format: date-time status: type: string description: Order Status enum: - placed - approved - delivered complete: type: boolean default: false xml: name: Order Category: type: object properties: id: type: integer format: int64 name: type: string xml: name: Category User: type: object properties: id: type: integer format: int64 username: type: string firstName: type: string lastName: type: string email: type: string password: type: string phone: type: string userStatus: type: integer format: int32 description: User Status xml: name: User Tag: type: object properties: id: type: integer format: int64 name: type: string xml: name: Tag Pet: type: object required: - name - photoUrls properties: id: type: integer format: int64 category: $ref: '#/definitions/Category' name: type: string example: doggie photoUrls: type: array xml: name: photoUrl wrapped: true items: type: string tags: type: array xml: name: tag wrapped: true items: $ref: '#/definitions/Tag' status: type: string description: pet status in the store enum: - available - pending - sold xml: name: Pet ApiResponse: type: object properties: code: type: integer format: int32 type: type: string message: type: string externalDocs: description: Find out more about Swagger url: http://swagger.io # Added by API Auto Mocking Plugin host: virtserver.swaggerhub.com basePath: /yuulinux.tokyo/TEST/1.0.0 schemes: - https - http
なんとなく言いたいことはわかるな。
Swagger Editorにアクセスしてみる
うーんいまいちお猿な私には進捗がとまってしまったな。
次の文献へ
これ良いね。やってみよう。
swagger: '2.0' info: version: "1.0.0" title: タイトル paths: /posts/{id}: get: description: | description 説明文 parameters: - name: id in: path description: Id of array required: true type: number format: double responses: 200: description: Successful responses schema: title: ArrayOfPosts type: array items: title: Posts type: object properties: name: type: string title: type: string published: type: boolean content: type: string
Swagger Editorの左側にコードを貼り付けたら、右側が非同期で表示されるな。
ダウンロードされたディレクトリの中で実行
$ pwd /Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server
nodejs-server-server $ npm install
実行
$ node index.js
$ node index.js events.js:186 throw er; // Unhandled 'error' event ^ Error: listen EADDRINUSE: address already in use :::8080 at Server.setupListenHandle [as _listen2] (net.js:1298:14) at listenInCluster (net.js:1346:12) at Server.listen (net.js:1434:7) at /Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/index.js:39:26 at /Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/index.js:85:7 at cbWrapper (/Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/lib/specs.js:1035:5) at validateSwagger2_0 (/Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/lib/specs.js:1030:3) at validateSemantically (/Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/lib/specs.js:1040:5) at /Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/lib/specs.js:1233:7 at /Users/kanehiro/Documents/develop/Swagger-Study/nodejs-server-server/node_modules/swagger-tools/lib/specs.js:1073:29 Emitted 'error' event on Server instance at: at emitErrorNT (net.js:1325:8) at processTicksAndRejections (internal/process/task_queues.js:80:21) { code: 'EADDRINUSE', errno: 'EADDRINUSE', syscall: 'listen', address: '::', port: 8080 }
エラーでてる。。
すでにそのポートは使われてるぜってことなので。
動かしていたDockerを止める。
$ docker stop $(docker ps -q)
改めて実行
$ node index.js Your server is listening on port 8080 (http://localhost:8080) Swagger-ui is available on http://localhost:8080/docs
http://localhost:8080/docs
にアクセス
使い方が見えてきました。
最初のサンプルも同じようにやってみた
見えてきたね。
@see
- Swaggerとは
- Qiita Swaggerの概要をまとめてみた
- SwaggerでRESTful APIの管理を楽にする
- Swaggerの記法まとめ
- Swaggerを利用した新規サービス開発
- 【初心者向け】SwaggerとAWS SAMを使ってWebAPIを簡単に作ってみた