[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
SlideShare a Scribd company logo
© Recochoku Co.,Ltd. Proprietary and Confidential
2017/02/07
Swaggerを利用した
新規サービス開発
株式会社レコチョク
事業システム推進部 ミュージックアーキテクトグループ
松木 佑徒
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
自己紹介
2
職業:フルスタックエンジニア(自称)
言語:C# (2008~2010) -> Java (2011~2015) -> Python (2016~)
趣味:ドラム / ジャグリング
Yuto Matsuki @yustam_jp id:yustam
2008: 某SIerにてシステムエンジニアとして色々な現場で仕事をする
2014: 株式会社レコチョクに転職
2014-2015: レコチョクの楽曲DB周辺のバッチなどをAWS環境上に再構築
2016-: 新サービスWIZYの開発リーダーとしてWebの開発に携わる
最近は研究開発的な事もしています。
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
レコチョクについて
3
https://eggs.mu http://playpass.jp
2015/02サービス開始 2016/03サービス開始
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
WIZYについて
4
2016/08サービス開始
https://wizy.jp
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
WIZYのシステム構成
5
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
WIZYを支える技術
6
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swagger
7
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯①
8
• re:Invent 2015 Bootcampで初めてSwaggerに触れる
• Swagger Api Gateway Importerを使用したハンズオン
• 用意されたSpecを利用してツールでAPI Gatewayにデ
プロイするというもの
• サーバレスという概念が出て来て間もない頃で非常に
画期的な印象
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯②
9
• 2015年末新規サービス開発のプロジェクトが始まる
• はじめてフロントのシステムを担当することに
• 最初のプロトタイプ開発は1人で
• 仕様書はExcelなどで書きたくない
• 書くならコードの自動生成/再利用性のあるもの
• 個人的にRAMLを使ったことがあったが
• CodeGeneratorがPythonに対応している
• Open API Initiativeが立ち上がりSwaggerを推し始めた
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯 ③使ってみる
10
• 簡単なSwaggerSpecをYAMLで作成
/projects/{project_id}:
get:
summary: プロジェクト取得
tags:
- Project
parameters:
- name: project_id
in: path
description: プロジェクトID
required: true
type: integer
responses:
200:
description: プロジェクト
schema:
$ref: '#/definitions/project'
project:
type: object
properties:
id:
type: integer
description: プロジェクトID
user_id:
type: integer
description: ユーザID
...
paths: definitions:
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯 ③使ってみる
11
• CodeGeneratorでPythonクライアントを生成
• definitionで定義したオブジェクトをそのままJSON化
• レスポンスはdefinitionsのオブジェクトで受け取れる
import swagger_client as sw
project_api = sw.ProjectApi(api_client=api)
project = project_api.projects_project_id_get(project_id)
print(type(project))
print(type(project.end_time))
<class 'swagger_client.models.project.Project'>
<class 'datetime.datetime'>
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯 ③使ってみる
12
• JSON Web Tokenを利用した認証
ApiKey:
type: apiKey
name: Authorization
in: header
securityDefinitions:
/authenticate:
post:
summary: 認証API
tags:
- Auth
parameters:
- name: authenticate
in: body
required: true
schema:
$ref: '#/definitions/authenticate'
responses:
200:
description: トークン
schema:
$ref: '#/definitions/token'
paths:
authenticate:
type: object
properties:
key:
type: string
description: 認証キー
secret:
type: string
format: string
description: 認証シークレット
token:
type: object
properties:
access_token:
type: string
description: 認証トークン
definitions:
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを採用した経緯 ③使ってみる
13
• JSON Web Tokenを使用した認証を採用
import swagger_client as sw
auth_api = sw.AuthApi(sw.ApiClient(API_HOST))
auth = sw.Authenticate(key='user',secret='hogehoge')
resp = auth_api.authenticate_post(authenticate=auth)
api = sw.ApiClient(host=API_HOST, header_name='Authorization',
header_value='JWT %s' % resp.access_token)
project_api = sw.ProjectApi(api_client=api)
project = project_api.projects_project_id_get(project_id)
curl-X POST -d '{"key":"user","secret":"hogehoge"}' http://${API_HOST}/authenticate
curl -X GET -H "Authorization: JWT ${JWT_TOKEN}" http://${API_HOST}/projects/${PROJECT_ID}
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
WIZYにおけるSwagger
14
• Swaggerの仕様バージョン2.0
• 開発言語はPython
• API側のフレームワークはFlask
• APIの認証はFlask-JWTを使用したJWTトークン認証
• 2017年2月時点でAPI数は 63 (pathベースで38)
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swagger Code Generator
15
YAMLで仕様を管理。YAMLから生成
https://github.com/swagger-api/swagger-codegen
html
python
/projects/{project_id}:
get:
summary: プロジェクト取得
tags:
- Project
parameters:
- name: project_id
in: path
description: プロジェクトID
required: true
type: integer
responses:
200:
description: プロジェクト
schema:
$ref: '#/definitions/project'
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
WIZYの開発手法
16
1. 機能要件に従ってテーブル定義等の仕様を決める
2. フロントの要件に従ってAPI仕様をSwagger Specで書く
3. Swagger Specに従ってAPIを実装
4. Swagger Code Generatorでクライアントを生成
5. 生成したクライアントを使用してフロントのアプリを実装
web api
client
cache database
spec
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(開発)
17
APIの仕様レビューがYAMLファイル上で行える
• diffで比較できるのでレビュー漏れが無い
• JSONよりYAMLの方が書き方に個人差が出ないのでオススメ
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(開発)
18
書式が決まっているのでAPIに必要な情報について曖昧さがない
実装前にある程度挙動を確認できるので手戻りが防げる
APIの開発者とクライアント側の開発者が並行で作業できる
他との矛盾/命名規則の違反などを発見しやすい
他のpaths/definitionsを再利用できる
/projects/{project_id}:
get:
summary: プロジェクト取得
tags:
- Project
parameters:
- name: project_id
in: path
description: プロジェクトID
required: true
type: integer
responses:
200:
description: プロジェクト
schema:
$ref: '#/definitions/project'
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(開発)
19
そのままコードになるのでレビューした内容とコードに差がない
ドキュメントにもなるのでコードとドキュメントの乖離がない
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(運用)
20
Web/APIを分離してバージョン管理しやすくなる
SwaggerSpecに変更がある場合のみAPI仕様に変更がある
swaggerのtags
webのtags apiのtags× ×
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(運用)
21
Blue-Green Deploymentにより無停止でバージョンアップ可能に
本番環境ELB
API-ELB
API v1.0
API v1.1ステージ環境ELB
Web v2.0
Web v2.1
しかしAPIに互換性がない場合は並行稼動できない…
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerを使って良かったこと(運用)
22
APIのインタフェース仕様の変更が一目でわかるので
前のバージョンと互換性があるかの判断が簡単になる
→ pathの追加だけであれば問題ない。など
差分がない場合は仕様に変更がないことが保証されるが
ソート順などは表現されないのでインタフェース以外の
修正は個別で判断する必要がある
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
「operationId」の定義は必要か
23
https://apihandyman.io/writing-openapi-swagger-specification-tutorial-part-7-documentation/
paths:
/persons:
parameters:
- $ref: '#/parameters/userAgent'
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
operationId: searchUsers
[main] WARN io.swagger.codegen.DefaultCodegen - Empty operationId found
for path: post /projects/{project_id}/items. Renamed to auto-generated
operationId: projectsProject_idItemsPost
「operationId」はAPI単位にユニークな名前をつけるもの
書かないとCodeGeneratorに怒られます。。
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07
Swaggerの使い方について今後の課題①
24
# operationId未指定の場合
projects = project_api.projects_get(limit=10)
# operationIdを指定した場合
projects = project_api.search_projects(limit=10)
ルールを作るとしたら
• 「GET /XXXs」=>「search_XXXs」
• 「GET /XXXs/{YYY}」 => 「get_XXX_by_YYY」
• 変えたい場合もある。POST/PUT場合はどうする。。?
APIのpathとは別でルールを考える必要がありそう
Pythonクライアントの場合は自動でメソッド名が決まる
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 25
• OpenAPI 3.0 への移行
• 全体の99%を占めるpaths/definitionsに大きな変更なし?
• definitionsはcomponentsの配下に移動
• pathsはそのままに見えます…
https://www.openapis.org/news/blogs/2016/10/tdc-structural-improvements-explaining-30-spec-part-2
今後の課題(3.0対応)
© Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 26
ご静聴ありがとうございました!

More Related Content

Swaggerを利用した新規サービス開発

  • 1. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを利用した 新規サービス開発 株式会社レコチョク 事業システム推進部 ミュージックアーキテクトグループ 松木 佑徒
  • 2. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 自己紹介 2 職業:フルスタックエンジニア(自称) 言語:C# (2008~2010) -> Java (2011~2015) -> Python (2016~) 趣味:ドラム / ジャグリング Yuto Matsuki @yustam_jp id:yustam 2008: 某SIerにてシステムエンジニアとして色々な現場で仕事をする 2014: 株式会社レコチョクに転職 2014-2015: レコチョクの楽曲DB周辺のバッチなどをAWS環境上に再構築 2016-: 新サービスWIZYの開発リーダーとしてWebの開発に携わる 最近は研究開発的な事もしています。
  • 3. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 レコチョクについて 3 https://eggs.mu http://playpass.jp 2015/02サービス開始 2016/03サービス開始
  • 4. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 WIZYについて 4 2016/08サービス開始 https://wizy.jp
  • 5. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 WIZYのシステム構成 5
  • 6. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 WIZYを支える技術 6
  • 7. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swagger 7
  • 8. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯① 8 • re:Invent 2015 Bootcampで初めてSwaggerに触れる • Swagger Api Gateway Importerを使用したハンズオン • 用意されたSpecを利用してツールでAPI Gatewayにデ プロイするというもの • サーバレスという概念が出て来て間もない頃で非常に 画期的な印象
  • 9. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯② 9 • 2015年末新規サービス開発のプロジェクトが始まる • はじめてフロントのシステムを担当することに • 最初のプロトタイプ開発は1人で • 仕様書はExcelなどで書きたくない • 書くならコードの自動生成/再利用性のあるもの • 個人的にRAMLを使ったことがあったが • CodeGeneratorがPythonに対応している • Open API Initiativeが立ち上がりSwaggerを推し始めた
  • 10. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯 ③使ってみる 10 • 簡単なSwaggerSpecをYAMLで作成 /projects/{project_id}: get: summary: プロジェクト取得 tags: - Project parameters: - name: project_id in: path description: プロジェクトID required: true type: integer responses: 200: description: プロジェクト schema: $ref: '#/definitions/project' project: type: object properties: id: type: integer description: プロジェクトID user_id: type: integer description: ユーザID ... paths: definitions:
  • 11. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯 ③使ってみる 11 • CodeGeneratorでPythonクライアントを生成 • definitionで定義したオブジェクトをそのままJSON化 • レスポンスはdefinitionsのオブジェクトで受け取れる import swagger_client as sw project_api = sw.ProjectApi(api_client=api) project = project_api.projects_project_id_get(project_id) print(type(project)) print(type(project.end_time)) <class 'swagger_client.models.project.Project'> <class 'datetime.datetime'>
  • 12. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯 ③使ってみる 12 • JSON Web Tokenを利用した認証 ApiKey: type: apiKey name: Authorization in: header securityDefinitions: /authenticate: post: summary: 認証API tags: - Auth parameters: - name: authenticate in: body required: true schema: $ref: '#/definitions/authenticate' responses: 200: description: トークン schema: $ref: '#/definitions/token' paths: authenticate: type: object properties: key: type: string description: 認証キー secret: type: string format: string description: 認証シークレット token: type: object properties: access_token: type: string description: 認証トークン definitions:
  • 13. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを採用した経緯 ③使ってみる 13 • JSON Web Tokenを使用した認証を採用 import swagger_client as sw auth_api = sw.AuthApi(sw.ApiClient(API_HOST)) auth = sw.Authenticate(key='user',secret='hogehoge') resp = auth_api.authenticate_post(authenticate=auth) api = sw.ApiClient(host=API_HOST, header_name='Authorization', header_value='JWT %s' % resp.access_token) project_api = sw.ProjectApi(api_client=api) project = project_api.projects_project_id_get(project_id) curl-X POST -d '{"key":"user","secret":"hogehoge"}' http://${API_HOST}/authenticate curl -X GET -H "Authorization: JWT ${JWT_TOKEN}" http://${API_HOST}/projects/${PROJECT_ID}
  • 14. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 WIZYにおけるSwagger 14 • Swaggerの仕様バージョン2.0 • 開発言語はPython • API側のフレームワークはFlask • APIの認証はFlask-JWTを使用したJWTトークン認証 • 2017年2月時点でAPI数は 63 (pathベースで38)
  • 15. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swagger Code Generator 15 YAMLで仕様を管理。YAMLから生成 https://github.com/swagger-api/swagger-codegen html python /projects/{project_id}: get: summary: プロジェクト取得 tags: - Project parameters: - name: project_id in: path description: プロジェクトID required: true type: integer responses: 200: description: プロジェクト schema: $ref: '#/definitions/project'
  • 16. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 WIZYの開発手法 16 1. 機能要件に従ってテーブル定義等の仕様を決める 2. フロントの要件に従ってAPI仕様をSwagger Specで書く 3. Swagger Specに従ってAPIを実装 4. Swagger Code Generatorでクライアントを生成 5. 生成したクライアントを使用してフロントのアプリを実装 web api client cache database spec
  • 17. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(開発) 17 APIの仕様レビューがYAMLファイル上で行える • diffで比較できるのでレビュー漏れが無い • JSONよりYAMLの方が書き方に個人差が出ないのでオススメ
  • 18. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(開発) 18 書式が決まっているのでAPIに必要な情報について曖昧さがない 実装前にある程度挙動を確認できるので手戻りが防げる APIの開発者とクライアント側の開発者が並行で作業できる 他との矛盾/命名規則の違反などを発見しやすい 他のpaths/definitionsを再利用できる /projects/{project_id}: get: summary: プロジェクト取得 tags: - Project parameters: - name: project_id in: path description: プロジェクトID required: true type: integer responses: 200: description: プロジェクト schema: $ref: '#/definitions/project'
  • 19. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(開発) 19 そのままコードになるのでレビューした内容とコードに差がない ドキュメントにもなるのでコードとドキュメントの乖離がない
  • 20. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(運用) 20 Web/APIを分離してバージョン管理しやすくなる SwaggerSpecに変更がある場合のみAPI仕様に変更がある swaggerのtags webのtags apiのtags× ×
  • 21. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(運用) 21 Blue-Green Deploymentにより無停止でバージョンアップ可能に 本番環境ELB API-ELB API v1.0 API v1.1ステージ環境ELB Web v2.0 Web v2.1 しかしAPIに互換性がない場合は並行稼動できない…
  • 22. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerを使って良かったこと(運用) 22 APIのインタフェース仕様の変更が一目でわかるので 前のバージョンと互換性があるかの判断が簡単になる → pathの追加だけであれば問題ない。など 差分がない場合は仕様に変更がないことが保証されるが ソート順などは表現されないのでインタフェース以外の 修正は個別で判断する必要がある
  • 23. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 「operationId」の定義は必要か 23 https://apihandyman.io/writing-openapi-swagger-specification-tutorial-part-7-documentation/ paths: /persons: parameters: - $ref: '#/parameters/userAgent' get: summary: Gets some persons description: Returns a list containing all persons. The list supports paging. operationId: searchUsers [main] WARN io.swagger.codegen.DefaultCodegen - Empty operationId found for path: post /projects/{project_id}/items. Renamed to auto-generated operationId: projectsProject_idItemsPost 「operationId」はAPI単位にユニークな名前をつけるもの 書かないとCodeGeneratorに怒られます。。
  • 24. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 Swaggerの使い方について今後の課題① 24 # operationId未指定の場合 projects = project_api.projects_get(limit=10) # operationIdを指定した場合 projects = project_api.search_projects(limit=10) ルールを作るとしたら • 「GET /XXXs」=>「search_XXXs」 • 「GET /XXXs/{YYY}」 => 「get_XXX_by_YYY」 • 変えたい場合もある。POST/PUT場合はどうする。。? APIのpathとは別でルールを考える必要がありそう Pythonクライアントの場合は自動でメソッド名が決まる
  • 25. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 25 • OpenAPI 3.0 への移行 • 全体の99%を占めるpaths/definitionsに大きな変更なし? • definitionsはcomponentsの配下に移動 • pathsはそのままに見えます… https://www.openapis.org/news/blogs/2016/10/tdc-structural-improvements-explaining-30-spec-part-2 今後の課題(3.0対応)
  • 26. © Recochoku Co.,Ltd. Proprietary and Confidential 2017/02/07 26 ご静聴ありがとうございました!