シェルスクリプトとCGIで作るREST APIエンドポイントもどき
要約
この記事は、25年前に既に使われていたような枯れた技術・CGIやシェルスクリプトを持ち出して、なんか新しめな技術や概念であるREST APIのエンドポイントを模したものを作ろうというものです。変なことやってんなー、と思いつつゆるりとお読みください。
注意・免責事項
今回作成したプログラムは、ローカルでの実験を予定した非常に簡素なもので、一切のWebアプリケーション向けのセキュリティ対策を施していません。万が一このプログラムの技法を利用する場合は、必ず入力値のチェックや無害化、適切な実行権限設定などのセキュリティ対策を実施してください。このプログラムを利用した場合の損害については責任を負えませんのでご留意ください。
はじめに
世界はWeb APIに満ちています。公開されているパブリックAPIもあり、外からアクセスできるようだけど表には出ていない謎のAPI、あるいは業務システムを疎結合にするためにWeb API形式でメッセージをやり取りしている例もあります。
Web APIを作るときは、たいていは後ろにルーティングを制御できる仕組み、たとえばフレームワークを利用して構築すると思います。ルーティングやパラメータの処理を明快に記述し、その先のデータベース処理とも容易に連携できます。
でも、私はやりたくなりました。「ApacheやnginxにCGIを動かしてもらって、RESTの思想に基づくWeb APIのエンドポイント風なURLとHTTPメソッドを受け付ける仕組みを作りたい」と。しかも、シェルスクリプトとUNIXコマンド群を使って。
私はシェルスクリプトに魅せられてしまった男です。きっかけは約5年前に出会った「Windows/Mac/UNIX すべてで20年動くプログラムはどう書くべきか」(松浦智之著・USP研究所監修、C&R研究所、2016年11月)[1]という本でした。こんなにいろいろなことができるのかと驚き、それから自分でいろいろ試しました。今回の実験はその延長にあります。シェルスクリプトは決して万人が容易に操れるものではなく、自分も大概bashからボコボコにされていますが、それでもやめられません。多くの人と共同で作り上げるプロジェクトのメインに据えるには技術者が足りませんが、自分が全責任を負えるプライベートなプロジェクトでちまちま使っていこうと思っています。
やりたいこと
- REST APIのエンドポイントっぽいアクセスができる仕組みを作る。
- http://hogehoge.fuga/webapi/v1/foo/bar でGETやPOST、DELETEなどのメソッドを受け付ける
やったこと
- Ubuntuの用意
- Apacheのインストール
- CGIモジュールの有効化
- サイト設定を作る
- スクリプトを置く
- 接続テスト
サイト設定一例
/webapi/ 以下にエンドポイントを作ります。以下の設定では、/usr/lib/cgi-bin/webapi/v1 というファイルをCGIスクリプトとして実行するようにします。
<IfModule mod_alias.c>
<IfModule mod_cgi.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule>
<IfModule mod_cgid.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule>
<IfDefine ENABLE_USR_LIB_CGI_BIN>
ScriptAlias /webapi/ /usr/lib/cgi-bin/webapi/
<Directory "/usr/lib/cgi-bin/webapi/">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
<FilesMatch "^v1$">
SetHandler cgi-script
</FilesMatch>
</Directory>
</IfDefine>
</IfModule>
スクリプト例
スクリプト名を「v1」として、/usr/lib/cgi-bin/webapi/ に置き、実行権限を付与します。
このスクリプトは、実行時のHTTPメソッドと、CGIプログラムに渡されたパス(v1以降の部分)を返却します。
#!/bin/bash
# v1
# WebAPIエンドポイント テストシェルスクリプト
# 受信したHTTPメソッド、およびシェルスクリプト名の後に続くパスを取得
# HTTPメソッドとパスの部分を解釈して、APIエンドポイントを振り分けるのに
# 使えるかもしれない
# HTTP レスポンスコードを変更したい時は次のコメントアウトを解除
# echo "Status: 418 I'm a teapot"
echo -ne "Content-Type: text/plain\n\n"
echo "Method: ${REQUEST_METHOD}"
echo "Path-Info: ${PATH_INFO}"
実験
# 実行
curl http://hogehoge.fuga/webapi/v1/foo/bar
# 返却
Method: GET
Path-Info: /foo/bar
使い道
Apacheだけが動いているようなサーバで、HTTP 80番 / 443番ポートを使って何かWeb APIを公開してみたい時などでしょうか……?
もし実用するとしたら、シェルスクリプトではなく、別のプログラミング言語でスクリプトを書いた方がいいと思います。
余談
古い技術ばかり使っていますが、私は2022年現在31歳です。若いわけではありませんが、あまり年が行っているわけでもありません……さすがに中年には遠いですよね?
Discussion