😺

Android Studioで始めるOpen API入門

に公開

概要

Open APIとは、API(Application Programming Interface)の仕様を標準化された形式で記述するための仕様のこと。

  • 特徴
    • APIのエンドポイント、リクエスト・レスポンスの形式、認証方法などを統一的に記述
    • JSON形式またはYAML形式で定義される
    • RESTful APIの設計と文書化
  • できること
    • API仕様書の自動生成
    • クライアントSDKの自動生成
    • テストケースの自動生成
    • APIドキュメントの自動作成

得ること

  • Android StudioでOpen API定義ができるようになる
  • Swagger UIで記述した内容がドキュメントとして閲覧できる

前提:RESTful APIとは

RESTとはREpresentational State Tranfer, Webサービス設計思想の一つ
4つの原則

  • アドレス可能性
    • 全ての情報が一意なURIで表現されること
  • 統一インターフェース
    • 情報の操作(取得、作成、更新、削除)は全てHTTPメソッドを利用
      • HTTPメソッド(GET/POST/PUT/DELETE)
      • やりとりするデータはJSON形式
  • ステートレス性
    • サーバーがクライアントの情報を持たないように設計
      • 全てのリクエストが完全に独立していてリクエスト間で影響し合わない
  • 接続性
    • 情報に別の情報や状態のリンクを含めることで別の情報に接続することができる

導入

  1. Android Studioのインストール
  2. Android Studioを開きOpenAPI(Swagger) Editorというpluginを入れる
    →そうすると正しいYamlファイルを開いている時に右上にShow OpenAPI Previewと表示されるようになり、そこからドキュメントを参照できるようになる

Swagger Specificationの書き方

yamlの書き方

# 文字列
name: "Taro"

# 数値
age: 30

# boolean
is_adult: true

# null
middle_name: null
nullable: true

# 配列
fruits:
 - Apple
 - Banana

# 階層構造
person:
  name: "Taro"
  address:
    street: 123
    city: "tokyo"
    state: "1234-abcd"

# 複数行
description: |
  This 
  is
  a
  pen

# リスト内のハッシュ
users:
  - name: "Taro"
    age: 30
  - name: Hanako
    age: 25

ルートオブジェクト

定義を書く上で7つのルートオブジェクトがある

  • openapi
    • OpenAPIのバージョン
      • 必須
  • info
    • API仕様書のメタデータ
      • 必須
  • servers
    • APIがどんな環境で提供されるか定義
  • tags
    • 分類するタグ
  • paths
    • パス
  • security
    • セキュリティ要件を定義
  • components
    • 再利用可能にするための定義

info

licenseに関してはspdxのlicense listから取得

openapi: "3.0.3"
info:
  title: "Blog Site API"
  description: |
    # Features
    - Get Blogs
    - Post Blogs
  version: 1.0.0
  termsOfService: "https://google.com"
  contact:
    name: "Customer Support"
    url: "https://google.com"
    email: "test@gmail.com"
  license:
    name: "MIT License"
    url: "https://spdx.org/licenses/MIT.html"

servers

servers:
  - url: "http://{enviroment}.test.com/v1"
    description: "環境毎のAPIサーバー"
    variables:
      enviroment:
        enum:
          - "api"
          - "dev-api"
        default: "api"
        description: "環境を指定します(api: 本番, dev-api: 開発)"

tags

tags:
  - name: blog
    description: "ブログ記事に関する操作"
  - name: user
    description: "ユーザー情報に関する操作"

components

共通schemaを使いまわせるようにする

components:
  schemas:
    BlogInfo:
      type: object
      properties:
        id:
          type: integer
          description: "ブログ記事のID"
        title:
          type: string
          description: "ブログ記事のタイトル"
        content:
          type: string
          description: "ブログ記事の本文"
        author:
          type: string
          description: "著者"
        createdAt:
          type: string
          format: data-time
          description: "作成日"

paths

パスを定義するステータスコード毎に記述できる
ファイルを分けて$refの内容をパス名にしても良い

paths:
  /blog/{blogId}:
    get:
      summary: "ブログの取得"
      description: "指定したブログを取得する"
      tags: 
        - blog
      deprecated: false
      parameters:
        - name: blogId
          in: path
          description: "ブログID"
          required: true
          schema:
            type: integer
          example: 1234
        - name: x-Request-Id
          in: header
          description: "リクエストID"
          required: false
          schema:
            type: string
            example: "1234-abcd"
        - name: sessionId
          in: cookie
          description: "セッションID"
          required: false
          schema:
            type: string
            example: "1234abcd"
      responses:
        "200":
          description: "成功時のレスポンス"
          headers:
            x-Total-Count:
              description: "ブログ記事の総数"
              schema:
                type: integer
            x-RateLimit-Limit:
              description: "レートリミットの上限"
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BlogInfo'
        "400":
          description: "無効なリクエストID"
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: "エラーメッセージ"
        "500":
         description: "サーバーエラー"
         content:
          application/json:
            schema:
              type: object
              properties:
                error:
                  type: string
                  description: "エラーメッセージ"

  /blogs:
    post:
      summary: "ブログ記事を登録する"
      description: "新しいブログを登録します"
      tags:
        - "blog"
      requestBody:
        description: "ブログ記事の情報"
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BlogInfo'

security

componentsにsecuritySchemesを足す
以下はAPIKey認証
他にもBasic認証、JWT認証、OAuth2.0、OpenID Connectなどで記述が異なる

components:
  securitySchemes:
    apiKey_auth:
      description: "API key autorization"
      type: apiKey
      in: header
      name: X-Api-key
  schemas:
    BlogInfo:
      type: object
      properties:
        id:
          type: integer
          description: "ブログ記事のID"
        title:
          type: string
          description: "ブログ記事のタイトル"
        content:
          type: string
          description: "ブログ記事の本文"
        author:
          type: string
          description: "著者"
        createdAt:
          type: string
          format: data-time
          description: "作成日"

pathに追加する
security自体をルートオブジェクトにすれば全てに適用できる
その場合はいらないpathでのsecurity:[]にしてあげる

paths:
  /blog/{blogId}:
    get:
      summary: "ブログの取得"
      description: "指定したブログを取得する"
      tags: 
        - blog
      deprecated: false
      parameters:
        - name: blogId
          in: path
          description: "ブログID"
          required: true
          schema:
            type: integer
          example: 1234
        - name: x-Request-Id
          in: header
          description: "リクエストID"
          required: false
          schema:
            type: string
            example: "1234-abcd"
        - name: sessionId
          in: cookie
          description: "セッションID"
          required: false
          schema:
            type: string
            example: "1234abcd"
      responses:
        "200":
          description: "成功時のレスポンス"
          headers:
            x-Total-Count:
              description: "ブログ記事の総数"
              schema:
                type: integer
            x-RateLimit-Limit:
              description: "レートリミットの上限"
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BlogInfo'
        "400":
          description: "無効なリクエストID"
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: "エラーメッセージ"
        "500":
         description: "サーバーエラー"
         content:
          application/json:
            schema:
              type: object
              properties:
                error:
                  type: string
                  description: "エラーメッセージ"
      security: []

  /blogs:
    post:
      summary: "ブログ記事を登録する"
      description: "新しいブログを登録します"
      tags:
        - "blog"
      requestBody:
        description: "ブログ記事の情報"
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BlogInfo'
      security:
        - apiKey_auth: []
  • apiKey_auth: []これはスコープを表している
    apiKey認証の場合は全権限がそのまま付与されるのでないが、他の認証の場合読み込み。書き込み権限、管理者かどうかなどここに指定する

Discussion