表参道.rb #47 〜API〜で共有した知見 #omotesandorb

LTする方が少なかったので、自分がやってる知見的な事を紹介するためのブログ。

API ドキュメント

OpenAPIで書いています。

初めて聞いた人向けの説明

Swagger Editorで書くと、 Swagger UIみたいな見た目のドキュメントが作れる。

ファイルの置き場所

#{Rails.root}/doc/api/openapi.yml に1ファイルで置いてあります。

更新するとき

#{Rails.root}/doc/api/docker-compose.yml を作っておきます。

version: "3.7"
services:
  editor:
    image: swaggerapi/swagger-editor
    ports:
      - "8080:8080"
  ui:
    image: swaggerapi/swagger-ui
    ports:
      - "8081:8080"
    volumes:
      - ./openapi.yaml:/usr/share/nginx/html/openapi.yaml
    environment:
      API_URL: openapi.yaml

つまり Swagger Editor を起動し、 http://localhost:8080 上で編集してエクスポートする感じです。

$ cd doc/api
$ docker-compose up -d
$ open http://localhost:8080

ドキュメントの共有

CIでS3にアップロードして、S3 bucketのポリシーでIP制限をかけてます。

以下のようなスクリプトをCIから実行するようにしてある。

#!/bin/sh

set -eu

sudo apt-get update
sudo apt-get install python-pip
sudo pip install awscli

S3_BUCKET="proj-doc"
S3_BUCKET_PATH="${S3_BUCKET}/proj-api"
S3_BASE_URL="https://s3-ap-northeast-1.amazonaws.com/${S3_BUCKET_PATH}"

if [ "$CIRCLE_BRANCH" = "master" ]; then
  aws s3 sync --delete doc s3://${S3_BUCKET_PATH}/doc
else
  aws s3 sync --delete doc s3://${S3_BUCKET_PATH}/tree/${CIRCLE_BRANCH}/doc
  echo ${S3_BASE_URL}/tree/${CIRCLE_BRANCH}/doc/rdoc/index.html
  echo ${S3_BASE_URL}/tree/${CIRCLE_BRANCH}/doc/api/html/index.html
fi

ドキュメントをどうやってメンテするか?

committee-railscommittee を使って、全てのAPIをテストで検証しています。

RSpec.configure do |config|
  # committee-rails
  config.add_setting :committee_options
  config.committee_options = {
    schema_path: Rails.root.join('doc', 'api', 'openapi.yaml').to_s,
    prefix: '/api'
  }
  config.after(type: :request) do |ex|
    if ex.metadata[:api_validation].nil? && ex.location.include?('api') && !request.nil?
      extend Committee::Rails::Test::Methods
      assert_schema_conform
    end
  end
end

APIのキャッシュ

APIサーバの前段にCloudFrontを置いておき、ユーザーが更新しないリソースは全てキャッシュするように設定してます。

  1. RailsのCache-Controlにprivateが入っているので min_ttl = 0 だと miss hit
  2. headers = ["*"] だと miss hit
  3. cookies の forward = "all" だと miss hit

つまり以下の設定ならキャッシュされる。

default_cache_behavior {
  allowed_methods  = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
  cached_methods   = ["GET", "HEAD"]
  target_origin_id = "${local.api_alb_origin_id}"

  forwarded_values {
    headers      = ["Host", "Authorization"]
    query_string = true

    cookies {
      forward = "none"
    }
  }

  min_ttl                = 3600
  default_ttl            = 3600
  max_ttl                = 86400
  viewer_protocol_policy = "redirect-to-https"
}

URL設計について

CloudFront はパスベースでTTLを変更できるので、キャッシュ時間でURLを変えると楽。

/favorites
/settings/profile
/settings/security

例えば、 /settings/* だけTTLを0にしたりできる。