まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:api

Swagger を使うことで、インタラクティブに実行可能な REST API のドキュメントを作ることができます。比較的有名な所では Swagger がライブデモとして用意している「ペットストア・サービスの REST API」があります:
https://petstore.swagger.io/

2020012201



↑架空の「ペットストア・ウェブサービス」が存在している前提で、ペットやその画像を登録/更新したり、検索したり、、加えてペットストア自体の登録/管理をしたり、利用者となるユーザーの管理といったペットストア運営に必要と思われる最低限の機能の REST API が実行可能な状態で公開されています。


アプリケーションを REST API ベースで作る際に、このような Swagger による API ドキュメントを用意しておくと、REST API の仕様が確認できるだけでなく、実際にパラメータを指定した上で実行したり、実行した時のデータのやりとりやその結果までを確認することができて便利です。REST API を作成した時にセットで作っておくと、開発後の運用時や機能追加、引き継ぎといった段階においても非常に役立つインタラクティブドキュメントだと思っています。


この Swagger ドキュメントは REST API 開発後に swagger.yaml (または swagger.json)というファイルを用意することで自動作成が可能になります。特定のルールに基づいて REST API の内容(ホスト、パス、メソッド、パラメータ、返り値、・・)を記述していくと、ドキュメントの UI は自動的に作成され、指定した通りに実行が可能になります(そして実際に実行された結果を確認することもできるようになります)。

なお上述のペットストア・サービス REST API の定義内容はこちらの Swagger Editor で確認できます:
https://editor.swagger.io/

2020012205


swagger.yaml の記述方法そのものについては本ブログエントリの範囲ではないので、興味ある方は別途調べていただきたいのですが、そこまで難しい内容ではないと感じています。例えば GET /users?limit=xx&offset=yy といった具合に2つの URL パラメータ(limit, offset)を指定可能(必須ではない)な GET の REST API が存在していて、これを Swagger ドキュメントに記述する場合は swagger.yaml ファイルに以下のように指定します:
  :
/users
  get
    parameters:
      - name: limit
        type: number
        in: query
        description: 取得するデータ数
      - name: offset
        type: number
        in: query
        description: 取得するデータのオフセット
  :

実際に Swagger ドキュメントとして生成すると、この部分は以下のような UI に変換されて指定可能になる、といった具合です:
2020012202



で、ここからが本エントリの本題です。この Swagger ドキュメント(の yaml ファイル)を記述する際の、特に「ファイルアップロード」の API を記述する場合のパラメータ指定方法が特殊でちとわかりにくいものでした。試行錯誤した上で実際に動く例を見つけたので、自分の備忘録も兼ねて以下に紹介します。

まず API そのものは単純なファイルアップロード(POST /file)と仮定します。受け取るパラメータはアップロードするファイル本体だけ、他のパラメータは(Swagger ドキュメント的には特別な部分ではないので)いったん無視します。Node.js + Express 環境であれば、以下のような内容で作られているようなものです:
//. multer モジュールを利用してアップロードファイルを受け取る
var express = require( 'express' ),
    multer = require( 'multer' ),
    router = express.Router(),

    :

//. multer モジュールの設定
router.use( multer( { dest: './tmp/' } ).single( 'file' ) );

    :

