[翻訳] httr vignette: APIパッケージ作成のベストプラクティス

この文書は Hadley Wickham によるRパッケージ[`httr`](https://cran.r-project.org/web/packages/httr/) (version 1.1.0) のビネット "[Best practices for writing an API package](https://cran.r-project.org/web/packages/httr/vignettes/api-packages.html)" の翻訳です．
License: [MIT](https://opensource.org/licenses/MIT)

* 関連記事：[httrはやわかり](http://qiita.com/nakamichi/items/14f9952445089927c38e)

---

<!-- # Best practices for writing an API package -->
APIパッケージ作成のベストプラクティス
--------------------

<!-- This document collects best practices for writing a package that connects to a web API. The goal is to help you produce a package that is safe, secure and keeps working in the long run. -->
この文書にはweb APIに接続するパッケージを書くためのベストプラクティスを集めています．目標は，安全かつセキュアで長期に渡って動作し続けるパッケージを読者が作成するのを手助けすることです．

<!-- If you're new to working with web APIs, start by reading "[An introduction to APIs](https://zapier.com/learn/apis)" by zapier. -->
もしweb APIに取り組むのが初めてであれば，zapierによる "[An introduction to APIs](https://zapier.com/learn/apis)" を読むことから始めてください．

<!-- ## Key info -->
## 重要な情報

<!-- When writing an API, it's best to start with some helper functions that capture the common conventions of the API in one place. These functions capture information like: -->
APIを書くときには，そのAPIの一般的な規約を表現するヘルパ関数を書くことから始めるのがベストです．これらの関数は以下のような情報を表すことになります：

<!-- * the base URL for all API requests. -->
<!-- * how authentication works -->
<!-- * how the API is versioned -->
<!-- * how results (including errors) are returned -->
* すべてのAPIリクエストのベースURL
* 認証の動作方法
* APIのバージョン
* 結果（エラーも含む）の返却方法

<!-- The following example shows how you might write these functions for the github API. Note that I've used lots of small function to avoid repeating code as much as possible. This is important when writing code that talks to APIs because APIs change all too frequently and you only want to have to change important facts in one place. -->
以下ではgithub APIに対して，これらの関数の書き方の一例を示します．コードのくり返しをできるだけ避けるために，多数の小さな関数を使っていることに注目してください．これはAPIと通信するコードを書くときには重要なことです．というのも，APIはあまりに頻繁に変更されるので，重要な事項は一か所にまとめておいて，そこだけ変更すれば済むようにしたいからです．

<!-- We start with functions to execute `GET` and `POST` requests: -->
`GET`と`POST`のリクエストを実行する関数を書くことから始めましょう：


```r
github_GET <- function(path, ..., pat = github_pat()) {
  auth <- github_auth(pat)
  req <- GET("https://api.github.com", path = path, auth, ...)
  github_check(req)

  req
}

github_POST <- function(path, body, ..., pat = github_pat()) {
  auth <- github_auth(pat)

  stopifnot(is.list(body))
  body_json <- jsonlite::toJSON(body)

  req <- POST("https://api.github.com", path = path, body = body_json,
    auth, post, ...)
  github_check(req)

  req
}
```

<!-- These need some additional infrastructure to authenticate, check the responses and give useful error messages and parse responses: -->
このコードには認証やレスポンスの確認，また有用なエラーメッセージの表示やレスポンスのパースを行うための追加のインフラが必要です．


```r
github_auth <- function(pat = github_pat()) {
  authenticate(pat, "x-oauth-basic", "basic")
}

github_check <- function(req) {
  if (req$status_code < 400) return(invisible())

  message <- github_parse(req)$message
  stop("HTTP failure: ", req$status_code, "\n", message, call. = FALSE)
}

github_parse <- function(req) {
  text <- content(req, as = "text")
  if (identical(text, "")) stop("No output to parse", call. = FALSE)
  jsonlite::fromJSON(text, simplifyVector = FALSE)
}

github_pat <- function() {
  Sys.getenv('GITHUB_PAT')
}

has_pat <- function() !identical(github_pat(), "")
```

<!-- `github_pat()` is just a shim, to get my personal access token from an environment variable. Later, you'll see a better, if lengthier, way of writing it in the authentication section. -->
`github_pat()`は環境からパーソナルアクセストークンを取ってくるために挿入しているだけです．後ほど「認証」のセクションで，長くはなりますがもっと良い書き方を見ることになります．

<!-- Once you have these pieces in place, it's simple to implement API functions. For example, we could implement a `rate_limit()` function that tells you how many calls against the github API are available to you. -->
いったんこれらのパーツを整えてしまえば，API関数を実装するのは簡単です．たとえば，github API の呼び出し可能回数がどれだけ残っているか知らせる`rate_limit()`関数を実装することができるでしょう．



```r
rate_limit <- function() {
  req <- github_GET("rate_limit")
  github_parse(req)
}

if (has_pat()) {
  str(rate_limit())
}
```

<!-- After getting the first version getting working, you'll often want to polish the output to be more user friendly. For this example, we can parse the unix timestamps into more useful date types. -->
最初のバージョンを動くようにした後には，大抵，出力がよりユーザフレンドリーになるように改良
したくなるでしょう．そのような例として，UNIXタイムスタンプをパースしてもっと有用なデータ型に変換することができます．


```r
rate_limit <- function() {
  req <- github_GET("rate_limit")
  core <- github_parse(req)$resources$core

  reset <- as.POSIXct(core$reset, origin = "1970-01-01")
  cat(core$remaining, " / ", core$limit,
    " (Reset ", strftime(reset, "%H:%M:%S"), ")\n", sep = "")
}

if (has_pat()) {
  rate_limit()
}
```

<!-- Depending on the complexity of the API, you might want to keep separate the functions that return a request object and the functions that parse it into a useful R object. -->
APIの複雑さによっては，リクエストオブジェクトを返す関数と，それをパースして有用なRオブジェクトに変換する関数を分けておきたい場合もあるかもしれません．

<!-- ## Parsing output and posting input -->
## 出力のパースと入力のポスト

<!-- Most APIs communicate either with json or xml. To work with json, I recommend the `jsonlite` package. To work with xml, use the `xml` package. -->
ほとんどのAPIはJSONかXMLで通信を行います．JSONを扱うには`jsonlite`パッケージがおすすめです．XMLを扱うには`xml`パッケージを使ってください．

<!-- httr provides some default parsers with `content(..., as = "auto")` but I don't recommend using them inside a package. Instead get the content as text with `content(..., as = "text")` and parse it yourself. The API might return invalid data, but this should be rare, so you can just rely on the parser to provide a useful error message. -->
httr は`content(..., as = "auto")`でデフォルトのパーサを提供していますが，これをパッケージ内部で使用することは推奨しません．代わりにコンテンツは`content(..., as = "text")`で取得して，パースは自分で行います．APIは（めったに起こるべきではないのですが）無効なデータを返してくるかもしれないので，有用なエラーメッセージを提供してくれるパーサが頼りになります．


```r
github_parse <- function(req) {
  text <- content(req, as = "text")
  if (identical(text, "")) stop("")
  jsonlite::fromJSON(text, simplifyVector = FALSE)
}
```

<!-- Many APIs use [content negotiation](http://en.wikipedia.org/wiki/Content_negotiation) to determine whats sort of data to send back. If the API you're wrapping does this, then you might find `accept_json()` and `accept_xml()` to be useful. -->
多くのAPIは送り返すデータの種類を決めるのに[コンテントネゴシエーション](http://en.wikipedia.org/wiki/Content_negotiation)を使用しています．もし読者がラッパーを書いているAPIがこの機能を使用している場合，`accept_json()`と`accept_xml()`が有用だと思うかもしれません．


<!-- ## Responding to errors -->
## エラーに対処する

<!-- First, check the HTTP status code. Status codes in the 400 range usually mean that you've done something wrong. Status codes in the 500 range typically mean that something has gone wrong on the server side. This however, might be that you sent the server something badly formed. -->
まずはHTTPステータスコードを確認しましょう．400番台のステータスコードは普通，あなたが何か誤ったことを意味しています．500番台のステータスコードは，概してサーバ側で何かが上手くいかなかったことを意味していますが，サーバに何かを間違った形式で送ってしまったのかもしれません．

<!-- When you get an error, often the body of the request will contain some useful information, so you should parse it and pull out the error. This will vary based on the API. For github, we can parse it as follows: -->
エラーを受け取ったときには，大抵リクエストのボディに有用な情報が含まれているので，それをパースしてエラーの内容を抜き出すべきです．APIによって内容は異なりますが，github の場合は以下のようにしてパースすることができます：


```r
github_parse <- function(req) {
  text <- content(req, as = "text")
  if (identical(text, "")) stop("No output to parse", call. = FALSE)
  jsonlite::fromJSON(text, simplifyVector = FALSE)
}
```

<!-- If the API returns special errors for common problems, you might want to provide more detail in the error. For example, if you run out of requests and are [rate limited](https://developer.github.com/v3/#rate-limiting) you might want to tell the user how long to wait until they can make the next request (or even automatically wait that long!). -->
APIがよくある問題に対して特別なエラーを返す場合には，エラーについてより詳しい情報をユーザに提供したくなるかもしれません．たとえば，リクエストを使い果たして[回数制限に引っかかった場合](https://developer.github.com/v3/#rate-limiting)には，ユーザに次のリクエストが可能になるまでの待ち時間を知らせたいでしょう（あるいはそれまでの長い間，自動的に待機するようにしたくなるかも！）．


<!-- ## Authentication -->
## 認証

<!-- The most common forms of authentication are OAuth and http basic auth: -->
最も一般的な認証方式は OAuth とBasic認証です：

<!-- * OAuth 1.0. Not terribly common any more. See `oauth1.0_token()` for  -->
<!--   details. -->
* OAuth 1.0. もはやそれほど一般的な認証方式ではありません．詳細については`oauth1.0_token()`を見てください．

<!-- * OAuth 2.0. Very common in modern web apps. It involves a round trip between -->
<!--   the client and server to establish if the API client has the authority to -->
<!--   access the data. See `oauth2.0_token()`. It's ok to publish api key and  -->
<!--   "secret" - these are not actually important for security of user data. -->
* OAuth 2.0. モダンなwebアプリケーションでは非常に一般的な認証方式です．APIクライアントがデータにアクセスする権限を確立するために，クライアントとサーバの間でのラウンドトリップを行います．詳細については `oauth2.0_token()` を見てください．ユーザのデータのセキュリティにとって，APIキーと「シークレット」は実は重要ではないので，公開してもかまいません．


<!-- * HTTP basic auth with username and password. This is the least secure -->
<!--   since it requires the most information. -->
* ユーザ名とパスワードによるBasic認証．最も多くの情報を要求するので，いちばんセキュアでない認証方式です．

    
    ```r
    authenticate("username", "password")
    #> <request>
    #> Options:
    #> * httpauth: 1
    #> * userpwd: username:password
    ```

<!-- * HTTP basic auth with API key. An alternative provided by increasing number -->
<!--   of APIs - instead of using a username and password intimately associated -->
<!--   with the users account, you instead use a randomly generated API key that -->
<!--   can be independently deactivated. Often the password is left blank or set -->
<!--   to a prespecified value. -->
* APIキーを用いたBasic認証．ますます多くのAPIによって提供されている代替的な認証方式です．ユーザアカウントと密接に関連しているユーザ名とパスワードを使う代わりに，ランダムに生成されたAPIキーを使用します．APIキーはユーザアカウントとは独立に無効化することができます．多くの場合，パスワードは空欄にするか，あらかじめ指定された値を使用します．

    
    ```r
    authenticate("ddfa3d40d5855d6ba76b7003fd4", "")
    #> <request>
    #> Options:
    #> * httpauth: 1
    #> * userpwd: ddfa3d40d5855d6ba76b7003fd4:
    ```

<!-- You also need some way to preserve user credentials so that they don't need to be re-entered multiple times. If you use OAuth, httr will take care of this for. For other use cases, I recommend using environment variables. The following function retrieves your PAT from an environmental variable called `GITHUB_PAT`, telling you how to set it if not. The devtools package needs to access your github personal access token to install packages from private repos. -->
ユーザクレデンシャルを何回も入力せずに済むように保持しておく方法も必要でしょう．OAuthを使用している場合は，httrが面倒を見てくれます．その他のユースケースの場合は，環境変数を利用することを推奨します．下記の関数はパーソナルアクセストークンを `GITHUB_PAT`という環境変数から取り出します．環境変数が存在しない場合はセットの仕方を教えます．devtoolsパッケージではパッケージをプライベートリポジトリからインストールするためにパーソナルアクセストークンにアクセスする必要があります．


```r
github_pat <- function(force = FALSE) {
  env <- Sys.getenv('GITHUB_PAT')
  if (!identical(env, "") && !force) return(env)

  if (!interactive()) {
    stop("Please set env var GITHUB_PAT to your github personal access token",
      call. = FALSE)
  }

  message("Couldn't find env var GITHUB_PAT. See ?github_pat for more details.")
  message("Please enter your PAT and press enter:")
  pat <- readline(": ")

  if (identical(pat, "")) {
    stop("Github personal access token entry failed", call. = FALSE)
  }

  message("Updating GITHUB_PAT env var to PAT")
  Sys.setenv(GITHUB_PAT = pat)

  pat
}
```

<!-- Encourage your users to store their important information once (see below), rather than typing it into the console - it's easy to accidentally publish your `.Rhistory` and you don't want it to contain private data. -->
読者のパッケージのユーザには，重要な情報はコンソールに打ち込むよりも，一度だけ保存して済ませるように勧めてください．公開したくないデータを含んだ`.Rhistory`をうっかり公開してしまうようなことは容易に起こります．

<!-- ### Vignettes -->
### ビネット

<!-- Including authentication requiring code in your vignettes is challenging, because you don't want to bundle your own credentials with the package! However, you can take advantage of the fact that the vignette is built locally, and only checked by CRAN with this idea from Jenny Bryan: -->
認証が必要なコードをビネットに含めるのはやっかいなことです．読者自身のクレデンシャルをパッケージにバンドルしたくはないでしょうから！とはいえ，Jenny Bryanのアイディアによれば，ビネットはローカルでビルドされて，CRANではチェックされるだけだという事実を利用することができます：

<!-- In an setup chunk, do: -->
セットアップのチャンクで以下のようにしてください：


```r
NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true")
knitr::opts_chunk$set(purl = NOT_CRAN)
```

<!-- And then use `eval = NOT_CRAN` as needed as a chunk option. -->
それから必要な箇所のチャンクオプションで`eval = NOT_CRAN`としてください．

<!-- ## Appendix: API key best practices -->
## 付録：APIキーのベストプラクティス

<!-- If your package supports an authentication workflow based on an API key or token, encourage users to store it in an environment variable. We illustrate this using the [`github` R package](https://github.com/cscheid/rgithub), which wraps the Github v3 API. Tailor this template to your API + package and include in `README.md` or a vignette. -->
読者のパッケージがAPIキーかトークンに基づく認証をサポートしている場合には，ユーザにはキーやトークンを環境変数に保存するよう勧めてください．Githubのバージョン3のAPIのラッパーである[`rgithub`](https://github.com/cscheid/rgithub) を例にとって説明しますので，このテンプレートを読者のAPIとパッケージに合うように変更して，`README.md`やビネットに含めるようにしてください．


<!-- 1.  Create a personal access token in the  -->
<!--     [Personal access tokens area](https://github.com/settings/tokens) of your -->
<!--     GitHub personal settings. Copy token to the clipboard. -->
<!-- 1.  Identify your home directory. Not sure? Enter `normalizePath("~/")` in  -->
<!--     the R console. -->
<!-- 1.  Create a new text file. If in RStudio, do *File > New File > Text file.* -->
<!-- 1.  Create a line like this: -->
<!--     ```bash -->
<!--     GITHUB_PAT=blahblahblahblahblahblah -->
<!--     ``` -->
<!--     where the name `GITHUB_PAT` reminds you which API this is for and  -->
<!--     `blahblahblahblahblahblah` is your personal access token, pasted from the clipboard. -->
<!-- 1.  Make sure the last line in the file is empty (if it isn't R will  -->
<!--     __silently__ fail to load the file. If you're using an editor that shows  -->
<!--     line numbers, there should be two lines, where the second one is empty. -->
<!-- 1.  Save in your home directory with the filename `.Renviron`. If questioned,  -->
<!--     YES you do want to use a filename that begins with a dot `.`. -->

<!--     Note that by default [dotfiles](http://linux.about.com/cs/linux101/g/dot_file.htm)  -->
<!--     are usually hidden. But within RStudio, the file browser will make  -->
<!--     `.Renviron` visible and therefore easy to edit in the future. -->
<!-- 1.  Restart R. `.Renviron` is processed only  -->
<!--     [at the start of an R session](http://stat.ethz.ch/R-manual/R-patched/library/base/html/Startup.html). -->
<!-- 1.  Use `Sys.getenv()` to access your token. For example, here's how to use  -->
<!--     your `GITHUB_PAT` with the `github` package: -->

<!--     ```R -->
<!--     library(github) -->
<!--     ctx <- create.github.context(access_token = Sys.getenv("GITHUB_PAT")) -->
<!--     # ... proceed to use other package functions to open issues, etc. -->
<!--     ``` -->
  
1. githubの設定の[Personal access tokens area](https://github.com/settings/tokens)でパーソナルアクセストークンを作成して，トークンをクリップボードにコピーしてください．

2. ホームディレクトリをを特定してください．分からない場合はRコンソールで`normalizePath("~/")`と打ち込んでください．
  
3. 新しいテキストファイルを作成してください．RStudioを使っている場合は *File > New File > Text file* を選択すればよいです．
   
4. 以下のような行を作成してください：

    ```bash
    GITHUB_PAT=blahblahblahblahblahblah
    ```
    `GITHUB_PAT`は，このAPIがどのサイトのものか思い出させるものです．`blahblahblahblahblahblah`にはクリップボードにあるパーソナルアクセストークンを貼り付けます．
        
5. ファイルの最終行が空行になっていることを確かめてください（そうなっていない場合，Rは_無言で_ファイルのロードに失敗します．行番号が表示されるエディタを使っている場合は，ファイルには2行存在して，2行目は空になっているべきです．）

6. このファイルをホームディレクトリに`.Renviron`という名前で保存してください．ドット`.`で始まるファイルを使用したいのかと質問された場合は，YESとしてください．

    ふつうデフォルトでは[ドットファイル](http://linux.about.com/cs/linux101/g/dot_file.htm)は隠しファイルになっていますが，RStudioのファイルブラウザでは`.Renviron`が表示されるので，あとで編集し直すのも簡単です．

7. Rを再起動してください．`.Renviron`ファイルは[R セッションの最初に](http://stat.ethz.ch/R-manual/R-patched/library/base/html/Startup.html)のみ処理されます.
  
8. トークンにアクセスするには`Sys.getenv()`を使ってください．たとえば，`GITHUB_PAT`を`rgithub`パッケージで使うには以下のようにします：

    ```R
    library(rgithub)
    ctx <- create.github.context(access_token = Sys.getenv("GITHUB_PAT"))
    # 他のパッケージ関数を使ってイシューを開いたりしてみてください．
    ```
<!-- FAQ: Why define this environment variable via `.Renviron` instead of in `.bash_profile` or `.bashrc`? -->

FAQ: どうして`.bash_profile`や`.bashrc`ではなく`.Renviron`で環境変数を定義するのでしょうか？

<!-- Because there are many combinations of OS and ways of running R where the `.Renviron` approach "just works" and the bash stuff does not. When R is a child process of, say, Emacs or RStudio, you can't always count on environment variables being passed to R. Put them in an R-specific start-up file and save yourself some grief. -->
多くのOSとR実行環境の組み合わせにおいて， `.Renviron` を使う方法はとりあえず上手く動きますが，bash関連のファイルではそう上手くはいかないからです．たとえばRがEmacsやRStudioの子プロセスである場合には，環境変数がRに渡されることが常に期待できるわけではありません．R専用のスタートアップファイルに環境変数を書いておくことで苦労が省けるのです．