Rでweb APIを提供するパッケージ「plumber-入門」【HTTP,API】



#はじめに

分析ばかりで開発になかなか関われないので自主練。
間違いあればコメント是非。


#Rでweb APIやて？

・Rで分析した結果を他人が確認できるように表示する
・誰でも簡単なインプットができてアウトプットされる仕組みが欲しい
・機械学習モデルを社内のだれでも活用できるようにしたい

そんな時に役立つのが「plumber」というパッケージ。
webアプリを作ってしまう「shiny」パッケージも過去に紹介しているので、サーバー立てられてデザインもある程度簡単に実現させたい人はこちらへどうぞ。
[Rでshiny レイアウトについてメモ](https://qiita.com/Ringa_hyj/items/9d3716c564dfe8a35d5e)


#plumberとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/6c6ba1ad-74fb-283e-14de-dc1195b02dee.png)


日本語に訳すなら「配管」
・機械学習モデルをRを使わない人でも活用してもらうため、機能として提供する。
・モデルを定期的なバッチ処理を裏で動かし、その結果をデータベースで共有して必要な人に取得してもらう。
どちらも便利ではない。

plumberはローカルPC上を仮想的なサーバーとして扱い、その中身でRが動いているような挙動をする。
Rとの通信はHTTP通信を使用して行う。
通信はURLのアドレスを使って行うことができるため、機械学習モデルのパラメタや、入力したいデータ,数値をURLとして書き込むことで、R内の関数が実行される。
そのため、スクリプトを書いて実行、変数を書き換えて実行などRを知っていなければできない操作が必要ない。

APIを通してRの実行が可能になれば、Rと画面アプリを別で開発し結び付けることなども可能になる。
ユーザーからヘタなスクレイピングやクエリ実行を行われ、アクセス負荷につながり運営が苦しくなるよりも、社内で走りやすいスクリプトを作っておいて、
ユーザーが項目を選択するだけで負荷の低いクエリが走り、データが抽出される。
という機能提供もできるようになります。


※API：Application Programming Interface

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/2cb354db-a2c5-6f1a-13c2-c030c00165b4.png)


[Red hat：API とは](https://www.redhat.com/ja/topics/api/what-are-application-programming-interfaces)




#HTTP？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/0d879229-2117-093f-bede-9e7fd5896f15.png)
[「HTTPリクエスト」と「HTTPレスポンス」](https://chopesu.com/programing/http/)

悩むより動かしてみたほうが早いと思うので言葉だけ先に紹介。
plumberの機能を実行したとき、webブラウザで立ち上がる画面を操作する自分がユーザーであり、
ユーザーの持っている端末(PC)がクライアントと呼ばれる。
クライアントから「HTTP」という通信方式で入力情報が「サーバ」に送られる。
(URLのような情報)

例：ピザのネット予約などはweb画面に入力した情報が、ネットワークを通して「ピザ屋の契約している予約管理サーバ」へ送られる。

今回の記事ではネットワークでつなぐとかは行わず、自分のPC内で「サーバー」も「web画面」も「クライアントからの操作情報」も試してみる。
(社内で公開する時には公開用のwindowsサーバーでも立ててネットワークを作る必要アリ。もしくはクラウドサービスなどので動的に返答を返してくれるサーバを借りてRを設置しplumberを実行しておく。)


#plumberでサーバー内のR処理を実行

plumberの使い方として、処理したいアルゴリズムを関数にして記述し、Rファイルとします。
このRファイル内の関数をRで実行させるためにURL(URI)アドレスを使います。
処理したい関数の場所を「[エンドポイント](http://e-words.jp/w/%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88.html)」と呼び、plumberはこのエンドポイントを簡単に作ってくれる機能を持っているわけです。


通常のRファイルと異なる点は、API画面を作るため、plumberの認識するコメント形式での記述を行う必要があります。



#Rファイルを作り実行


以下の記述を丸々コピーして、任意のフォルダに「plumber.r」というRファイルで保存します。
私はdesktopのtestフォルダ内に作りました。

```r
#* @apiTitle ぼくの画面
#* @apiDescription とりあえず作って理解
#* @apiVersion 未来ガジェットver 0.0.11

#* @get /plot
#* Plotをしたい
#* @param spec 種子の名前を入れて(setosa,versicolor,virginica)
#* @serializer png

function(spec){
  myData <- iris
  title <- "All Species"

  if (!missing(spec)){
    title <- paste0("Only the '", spec, "' Species")
    myData <- subset(iris, Species == spec)
  }

  p<-myData %>% ggplot(aes(x=Sepal.Length, y=Petal.Length)) + 
  geom_point()+
  labs(title=title)

  print(p)

}

```



Rを開き、以下コマンドを実行します。

```r
library(tidyverse)
library(plumber)

pr("C:\\Users\\ringa\\Desktop\\test\\plumber.r") %>% pr_run(port=8080)
```

これでもOK

```
plumber::plumb(".....\\plumber.r")$run(port = 8080)
```

すると


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/44e2a59e-1350-579a-0eaf-c576ecb8418d.png)

がconsoleに記述され、ホップアップで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/b17a7483-8269-17df-3227-fdd6647a949b.png)


こんなAPI画面が表示されていると思います。(表示されていなければconsolのアドレスをブラウザにコピペ)

plumber.rで記述したいくつかのコメントが反映されています。



getボタン > try out >　message入力 > 実行

の操作を行うと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/864555d0-0ff8-f63c-8628-b6dc6bdd3482.png)