//. POST /file として REST API を用意する
router.post( '/file', function( req, res ){
  //. アップロードされたファイルの情報を取り出す
  var filepath = req.file.path;
  var filetype = req.file.mimetype;

    :
    :


UI 側からこの API を呼ぶ時は、普通に以下の様な enctype="multipart/form-data" を指定した form の HTML を用意すれば実行できるものです:
<form method="POST" action="/file" enctype="multipart/form-data">
<input type="file" name="file"/>
</form>

↓こんな感じの見た目になって実行されるものです:
2020012203

このような挙動を行う API : POST /file を Swagger ドキュメントとして用意する場合の(パラメータ部分の)記述方法をどのようにするか、というのが今回のテーマでした。

ちょっと特殊な指定方法となりますが、結論としては以下のようになります:
  :
/file:
  post:
    consumes:
      - multipart/form-data
    parameters:
      - in: formData
        name: file
        type: file
        description: アップロードするファイル
        required: true
  :

特殊な部分を解説します。まず HTML の form 属性で enctype="multipart/form-data" 指定を行っていた部分ですが、上述のように consumes: で "multipart/form-data" を指定することで実現します。

またパラメータ部分ですが、POST のデータとして送信するので "in: formData" を指定します。またパラメータの種類として "type: file" も付与します。 加えて、このパラメータは API 実行時には必須指定パラメータとなるので "required: true" も付与します。swagger.yaml ではこのように指定することでファイルアップロード系の API を記述できます。

参考程度に、このように指定した swatter.yaml を実際に Swagger ドキュメントに変換して表示すると、以下のような画面になりました:
2020012204


期待通りの結果になりました。

業務やプライベートでウェブアプリを作る際に colorbox を使う機会が少なからずあります。jQuery に対応したモーダルダイアログの軽量プラグインで、メイン画面にオーバーラップするダイアログ画面を呼び出し、ダイアログを閉じるまではメイン画面が使えなくなります。HTML 的な言い方をすると、ボックス領域の表示/非表示を切り替えつつ、ここが表示されている間は他の要素にアクセスできなくさせたい場合などに便利です。

加えて、個人的によく Google MAPs API を使った地図アプリを作っています。他にも多くの地図 API はありますし、実際に使うこともありますが、ストリートビューなど他にはない機能もあって、マンホールマップを始め、多くのアプリで Google MAPs API を活用しています。

今回紹介するのはこの2つを組み合わせて使う方法、つまり colorbox のモーダルダイアログ内で Google MAPs の地図を表示する方法です。特に考慮することなく普通に(colorbox で表示する領域の中に Google MAPs の地図領域を定義しておくだけで)使えそうな気がしていたのですが、どうもこれらの初期化処理時における相性があまりよくないようで、ちょっとしたコツが必要だということがわかりました。

この「ちょっとしたコツ」の結論は
・colorbox のダイアログを表示して、
ダイアログの表示が完了した後で Google MAPs を初期化してダイアログ内に表示する
という順序で実現する必要がありそうでした。一般的には HTML ページの初期化時に Google MAPs を初期化することが多いと思うのですが、colorbox と組み合わせて使う場合は、その初期化タイミングをダイアログの表示後に(ダイアログの表示が完了したことを検知した上で動的に)行う必要がありそうでした。


以下は具体的な実現方法です。まず jQuery や colorbox、Google MAPs API の JavaScript や CSS を一通りロードします(Google MAPs API をロードする際に API KEY の取得と指定が必要です):
  :
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript" src="//maps.google.com/maps/api/js?key=(your api key)"></script>
<link href="/css/colorbox.css" rel="stylesheet"/>
<script src="/js/jquery.colorbox-min.js" type="text/javascript"></script>
  :

HTML 内に colorbox で表示するモーダルダイアログ部分(id="mapModal")を定義します。ここは初期状態では表示されていてはまずいので display:none のスタイル指定をしておきます。またモーダルダイアログ表示した際にこの id="map_canvas" のブロックの中で Google MAPs の地図を表示することになりますが、初期段階では何も定義しません:
  :
<div style="display:none">
  <div id="mapModal">
    <div id="map_canvas" style="width:100%; height:520px"></div>
  </div>
</div>
  :

ではこのブロックをモーダルダイアログ表示するための colorbox のアクションを作成します。以下の例では <span> で括られたエリア(id="span1")をクリックした時に colorbox のモーダルダイアログを 90% x 90% でインライン表示するようにしています。加えてこのモーダルダイアログが表示されきった直後に $('#map_canvas').modalMap() が実行されるように定義しています:
  :
<span href="#mapModal" id="span1">ここをクリック</span>

<script>
$(function(){
  $('#span1').colorbox({
    inline: true,
    transition: 'none',
    width: '90%',
    height: '90%',
    onComplete: function(){
      $('#map_canvas').modalMap();
    }
  });
});
</script>
  :

↑この時の <span> 要素に href 属性を付けて対象モーダルの id を指定するのが肝のようです。。

最後にこの modalMap() 関数を定義して、この中で動的に Google MAP を初期化して表示するまでのコードを記述します:
  :
<script>
$.fn.modalMap = function(){
  var latlng = new google.maps.LatLng( 35.690625, 139.699788 );
  var opt = {
    zoom: 8,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    scaleControl: true
  };

  var map = new google.maps.Map( document.getElementById( 'map_canvas' ), opt );
  map.setCenter( latlng );

  var marker = new google.maps.Marker({
    position: latlng,
    map: map
  });
};
</script>
  :

これで <span> 部分をクリックすると colorbox のモーダルダイアログを出し、ダイアログ内で動的にGoogle MAP の地図を初期化&表示する、という一連のコードが完成です:
2019090801

  ↓

2019090802

(↑わかりにくいかもしれませんが、地図部分はモーダルダイアログ表示されています)



このブログエントリの続きです:
Slack の OAuth API を使ってみる

↑ここで紹介した方法を使って実際にアプリケーション・サービスを作ってみました。作った内容はこれ↓の Slack 版です:
お絵かき LIFF アプリを作ってみた

2019052501


(実はもともとは Twitter 向けに作ったのですが)LINE のフロントエンドフレームワーク: LIFF を使って、その場で指でお絵描きした画像を LINE のトークルームに送信する、という連携アプリケーションを以前に作りました。その Slack への移植です。

なお、このアプリケーションは Barloon というエンジニア向けバーで企画されたハッカソン向けに作成しました。興味ある方は "Barloon" でググって調べてみてください。


【作った物】
こちらで MIT ライセンスで公開しています。よかったら使ってください:
https://github.com/dotnsf/slack-doodle

2019052502



以下でも紹介していますが、注意点として「ワークスペースごとにアプリケーション・サーバーが1台必要」です。その理由ですが、このアプリは Slack API を利用して作っているのですが、Slack API に登録アプリを申請する際にワークスペース(https://○○○○.slack.com/ の ○○○○部分)を指定して申請する必要があるからです。ここで申請したワークスペース向けにアプリケーションを作って動かす形になるため、複数のワークスペースで動くアプリケーションを1つの URL で動かすことができないのでした(このあたりが上記の LINE 向けアプリと異なります)。


【サーバーの動かし方】
このアプリケーションは Node.js 上で動くウェブアプリケーションです。一応レスポンシブ対応しているつもりなので、PC ブラウザからも、スマホのブラウザからも使えます(PC ブラウザの場合はマウスで、スマホブラウザの場合は指でお絵描きすることになります)。したがって Node.js が導入済みのアプリケーション・サーバーが必要です。

利用にあたっては、まず Slack API のアプリケーション登録が必要です。こちらの詳しい手順はこのリンク先を参照してください:
http://dotnsf.blog.jp/archives/1074688701.html

ただし1点だけ注意が必要です。上記ページではアプリケーションの scope に channels:read のみを指定していますが、このお絵描きアプリケーションでは更に加えて:
 chat:write:user
 files:write:user
の2つ(計3つ)の scope を指定する必要があります(描いた画像を API でアップロードするために必要な scope です)。この3つを scope に指定する必要がある、という点に注意してください。

2019052503

※必要に応じてアプリケーションのアイコンなども好きなものに変えておいてください。


その上で上記 github の URLからソースコード一式を Node.js アプリケーションサーバー上に git clone するか download & unzip して、ソースコードを展開します。

展開後、settings.js というファイルが存在しているので、このファイルをテキストエディタで開き、exports.slack_client_id の値と、exports.slack_client_secret の値をそれぞれ Slack API 登録アプリの client_id および client_secret の値に書き換えて保存します(このあたりの具体的な情報はこちらを参照してください)。

そしてアプリケーションサーバーを起動、これで準備完了です:
$ npm install
$ node app

【遊び方】
アプリケーション・サーバー(例えば https://slack-doodle.xxx.com/ )が動いている状態で、そのアプリケーションサーバーの URL に PC かスマホのブラウザにアクセスするだけなのですが、その前にやっておくことがあります。

上記でも触れたのですが、このアプリケーションサーバーは特定のワークスペース向けに作られています(そのワークスペースでしか使えません)。一方、ブラウザで Slack にアクセスすると、いろんなワークスペースに切り替えて使うことができます。ということはブラウザが目的のワークスペース以外のセッションなどを保持している可能性があり、その状態で使っても期待通りの挙動にならない可能性があるのです。

この状態をクリアするために『念の為』以下の手順を最初に行っておくことを推奨します。まず PC かスマホのブラウザを起動し、目的のワークスペース(例えば目的のワークスペースが "abc" であれば https://abc.slack.com/ )にアクセスして、認証してログインします。これでブラウザが目的のワークスペースのセッションを保持した状態が作れました。

その上で、そのままアプリケーションサーバー( https://slack-doodle.xxx.com/ )にアクセスします。以下はスマホでの画面例ですが、PCブラウザだともう少し横に大きな画面になると思います(一応、この未ログインの時点でお絵描きを試すことはできるのですが、送信することはできません)。ではログインするため左上の "Login" をタップします:
2019052504


Slack アプリケーションのページに転送され、目的のワークスペースに向けた OAuth の認証が行われます:
2019052505


内容を確認して、「許可する」を選択します:
2019052506


するとログインが完了し、元のアプリの画面に戻ります。この時、画面上部にワークスペース上で自分が利用することのできるチャネルが選択できるようになり、POST をクリックすると、ここで選択したチャネルに描いた画像がアップロードされます:
2019052507


実際に POST するとこんな感じで目的のワークスペースの目的のチャネルに画像をアップロードすることができます:
2019052508


この系統のアプリ、Twitter ではじめて、LINE に移植して、今回は Slack にも移植して・・・ 次は何にしよう?? ちなみに facebook は publish の API が昨年廃止になってしまったので技術的に作れないことがわかってます。



某アプリを Slack 対応する経緯で Slack API の中の、特に認証/認可を司る OAuth API を使う機会があったので自己まとめです。

もともとやりたかったのはウェブアプリに Slack アカウントでログインして、そのログインした人の権限でチャネル一覧を取得し(※)、ウェブアプリから指定したチャネルにメッセージを書き込む、ということでした。この中の※部分までを Node.js + Express + EJS で実現したコードを Github に公開しています(後述)。


実際に試してみるにはまず Slack に対象アプリケーションを登録する必要があります。 https://api.slack.com/apps を開いてログインし、"Create New App" ボタンをクリックしてウェブアプリを登録します:
2019052401


登録するアプリの名前と、対象ワークスペースを指定します(つまり同じアプリを複数のワークスペースで使いたい場合は、アプリを複数登録する必要があります)。以下では名前は "Slack OAuth Sample"、ワークスペースは "dotnsf" を指定しています(ワークスペースはログインしたユーザーが利用可能なワークスペース一覧から選択します)。最後に "Create App" ボタンをクリックして作成します:
2019052402


すると指定したアプリケーションの API 設定画面に切り替わります。画面左上に入力したアプリ名がデフォルトアイコンと一緒に表示されていて、"Basic Information" メニューが選択されていることを確認します:
2019052403


この画面を下スクロールすると App Credentials という項目があります。この中の Client IDClient Secret の値を後で使うので、どこかにコピーしておくか、いつでもこの画面を開ける状態にしておきましょう。なお Client ID の値は画面内に表示されていますが、Client Secret の値は初期状態では非表示になっています。"Show" ボタンをクリックして内容を表示し、その表示された値をあとで使うことに注意してください。またこれらの値は他の人には教えないように、自分で管理する必要があります:
2019052404


次に画面左のメニューから "OAuth & Permissions" を選び、少し下にスクロールすると Redirect URLs という項目があります。ここにウェブアプリケーションを動かす際のコールバック URL を登録しておく必要があります。"Add New Redirect URL" ボタンをクリックします:
2019052405


すると Redirect URL を追加する画面になるので、http(s)://サーバー名/slack/callback と入力します。この値は開発時には開発時用のサーバー名とポート番号、本番環境では本番環境用のサーバー名を指定する必要があります。下図では開発時向けに localhost の 6010 番ポートで動かす想定で http://localhost:6010/slack/callback と指定しています。ここの値は実際の環境に合わせて適宜変更してください。入力し終わったら "Add" ボタンをクリックして、その後 "Save URLs" ボタンをクリックします:
2019052406


画面上部に "Success!" というメッセージが表示されればリダイレクト URL の設定は完了です。正しい Redirect URLs が登録されたことを確認します:
2019052407


続けて、このアプリで利用する Slack 機能のスコープを指定します。実は OAuth 認証だけであればここの設定は不要なのですが、今回のデモアプリでは OAuth 認証後にログインユーザーが参照できるチャネルの一覧を取得して表示する、という機能が含まれています。また実際のアプリケーションではそのアプリケーションで実装する機能によって、ここでスコープを追加する必要があります:
2019052408


今回はログインユーザーが利用できるチャネル一覧を取得するため、"channels:read" スコープを追加します。また他に必要なスコープがあればここで追加します。最後に "Save Changes" ボタンをクリックして変更を反映します:
2019052409


これで Slack API 側の設定は完了しました。

では改めて Github からアプリケーションを取得します。Node.js がインストール済みの実行サーバー上で以下の URL を指定して git clone するか、ソースコードをダウンロード&展開してください:
 https://github.com/dotnsf/slack-oauth

2019052410


ソースコード内の settings.js をテキストエディタで開き、exports.slack_client_id の値と exports.slack_client_secret の値を上記で確認した client_id と client_secret の値に(コピー&ペーストなどで)変更して、保存してください。

なお、このサンプルアプリケーションでは以下のリクエスト API(?)が用意されていて、これらを明示的&内部的に使って動きます:
リクエスト API用途
GET /ユーザーがアクセスする唯一のページ。アクセス時に認証情報がセッションに含まれているとチャネル一覧が表示される。認証情報がセッションに含まれていない場合は認証前とみなして「ログイン」ボタンを表示する
GET /slack/loginユーザーページで「ログイン」ボタンをクリックした時に実行される。Slack の OAuth 認証ページにリダイレクトされる
GET /slack/callbackSlack の OAuth 認証ページで Authorize された時のリダイレクトページ。この URL が Slack OAuth 設定時に指定されている必要がある。アクセストークンを暗号化してセッションに保存し、GET / へリダイレクトされる
POST /slack/logoutログアウト(セッション情報を削除)する
GET /channelsチャネル一覧を取得する。認証後にユーザーページが表示されると内部的にこの REST API が AJAX 実行されて、画面にチャネル一覧が表示される。


では実際に起動してみます。起動サーバーにログインし、ソースコードのあるフォルダに移動した状態で、以下を実行します:
$ npm install
$ node app

そしてウェブブラウザで起動中のアプリケーションにアクセスします。以下の例では localhost:6010 でアプリケーションが起動されている想定になっているので、http://localhost:6010/ にアクセスします。上記の GET / が実行され、ログイン前のシンプルなページが表示されます。ここで "Login" を選択します:
2019052411


GET /slack/login が実行され、ブラウザは Slack API の OAuth 認証ページにリダイレクトされます。アプリケーションが利用する scope が表示され、このまま認証処理を許可するかどうかを聞かれます。許可する場合は "Authorize" を選択します:
2019052412


Authorize を選択すると認証と認可が完了し、そのアクセストークンが GET /slack/callback へ渡されます。そこでアクセストークンを暗号化してセッションに含めます。この状態であらためてトップページ(GET /)が表示され、ログイン処理が住んでいるのでログイン後の画面が表示されます。AJAX で GET /channels が実行され、ログインユーザーが参照することのできるチャネルの一覧が表示されれば成功です:
2019052413


以上、Slack API の OAuth を使ってウェブアプリケーションから Slack の認証を行い、認証ユーザーの権限で Slack API を外部から実行する、というアプリケーションのサンプルを作って実行するまでの手順紹介でした。


 

Swagger APIはインタラクティブに動く REST API のドキュメントを比較的簡単に作ることができて便利です。自分も実際に業務やプライベートアプリに使っています。

この機能を使う場合、YAML と言われるフォーマットをベースにした記述方法で API の仕様を記述するだけで動く API ドキュメントページを作ることができます。

で、この YAML で仕様を記述する際に「コメント」を記述したくなることがあります。実質的にプログラミングする必要なく API テストページを作れるのは便利で、プログラミング時と同様にコメントを残したくなることもあると思います。 が、YAML でコメントを書いたことがなかったので、改めて明示的にコメントを残そうとした際の手法がわからず、調べてみました。

答えとしては「# から行末までがコメント」となるようです。つまり一行単位でコメントが生成されます。「ここからここまで」という範囲コメントは存在していないようです。
info:
  description: 普通の行
#  description: コメント行
  titie: タイトル   # ここはコメント  

なお、コメント扱いにしたくない # を含めたい場合は \# のようにバックスラッシュでエスケープすることで実現できます。




 

このページのトップヘ