Web APIを実装しよう！！（Rails）

# はじめに

[PORT Advent Calendar 2020](https://qiita.com/advent-calendar/2020/port) の4日目の記事です！

はじめまして！　PORT新卒エンジニアの[しゅんいち(shxun6934)](https://mobile.twitter.com/shxun6934) です！

業務でのとあるタスクにて、Railsを使用して**WebAPI**を実装することになりました。
今までは、WebAPI（QiitaとかTwitterとかお世話になりました。）を使用する側でしたが、WebAPIを**作成する側**になったので、いろいろわからないところが多かったです。

簡単にですが、そのタスクに臨むにあたって**学んだこと、意識していたこと**を皆さんに共有しておきたいと思います。


# そもそも、APIって何？

API(Application Programming Interface) は、**アプリケーションとアプリケーション、人、組織をつなげてくれるもの**です。

APIと言っても種類はいくつかあります。
（例：Twitterから「いいね」の情報を取得するためのもの、iOSアプリでカメラの機能を使用するためのもの、画像の色を反転させるためのもの、などなど。。。）

一般的に言われている「API」は、WebAPIを指すことが多いです。

WebAPIは、**ネットワークを使用して他のアプリケーションと通信する** APIのことです。


# RESTful API

**RESTの原則**に従ったAPI。

ここで思うことは、「RESTって何???」

簡単に言うと、RESTは**複数のソフトウェアを連携させるための設計原則の考え方**のことです。
RESTの原則は以下の4つ。

URIを通して提供できる情報が表現できていること = **アドレス可能性**
インターフェースが統一されていること = **統一インターフェース**
やり取りする情報で全てを完結させること = **ステートレス性**
情報の内部に別の情報や状態へのリンクを含めることができること = **接続性**

これらに従って設計すれば、使いやすくAPIになります。

では、実際にWebAPIで意識することを見ていきます。


## URI

WebAPIなので、URIは必須になります。

ここでは、REST原則の**アドレス可能性**が鍵になります。
URIはユーザーが実際に入力するものなので、**わかりやすく、どんな機能を持つURIがひと目でわかる**ようにしたほうがベストです。

例として、犬の種別の一覧を取得するAPIを設計します。

```
GET https://example.com/api/get-dogs-type-all-list
```

これでは、**読みにくく、直感的ではありません**。（何の機能なのかはなんとなくわかる気がする。。。）

`dogs`と`type`が同列に並んでいるので、階層的にわかりづらいですし、`list`と`all`では意味がほぼ同じなので、重複してます。
また、WebAPIを使用するユーザーが想定なので、URIにわざわざ`get`という単語を入れなくてもいいです。（後述のHTTPメソッドより）

なので、**階層的にわかりやすく、シンプルに**したほうが使いやすそうですね。
以下のように修正します。

```
GET https://example.com/api/dogs/type/list
```

`dogs`の`type`の`list`を取得できると直感的にわかるようになったと思います。（多分）


## HTTPメソッド

REST原則の**統一インターフェース**に一番密な要素です。
標準化されたHTTPメソッドの個々の役割を理解して、それらを**どのAPI**でも適用するものです。

基本的なHTTPメソッドは、以下。

|HTTPメソッド|役割|
|:-:|:-:|
|GET|リソースを取得する、検索する|
|POST|リソースを作成する、追加する|
|PUT|リソースのデータを更新する|
|DELET|リソースを削除する|

もし、POSTで「リソースのデータを更新する」役割をも持たせたとして、
`記事を投稿するAPI`と`記事の内容を更新するAPI`があったとします。

2つのAPIを以下のように設計します。

```
POST /api/articles
POST /api/articles/:article_id
```

上記の設計だと、同じアプリケーションに「リソースを作成する」`POST`と「リソースのデータを更新する」`POST`が存在してしまいます。

これでは、`POST`に関して**同じ意味をなさなくなる**ので、インターフェースが統一されていないことになり、使いづらいAPIになってしまいます。

この例では、HTTPメソッドの役割に沿って、`記事の内容を更新するAPI`は**PUT**で行うようにしたほうがいいと思います。


## HTTPレスポンス

APIを使用して返ってくるものにもしっかりと制約をつけ、インターフェースを統一しましょう。
(HEADは割愛させていただきます。すいません。)


### ステータスコード

`200`とか、`404`とか、`500`とかのあれです。
ステータスコード単体でも意味を成しているので、HTTPメソッド同様、理解する必要があります。

よく目にするステータスコードは以下。

|ステータスコード|意味|
|:-:|:-:|
|200|リクエストが成功した|
|201|リクエストが成功し、リソースが新規作成された|
|400|リクエストパラメータに不足・不備があった|
|401|アクセストークンが無効、認証されていない|
|404|リクエストされたリソースが存在しなかった|
|500|何らかのエラーがサーバー側で発生している|

WebAPIの設計において、基本的には**想像しうる状態を全て網羅**しなくてはいけません。
網羅した上で、必要なステータスコードはなんなのかを考えていきましょう。


### ボディ

ユーザーが実際に扱うデータのフォーマットや構造を考えて置く必要があります。

最近のWebAPIは、**JSON**で返すことが多いです。`JSON`のフォーマットにしたがっていけば問題なさそうですね。

レスポンスのボディは**2種類**あると思います。
`リクエストが成功した場合`と`リクエストが失敗した場合`です。


#### リクエストが成功した場合

ユーザーが欲しい情報を`JSON`のフォーマットに沿って構造化していきます。

今回、個人的に意識したことは、**階層構造**です。

例として、ユーザー一覧を取得するAPIの`JSON`を考えます。
ユーザーを取得する際に、住所の情報も欲しいとします。

もし、住所の情報に、`prefecture`と`city`が欲しいとき、
以下のように階層ごとにグループ化することで、わかりやすく、データもまとまります。

```json:users.json
{
  {
    "id": 1
    "first_name": "AAAA",
    "middle_name": null,
    "last_name": "BBBB",
    "sex": "man",
    // 住所として一つのグループにする。
    "address": {
      "prefecture": "東京都",
      "city": "新宿区"
    },
    "favorite_tags": ["Ruby", "Rails", "WebAPI"]
    "url": "https://example.com/users/1"
  },
  {
    "id": 2
    "first_name": "CCCC",
    "middle_name": "1111",
    "last_name": "DDDD",
    "sex": "woman",
    // 同列だとわかりづらい
    "prefecture": "東京都"
    "city": "渋谷区"
    "favorite_tags": []
    "url": "https://example.com/users/2"
  },
}
```


#### リクエストが失敗した場合

ユーザーに**何のエラー**なのか、**どうして起きた**のかを正しく提供しなくてはいけません。

ユーザー一覧を取得するAPIのパラメーターに、ソートをかけるとします。（例：favorites_tagsで"Ruby"を持っているユーザーの一覧)

ここで間違えて、"Ruby"ではなく、数字を入れてしまったときのレスポンスは、
以下のようにする必要があると思います。

```
https://example.com/api/users?favorites_tags=65847
```

```json
{
  "message": "Invalid Request",
  "errors": [
    {
      "type": "bad_type",
      "message": "favorites_tags is String, is not Integer"
    }
  ]
}
```

エラーが複数存在する場合は、グループ化して、わかりやすくするのも一つの手ですね。


# Railsでは、、、

Webアプリを作成するために最適な`Rails`でも当然、WebAPIの実装はできます。


## RailsでのAPI実装

Railsには、**APIモード**なるものが存在していて、プロジェクトを新規作成する場合は、

```console
$ rails new my_api --api
```

でAPIモードになります。

また、既存のアプリをAPI専用にしたい場合は、`config/application.rb`にて

```ruby:config/application.rb
config.api_only = true
```

を設定するとできるみたいです。（超便利！！）


ただ、今回は既存のプロジェクトの一部でAPIが実装されているので、上二つのやり方はできませんでした。


RailsのAPI実装の特徴は、**APIモードではない、いつも通りのRailsとあまり変わらずに実装することができる**ことです。

`MVC`のView層が使用されないくらいで、あとは同じ感じでコードを書けるので、楽にかけます。
ただ、APIではいつもよりも制限がかかっているので、仕様については理解しないといけないところがあります。

今回の実装で詰まった、`ActionController::API`を簡単に説明します。


## ActionController::API

APIモードにする際に、`app/application.rb`を以下のように変更する必要があります。

```ruby:app/application.rb
# ActionController::Base → ActionController::APIに変更する。
class ApplicationController < ActionController::API
end
```

これでAPI専用になるのですが、、、
この`ActionController::API`は、**`ActionController::Base`をAPI専用にしたもの**であることを認識しないといけませんでした。

上記でいつも通りに開発できると言いましたが、厳密には少し違います。

この[ActionController::APIのリファレンス](https://api.rubyonrails.org/classes/ActionController/API.html)のこの部分。

> Keep in mind that templates are not going to be rendered

APIモードでも、`render`メソッドでhtmlやxmlのフォーマットを指定すれば、読み出せます。しかし、**`template`の読み出しはできない**ため、jsonをviewとして扱うことが結構難しくなっています。


# まとめ

APIを実装する上では、**ユーザー目線に立つことが何よりも大事**だと思いました。
実際に使う人の目線に立って、使いづらくないか、わかりやす構造になっているかを気にしてAPIを組み立てていく必要があると思います。

RailsでWebAPIを実装するときは、ドキュメントを読んで**仕様を理解する必要**があります。
便利な機能が揃っていて、ブラウザ向けアプリケーションの開発とあまり大差ないので楽にかける分、ブラウザ向けアプリケーションでできていたことができないことみたいな制約もあるので、注意が必要です。


# 参考

以下、参考にしたもの。


## 書籍

[Web APIの設計](https://www.amazon.co.jp/Web-API%E3%81%AE%E8%A8%AD%E8%A8%88-Arnaud-Lauret-ebook/dp/B08CK2H12H)


## サイト
### Rails API
[Rails による API 専用アプリケーション](https://railsguides.jp/api_app.html)

[Rails における JSON のシリアライズと向き合う](https://qiita.com/sakuraya/items/924ec3c3001938071407)

[Rails での JSON API 実装まとめ](https://blog.onk.ninja/2017/09/21/history_of_json_api_with_ruby)


### API設計

[翻訳: WebAPI 設計のベストプラクティス](https://qiita.com/mserizawa/items/b833e407d89abd21ee72)

[RESTful APIとは何なのか](https://qiita.com/NagaokaKenichi/items/0647c30ef596cedf4bf2)

[リソース指向アーキテクチャ(ROA)とは何なのか](https://qiita.com/NagaokaKenichi/items/0f3a55e422d5cc9f1b9c)

[RESTful APIのURI設計(エンドポイント設計)](https://qiita.com/NagaokaKenichi/items/6298eb8960570c7ad2e9)

[RESTful APIのリソース設計](https://qiita.com/NagaokaKenichi/items/ef23ca15ba0e9e5ee022)


# PORTについて

「世界中に、アタリマエとシアワセを。」 を目的に、就活や金融領域などの各産業領域に特化したメディアを展開しています。

[PORT-INC. 公式ホームページ](https://www.theport.jp/)