OpenAPI Specification 3.0.3を使ったいい感じのCRUD APIのサンプルを作る
はじめに
今までOpenAPI 2.0(Swagger2.0)を使って書くことが多かったのですが、いい加減新しいバージョンも試したく。記法を学びつつ新規作成時の手本にできるようなサンプルを作ろうと思いました。
作ったもの
Swagger Editorとかにコピペして見てみてください。openapi: "3.0.3" info: title: "My API Spec" description: |- My Sampe API Specification.</br> It works for me. termsOfService: https://www.blog.danishi.net/about/ version: "1.0.0" contact: name: API Support email: support@example.com url: http://example.com/support license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html servers: - url: https://api.example.com/api/v1 description: production - url: https://{environment}.api.example.com/api/v1 variables: environment: default: dev enum: - dev - staging description: develop - url: "{protocol}://{host}:{port}/api/v1" description: local variables: protocol: enum: - http - https default: http host: default: localhost port: enum: - '443' - '8443' default: '443' tags: - name: User description: Access to user model. paths: /users: post: tags: - "User" security: - bearer: [] summary: CreateUser description: |- Create a user. requestBody: $ref: '#/components/requestBodies/CreateUserRequestBody' responses: '200': $ref: '#/components/responses/CreateUserResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' get: tags: - "User" security: - bearer: [] summary: GetUsers description: |- Search for a users and get a list. parameters: - in: query name: email description: User mail address. schema: type: string format: email example: John@example.com - in: query name: name description: User name. schema: type: string example: John Smith - $ref: '#/components/parameters/LimitParameter' - $ref: '#/components/parameters/OffsetParameter' responses: '200': $ref: '#/components/responses/GetUsersResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' /users/me: get: tags: - "User" summary: GetUserByMine security: - bearer: [] description: |- Get user by logged in session. responses: '200': $ref: '#/components/responses/GetUserResponse' '400': $ref: '#/components/responses/BadRequestResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' /users/{id}: parameters: - $ref: '#/components/parameters/UserIdParameter' get: tags: - "User" summary: GetUserById security: - bearer: [] description: |- Get user by id. responses: '200': $ref: '#/components/responses/GetUserResponse' '400': $ref: '#/components/responses/BadRequestResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' put: tags: - "User" summary: UpdateUserById security: - bearer: [] description: |- Update user by id. parameters: - $ref: '#/components/parameters/VersionParameter' requestBody: $ref: '#/components/requestBodies/UpdateUserRequestBody' responses: '200': $ref: '#/components/responses/CreateUserResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictErrorResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' delete: tags: - "User" summary: DeleteUserById security: - bearer: [] description: |- Delete user by id. parameters: - $ref: '#/components/parameters/VersionParameter' responses: '200': $ref: '#/components/responses/CreateUserResponse' '401': $ref: '#/components/responses/UnauthorizedResponse' '403': $ref: '#/components/responses/ForbiddenResponse' '404': $ref: '#/components/responses/NotFoundResponse' '409': $ref: '#/components/responses/ConflictErrorResponse' '500': $ref: '#/components/responses/InternalServerErrorResponse' components: #------------------------------- # Reusable schemas #------------------------------- schemas: UserModel: description: User model required: - id - name - email type: object properties: id: title: User id type: string example: 2c6e239a-f02b-d158-2833-c7f883bb5530 readOnly: true name: title: User name type: string example: Leanne Graham email: title: Mail address type: string example: Sincere@april.biz address: title: User address type: object properties: street: title: User address of street type: string example: Kulas Light suite: title: User address of suite type: string example: Apt. 556 city: title: User address of city type: string example: Gwenborough zipcode: title: User address of zipcode type: string example: 92998-3874 hobbies: title: User hobbies type: array items: type: string enum: - Reading books - Blogging - Singing - Listening to music - Learning new languages - Shopping - Dancing - Drawing - Traveling - Cooking example: - Shopping - Cooking TimeStampsModel: description: TimeStamps Model required: - createAt - version type: object properties: createAt: title: Created datetime. type: string format: date-time example: 2017-07-21T17:32:28Z updateAt: title: Updated datetime. type: string format: date-time example: 2020-09-12T01:41:23Z version: title: Optimistic lock key. type: integer minimum: 1 default: 1 PaginationModel: description: Pagination model required: - page - total type: object properties: page: title: Page number. type: integer minimum: 1 example: 1 total: title: Total count. type: integer minimum: 0 example: 10 ErrorModel: description: Response Error Model. required: - code - message type: object properties: code: title: error code type: string example: 500 message: title: error message type: string example: Internal Server Error. #------------------------------- # Reusable operation parameters #------------------------------- parameters: UserIdParameter: name: id in: path description: User id. required: true schema: type: string format: uuid4 example: cfe43609-4c38-d52d-44ff-66bf2bc2d5c2 VersionParameter: name: version in: query description: Optimistic lock key. required: true schema: type: integer default: 1 example: 1 LimitParameter: name: limit in: query description: Limit one page. schema: type: integer default: 20 example: 20 OffsetParameter: name: offset in: query description: Offset page. schema: type: integer default: 0 example: 100 #------------------------------- # Reusable request body #------------------------------- requestBodies: CreateUserRequestBody: description: user data required: true content: application/json: schema: $ref: '#/components/schemas/UserModel' UpdateUserRequestBody: description: user data required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/UserModel' - properties: email: readOnly: true #------------------------------- # Reusable responses #------------------------------- responses: GetUsersResponse: description: User lists content: application/json: schema: allOf: - $ref: '#/components/schemas/PaginationModel' - required: - users - type: object - properties: users: type: array items: $ref: '#/components/schemas/UserModel' example: - id: 2c6e239a-f02b-d158-2833-c7f883bb5530 name: Leanne Graham email: Sincere@april.biz address: street: Kulas Light suite: Apt. 556 city: Gwenborough zipcode: 92998-3874 hobbies: - Shopping - Cooking createAt: 2020-09-12T01:41:23.000Z update_at: 2020-09-12T01:41:23.000Z version: 2 - id: 65fe854a-ca6d-2caa-1b12-e0b8d8b0c563 name: Clementine Bauch email: Nathan@yesenia.net createAt: 2020-09-12T01:41:23.000Z version: 1 - id: 36c1ee69-9e35-0740-990d-2b97508bd9fb name: Ervin Howell email: yamada@example.com hobbies: - Singing - Dancing - Drawing createAt: 2020-09-12T01:41:23.000Z update_at: 2020-09-12T01:41:23.000Z version: 3 GetUserResponse: description: Got user. content: application/json: schema: allOf: - $ref: '#/components/schemas/UserModel' - $ref: '#/components/schemas/TimeStampsModel' CreateUserResponse: description: Created user. content: application/json: schema: allOf: - $ref: '#/components/schemas/UserModel' - $ref: '#/components/schemas/TimeStampsModel' BadRequestResponse: description: | Bad Request. content: application/json: schema: allOf: - $ref: '#/components/schemas/ErrorModel' properties: code: example: 400 message: example: Bad Request. UnauthorizedResponse: description: | Unauthorized. content: application/json: schema: allOf: - $ref: '#/components/schemas/ErrorModel' properties: code: example: 401 message: example: Unauthorized. ForbiddenResponse: description: | Forbidden. content: application/json: schema: allOf: - $ref: '#/components/schemas/ErrorModel' properties: code: example: 403 message: example: Forbidden. NotFoundResponse: description: | Not Found. content: application/json: schema: allOf: - $ref: '#/components/schemas/ErrorModel' properties: code: example: 404 message: example: Not Found. ConflictErrorResponse: description: | Conflict. content: application/json: schema: allOf: - $ref: '#/components/schemas/ErrorModel' properties: code: example: 409 message: example: Conflict. InternalServerErrorResponse: description: |- Internal Server Error. content: application/json: schema: $ref: '#/components/schemas/ErrorModel' #------------------------------- # Reusable security #------------------------------- securitySchemes: bearer: type: http scheme: bearer description: JWT Token Authentication apikey: type: apiKey name: x-api-key in: header description: API Key Authentication basicAuth: type: http scheme: basic description: Basic Authenticationドキュメントをよく読みながら書いてみると、色々と便利な記述がありOpenAPI 2.0の頃より再利用性が高まっています。
Readの時は欲しいけどCreateの時は指定しない(できない)情報や、Updateの時は更新したくないので指定しない、みたいのは
readOnly
や allOf
をうまく使えば表現できるのも発見でした。
ディスカッション
コメント一覧
まだ、コメントがありません