Nginxのリバースプロキシを用いてRESTでないAPIをRESTっぽく呼び出せるようにする
2016年 12月 08日
このエントリーは、エキサイト Advent Calendar 2016 の12/8の記事です。
こんにちは。ニュースチームのエンジニアのツボイです。
ニュースチームで使っているAPIの中には、RESTでないAPIがあります。修正するとなると結構工数がかかってしまうので、今回はNginxでAPIゲートウェイを作成し、既存APIをRESTっぽく呼び出せるような実装を検討してみました。
Nginxを使用した理由は最近Nginxを触る機会があったことと、実装する上で想像しやすかったためです。
API設計 ※実際に使用しているAPIとは多少異なります
http://api.example.com/v1/api/
IPアドレス
192.168.161.100
GET /v1/api/news/list/
ニュース記事一覧を取得する。
Parameter | Required |
---|---|
category | 任意 |
GET /v1/api/news/detail/
ニュース記事詳細を取得する。
Parameter | Required |
---|---|
id | 必須 |
category | 任意 |
GET /v1/api/category/list/
カテゴリ一覧を取得する。
Parameter | Required |
---|---|
なし |
GET /v1/api/news/movie/list/
ニュース動画一覧を取得する。
Parameter | Required |
---|---|
category | 任意 |
GET /v1/api/news/movie/detail/
ニュース動画詳細を取得する。
Parameter | Required |
---|---|
movie_id | 必須 |
category | 任意 |
このAPIをRESTっぽく呼び出せるようにします。
以下のような感じで呼び出したいですよね!(個人の意見です)
API設計 改 ※実際に使用しているAPIとは(ry
http://api.example.com/news/
IPアドレス
192.168.161.110
GET /news/
ニュース記事一覧を取得する。
Parameter | Required |
---|---|
category | 任意 |
GET /news/:id/
ニュース記事詳細を取得する。
Parameter | Required |
---|---|
category | 任意 |
GET /news/category/
カテゴリ一覧を取得する。
Parameter | Required |
---|---|
なし |
GET /news/movie/
ニュース動画一覧を取得する。
Parameter | Required |
---|---|
category | 任意 |
GET /news/movie/:movie_id/
ニュース動画詳細を取得する。
Parameter | Required |
---|---|
category | 任意 |
一覧取得の/listを省略し、詳細取得の必須パラメータであるidをパスに指定する形式に変更しました。このような形式で呼び出せるようにNginxで実装します。
NginxでのRESTっぽくAPIを呼び出す実装
nginx.confupstream news-api {
server 192.168.161.100;
}
server {
・
・
・
location /news {
location = /news/ {
rewrite ^(.*)$ /v1/api/news/list/ break;
proxy_pass http://news-api;
}
location ~ ^/news/([^/]*)/?$ {
rewrite ^/news/([^/]*)/?$ /v1/api/news/article/?id=$1 break;
proxy_pass http://news-api;
}
location ^~ /news/category {
location = /news/category/ {
rewrite ^(.*)$ /v1/api/news/category/list/ break;
proxy_pass http://news-api;
}
}
location ^~ /news/movie {
location = /news/movie/ {
rewrite ^(.*)$ /v1/api/news/movie/list/ break;
proxy_pass http://news-api;
}
location ~ ^/news/movie/([^/]*)/?$ {
rewrite ^/news/movie/([^/]*)/?$ /v1/api/news/movie/detail/?movie_id=$1 break;
proxy_pass http://news-api;
}
}
}
・
・
・
}
気をつけることはlocationディレクティブの優先順位です。ニュース記事詳細(/news/:id/)よりカテゴリ一覧(/news/category/)を優先したいのでカテゴリ一覧を前方一致、記事詳細を正規表現で記述しています。今回作成したものはlocationの順不同で動作するようにしました。
APIのパスが多く冗長になる場合はlocation /news {}の中身をincludeして別ファイルにしておくと見やすくなると思います。
nginx.confupstream news-api {
server 192.168.161.100;
}
server {
・
・
・
location /news {
include /{$pj}/news.conf;
}
・
・
・
}
news.conf
location = /news/ {
rewrite ^(.*)$ /v1/api/news/list/ break;
proxy_pass http://news-api;
}
location ~ ^/news/([^/]*)/?$ {
rewrite ^/news/([^/]*)/?$ /v1/api/news/article/?id=$1 break;
proxy_pass http://news-api;
}
location ^~ /news/category {
location = /news/category/ {
rewrite ^(.*)$ /v1/api/news/category/list/ break;
proxy_pass http://news-api;
}
}
location ^~ /news/movie {
location = /news/movie/ {
rewrite ^(.*)$ /v1/api/news/movie/list/ break;
proxy_pass http://news-api;
}
location ~ ^/news/movie/([^/]*)/?$ {
rewrite ^/news/movie/([^/]*)/?$ /v1/api/news/movie/detail/?movie_id=$1 break;
proxy_pass http://news-api;
}
}
外部のAPIでAPI自体の変更ができないときも、この方法ならRESTっぽく呼び出せるようになるので、(公開APIにRESTでないAPI自体あまりないと思いますが)試してみてください。
明日のAdvent Calendarは、同じくニュースチームのエンジニアです。お楽しみに!