2020-02-05 / 最終更新日時 : 2020-01-24 senooken other GitHub APIを使ったWeb API利用手順の学習 FacebookXHatenaPocketCopy 以前書評を書いた「Software Design 2018年3月号」のp. 18-31「第1章 そもそもWeb APIとは何か」の特集記事を参考に,GitHub APIを例にWeb APIの利用手順を学習する。Web APIの使い方自体は,Web APIごとにほとんど違いはなく,以下の3の手順で行う。アクセストークンの取得アクセス方法の学習コーディング Webアプリケーションの場合,先日サンプルを投稿したJavaScriptのXMLHttpRequestを使ったり,HTTP通信を行うライブラリーが使われる。 目次 アクセストークンの取得 アクセス方法の学習 コーディング 結論 アクセストークンの取得 GitHubではOAuth2を自前で実装して取得する他に,簡単にOAuth2トークンを生成できるアクセストークンを提供している。自分のトークンをその場で生成できるので簡単だ。個人の設定ページで作成できる。ページにアクセス後,[Generate new token] を選択する。 [Personal access tokens] 画面 アクセス権の選択画面が表示される。[Note] に [Bookmarklet] と入力し,[Select scopes]>[☑gist] を選択して,[Generate token] を選択する。 [New personal access token] 画面 画面が変わってアクセストークンが表示される。 作成したアクセストークンの表示 アクセストークンは二度と表示されないので,コピーして控えておく。万が一見失ったり忘れたりしても,削除してまた作成すれば問題ない。上記画面のアクセストークンは削除済みなので問題ない。 アクセス方法の学習 GitHubのドキュメントは [https://developer.github.com/v3/] にある。最新はGraphQLを扱ったv4だが,GraphQLはよくわからないので,ひとまずREST APIのv3を参照する。まず冒頭でhttps://api.github.comが要請のエンドポイントであることが書いてある。そして,[Authnentication] に,以下のコマンドのようにHTTPヘッダーのAuthorizationヘッダーに取得したトークンを指定すればよいと書いてある。curl -H "Authorization: token OAUTH-TOKEN" https://api.github.com さらに,Gistについては [Create a gist] にGistへの登録方法が書いてある。以下のようにHTTPメソッドのPOSTを使う。 POST /gists 要請のパラメーターも書かれている。 /gistsへのHTTP要請のパラメーターNameTypeDescriptionfilesobject必須。ファイル名と内容。filesオブジェクト内のキーがstring型でファイル名を表す。なお,Gistが内部で自動的に使うため,ファイル名にgistfile[0-9]+ (gistfileに数字の接尾辞) を指定してはいけない。descriptionstringgistの説明。publicbooleantrueにすると一般公開される。既定はfalse。 fileオブジェクトは以下のキーを値に持つ。 fileオブジェクトの中身NameType Descriptioncontentstringファイルの内容。 POSTメソッドのbodyとその応答の事例が以下のように掲載されている。 Example { "description": "Hello World Examples", "public": true, "files": { "hello_world.rb": { "content": "class HelloWorld\n def initialize(name)\n @name = name.capitalize\n end\n def sayHi\n puts \"Hello !\"\n end\nend\n\nhello = HelloWorld.new(\"World\")\nhello.sayHi" }, "hello_world.py": { "content": "class HelloWorld:\n\n def __init__(self, name):\n self.name = name.capitalize()\n \n def sayHi(self):\n print \"Hello \" + self.name + \"!\"\n\nhello = HelloWorld(\"world\")\nhello.sayHi()" }, "hello_world_ruby.txt": { "content": "Run `ruby hello_world.rb` to print Hello World" }, "hello_world_python.txt": { "content": "Run `python hello_world.py` to print Hello World" } } } Response Status: 201 Created Location: https://api.github.com/gists/aa5a315d61ae9438b18d { "url": "https://api.github.com/gists/aa5a315d61ae9438b18d", "forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks", "commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits", "id": "aa5a315d61ae9438b18d", "node_id": "MDQ6R2lzdGFhNWEzMTVkNjFhZTk0MzhiMThk", "git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git", "git_push_url": "https://gist.github.com/aa5a315d61ae9438b18d.git", "html_url": "https://gist.github.com/aa5a315d61ae9438b18d", "files": { "hello_world.rb": { "filename": "hello_world.rb", "type": "application/x-ruby", "language": "Ruby", "raw_url": "https://gist.githubusercontent.com/octocat/6cad326836d38bd3a7ae/raw/db9c55113504e46fa076e7df3a04ce592e2e86d8/hello_world.rb", "size": 167, "truncated": false, "content": "class HelloWorld\n def initialize(name)\n @name = name.capitalize\n end\n def sayHi\n puts \"Hello !\"\n end\nend\n\nhello = HelloWorld.new(\"World\")\nhello.sayHi" }, "hello_world.py": { "filename": "hello_world.py", "type": "application/x-python", "language": "Python", "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/99c1bf3a345505c2e6195198d5f8c36267de570b/hello_world.py", "size": 199, "truncated": false, "content": "class HelloWorld:\n\n def __init__(self, name):\n self.name = name.capitalize()\n \n def sayHi(self):\n print \"Hello \" + self.name + \"!\"\n\nhello = HelloWorld(\"world\")\nhello.sayHi()" }, "hello_world_ruby.txt": { "filename": "hello_world_ruby.txt", "type": "text/plain", "language": "Text", "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/9e4544db60e01a261aac098592b11333704e9082/hello_world_ruby.txt", "size": 46, "truncated": false, "content": "Run `ruby hello_world.rb` to print Hello World" }, "hello_world_python.txt": { "filename": "hello_world_python.txt", "type": "text/plain", "language": "Text", "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/076b4b78c10c9b7e1e0b73ffb99631bfc948de3b/hello_world_python.txt", "size": 48, "truncated": false, "content": "Run `python hello_world.py` to print Hello World" } }, "public": true, "created_at": "2010-04-14T02:15:15Z", "updated_at": "2011-06-20T11:34:15Z", "description": "Hello World Examples", "comments": 0, "user": null, "comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/", "owner": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "truncated": false, "forks": [ { "user": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "url": "https://api.github.com/gists/dee9c42e4998ce2ea439", "id": "dee9c42e4998ce2ea439", "created_at": "2011-04-14T16:00:49Z", "updated_at": "2011-04-14T16:00:49Z" } ], "history": [ { "url": "https://api.github.com/gists/aa5a315d61ae9438b18d/57a7f021a713b1c5a6a199b54cc514735d2d462f", "version": "57a7f021a713b1c5a6a199b54cc514735d2d462f", "user": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "change_status": { "deletions": 0, "additions": 180, "total": 180 }, "committed_at": "2010-04-14T02:15:15Z" } ] } 試しに上記のサンプルコードをcurlコマンドで試してみる。curl -H "Authorization: token $OAUTH_TOKEN" -d '{"files": {"hello.txt": {"content": "hello."}}}' https://api.github.com/gistsOAUTH_TOKEN変数に入手した認可コードを格納している。-dのコマンド引数ではなく,ファイルを指定する場合,以下のコマンドを実行する。curl -H "Authorization: token $OAUTH_TOKEN" -d @file.json https://api.github.com/gists file.jsonには-dで指定していたJSONを記しておく。実行すると以下の通り,自分のGistにファイルがアップロードされている。 Gistへの登録結果 これでWeb APIのアクセス方法の学習が完了となる。 コーディング アクセストークンを入手し,アクセス方法を学習したので,これらの情報を使って実際のコーディングに移る。プログラミング言語によって細かい文法は異なるものの,基本的な流れは以下となる。アクセストークンやエンドポイントの変数への格納送信JSONデータの作成HTTP要請の作成・送信サンプルコードは,Webブラウザーで選択範囲をGistへ登録するブックマークレットの実装例を以下に記す。サンプルコードはGitHubでも公開している。 ブラウザーでの選択範囲をGistに登録 "use strict"; // API info. let token = 'fba5bdae4a80b6ef91b446a926002031455ab5aa'; let url = 'https://api.github.com/gists'; // Target data. let content = window.getSelection().toString(); let fileName = prompt('File name?', 'index.js'); // JSON. let json = { "description": 'Code that was on ' + location.href + '.', 'public': true, 'files': {} }; json.files[fileName] = { 'content': content }; // HTTP request. let request = new XMLHttpRequest(); request.open('POST', url); request.setRequestHeader('Authorization', 'token ' + token); request.send(JSON.stringify(json)); request.onload = function() { if ((200 <= request.status) && (request.status < 400)) { var json = JSON.parse(request.responseText); if (confirm('Open URL?')) { window.open(json.html_url, '_blank'); } } else { alert('Error occurred' + request.responseText); } }; YOUT_TOKENに自分のトークンを記入して使う。このコードでは,Webブラウザーで現在選択中のテキストをGistに登録する。最後に,このJavaScriptのコードをブックマークレットにする。元々の記事では,ブックマークレットの作成に「WDF – Software : ブックマークレット作成スクリプト」を使っていた。ただし,こちらはコメントを自分で削除しておく必要がある。コメントの削除も自動で行ってくれる「ブックマークレット作成」を使う。先頭1行目に以下の内容を記入してから貼り付ける。// title:(gist)[ブックマークレット作成] を選択すると,[ブックマークレット] 欄に と書かれたリンクができる。これをブックマークツールバーにドラッグ・ドロップで登録する。これにより,ボタンを押すだけでいつでもGistに登録できる。 結論GitHub APIを例に,Web APIの利用手順を学習した。curlやJavaScriptのXMLHttpRequestを使ったWeb APIの大まかな利用手順がわかり,今までよくわからなかったWeb APIというものの扱い方が具体的にわかってきた。実際にアクセス可能なWeb APIをもう少し試して扱い方に慣れていきたい。 リンク 関連 FacebookXHatenaPocketCopy コメントを残す コメントをキャンセルメールアドレスが公開されることはありません。 ※ が付いている欄は必須項目ですコメント ※ 名前 ※ メール ※ サイト 次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。 新しいコメントをメールで通知 新しい投稿をメールで受け取る Δ