API画面に入力した情報がリクエストとしてRに渡り、Rで処理され、リアルタイムに画面に反映されました。
この画面の

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/a9993fb4-c724-a351-05dc-6dba2546744e.png)

request URLをブラウザで開いてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/c3e6e8ab-4603-ae17-d19b-8b374ecbb427.png)


結果を**「webブラウザで表示」**することができました。

##URIでサーバーに改めて処理を実行させる

このURLの末尾に「plot?spec=setosa]」とついています。

plumberは「@get /plot」という名前に対して「ggplotで散布図を描く機能」として認識しています。
つまり機能の位置を「ローカルアドレス+plot」という記述でアクセスできるようにしてくれています。
そして、関数に渡したいパラメタを「?」を付けた後に渡すことで、サーバ側のRでの処理実行時に引数に代入してくれるわけです。

よりHTTPリクエストやメソッドの関係が知りたければこちらへ。
[ HTTP【 HyperText Transfer Protocol 】](http://e-words.jp/w/HTTP.html)



試しににAPI画面でなく、「ブラウザのURL上で」パラメタであるsetosaをvirginicaに変えてみると？





![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/0bd837b8-630d-fafe-50c5-d67989918c30.png)


変更されて、処理結果がリアルタイムで返ってきました。

ここまでの内容で、
**APIがアドレス形式で「パラメタを入力」することでRスクリプトを知らずにRの処理が実行できる。**
というメリットを感じていただけたかと思います。(いただけてる？)


もう少しチョコチョコと機能を紹介して終わりにします


#機能紹介:plot,hist



plumber.rに追記していくことを想定して記述していきます。

```r
#* ヒストグラムをかく
#* @get /histplot
#* @serializer png
function(seed = 1) {
    set.seed(seed)
    hist(rnorm(100))
}
```

ggplotはprintで表示させましたが、plotやhitsはそのままでも表示できます


#機能紹介:足し算を実行

```r

#* 足し算した結果をjsonに
#* @param a 一つ目の数字
#* @param b 二つ目の数字
#* @post /sum
function(a, b) {
  as.numeric(a) + as.numeric(b)
}

```



#機能紹介:html出力をさせる



```r

#* htmlファイルを出力。ブラウザで開くと?
#* @get /hello_html
#* @serializer html
function(){
  "<html><h1>hello world</h1></html>"
}

```

request URLである

```
http://127.0.0.1:8080/hello_html
```

をブラウザで開くと、ブラウザはhtmlファイルを認識できるので


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/f92dc351-0271-25ff-0eb7-3712a5b82c68.png)

htmlでのwebページが表示される。
パラメタを渡すように設計してやればhtmlでブラウザ画面も動的に変更させることが可能になる。

API画面はhtmlファイルを開くわけでなく、htmlスクリプトを表示させるだけ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/89dba853-31a9-f44f-2304-ffe06b538fc3.png)

ダウンロードボタンを押してもテキストファイルでしかない。


#機能紹介:htmlをファイルとしてダウンロード

先ほどテキスト形式だったが、表示したいわけでなく、htmlファイルとしてレポートをDLしたい場合などもあるだろう。
その場合にはR側でas_attachment()を使う。


```r
#* html形式でDLする
#* @get /hello_html_DL
#* @serializer html
function(){
  aas<-"<html><h1>hello world</h1></html>"
  as_attachment(aas,"hellow2.html")
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/ae7bc018-4df5-475f-a60f-e84a3d41c12b.png)




#機能紹介:処理結果をcsvでDL



```r
#* csv形式でDLする
#* @get /save_csv
#* @serializer csv
function(){
  as_attachment(iris,"iris2.csv")
}
```


csvでのダウンロードも可能になります。


#機能紹介:ローカルのcsvを読み込む



```r
#* csv形式を読み込む
#* @get /readdata
function(){
  read_data <- read_csv("iris.csv")
}
```



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/adfe9608-8add-75f2-1b37-5855f5ad0741.png)


最初にplumberから指定したtestフォルダが作業用フォルダとなっています。
バッチ処理でここにcsvが保存されるようにしておけば、現状のデータの状態などが確認できるようになります。



#機能紹介:学習済みモデルを読み込んで実行


システムの中で機械学習モデルだけ入れ替えられるようにすることができます。
現行のがダメになったら置き換えましょう。
Rでは作ったモデルをsave()で「.Rda」ファイルに出力できます。
csvを読み込んだのと同じ要領でload()によって「.Rda」を読み込めば、
predict()に渡すことができます。
あとはパラメタで入力を定義してやるだけです。

スクリプトではなく、簡単にイメージだけ記入しておきます。

```
model <- svm(y~x)
save(model,"model.Rda")
```

保存したmodelを

```
function(x){
  load("model.Rda")
  predict(model,x)
}
```

で予測出力を確認することができる。




#参考

[第1回 APIの概要とデータの取得](https://app.codegrid.net/entry/2018-web-api-1)
[plumber](https://www.rplumber.io/)
[REST APIs and Plumber](https://rviews.rstudio.com/2018/07/23/rest-apis-and-plumber/)
[plumberとshinyを使ってマイクロサービスを作ってみた](https://techblog.nhn-techorus.com/archives/13164)
[rstudio/plumber](https://github.com/rstudio/plumber)
[Web API: The Good Parts](https://www.amazon.co.jp/Web-API-Parts-%E6%B0%B4%E9%87%8E-%E8%B2%B4%E6%98%8E/dp/4873116864)