ð§Rã§REST APIãäœãïŒplumberç·šïŒ
æ§ã ãªAPIãå©çšããŠãããšã次第ã«èªåã§ãAPIãäœããããªããŸãããïŒ Rã®é¢æ°ãå©çšããŠHTTPçµç±ã§ããŒã¿ã®åãæž¡ããã§ãããšå¬ããã§ããããå ããŠãRã®äœå³æ©èœã䜿ã£ãŠãAPIãå©ãã ãã§äœå³ããŠããããšè¶ ããããŒã§ãããã
å眮ããäœããªãåçªã§ããã{plumber}
ããã±ãŒãžã䜿ã£ãŠãæ軜ã«Rã§APIãµãŒããŒãæ§ç¯ã§ãããšããšãã話ã§ãã{plumber}
ã¯ãŸã CRANã«ç»é²ãããŠããªãã®ã§ãå©çšããéã«ã¯GitHubããéçºçãã€ã³ã¹ããŒã«ããŠããŠãã ããã
ð€Rã§APIãµãŒããŒ?
ãRã§APIãµãŒããŒãäœãããšãã話èªäœã¯æšå¹Žæ«ã®Japan.Rã§ãŽãç®±ããã話ãããŠããã®ã§ãããéå¶åŽã ã£ãããšããã£ãŠãã£ãããšèããŠããŸããã§ããïŒãã®èšäºãæžãããšããŠãããããã°ãŽãç®±ãããRã§APIãäœããã¿ãããªè©±ããŠããããªãšããã®ãæãåºããïŒããŽãç®±ããã®è©±ã®äžã§ã{plumber}
ã«ã€ããŠèšåããŠããŸãã
äœãã§ããã®ïŒ
ãã£ãããšèª¬æãããšRã³ãŒãã®åŠçãURLçµç±ã§ååŸã»è¡šç€ºããããšãå¯èœã«ãªããŸããã©ããã§APIãµãŒããŒãšããŠRã³ãŒããå®è¡ããŠããã°ãURLã«ã¢ã¯ã»ã¹ããã ãã§çµæãåŸããããããšãã§ããŸãã
Rã®æŒç®èœåãçµ±èšåŠçã®çµæããŠã§ããã©ãŠã¶ã§ã¿ãããããããã衚瀺ãããã§ããŸããåºç€ã«ãªãã®ã¯Rã®ã³ãŒããªã®ã§ããã©ã¡ãŒã¿ãå®çŸ©ããŠããããšã§å©çšè ã®çšéã«å¿ããåºåãå¯èœã«ãªããªããŠçŽ æµã ãšæããŸãããã
ãšããããã§ãã£ãŠã¿ãŸãããã
{plumber}
ããã±ãŒãžã®å©ç¹ã¯ãæ¢åã®Rã³ãŒãã«æãã€ããAPIåã§ããç¹ã«ãããŸãã
hw <- function() { return("Hello world!") } hw()
Rã§ãã®é¢æ°ãå®è¡ãããšã³ã³ãœãŒã«ã«'Hello world!'ãåºåãããŸããããŸãã¯ãã®é¢æ°ãAPIåããŠã¿ãŸãããã次ã®ã³ãŒããé©åœãªååã§ä¿åããŸããããããã§ã¯first_api.R
ãšããŸãã
#* @get /hello hw <- function() { return("Hello world!") }
é¢æ°plumb()
ã«ãã£ãŠãå
ã»ã©ã®first_api.R
ãèªã¿èŸŒã¿ãŸããå®è¡çµæã¯é©åœãªååã®ãªããžã§ã¯ãã«ä¿åããŠãããŸãããã
# devtools::install_github('trestletech/plumber') library(plumber)
r <- plumb("first_api.R")
plumb()
é¢æ°ã®å®è¡çµæã¯R6ã¯ã©ã¹ã¡ãœããã«ãã£ãŠå®è£
ãããplumberã¯ã©ã¹ãªããžã§ã¯ãã§ãããããããªèŠçŽ ããã£ãŠããŸãããã²ãšãŸã眮ããŠãããŠAPIãå©ããŸãããã
r %>% { class(.) %>% print() names(.) }
## [1] "plumber" "R6"
## [1] ".__enclos_env__" "debug" "filters"
## [4] "endpoints" "clone" "run"
## [7] "route" "serve" "addGlobalProcessor"
## [10] "setSerializer" "addFilter" "set404Handler"
## [13] "setErrorHandler" "addAssets" "addEndpoint"
## [16] "onWSOpen" "onHeaders" "call"
## [19] "initialize"
portåŒæ°ã§ããŒãçªå·ãæå®ãå®è¡ããŸãã
r$run(port = 8000) # Starting server to listen on port 8000
ãã®ç¶æ
ã§ãã©ãŠã¶ãèµ·åããhttp://localhost:8000/hello
ã«ã¢ã¯ã»ã¹ãããcurl 'http://localhost:8000/operation'
ãå®è¡ããŸããããRã®ã³ã³ãœãŒã«ã§åŸãããããã«"Hello world!"ã衚瀺ãããŸãããïŒãã®APIã§ã¯è¡šç€ºãããã¡ãã»ãŒãžãåºå®ãããŠããã®ã§ã次ã®äŸã§ã¯ãã©ã¡ãŒã¿ã«ãã£ãŠå®è¡çµæãå€åãããŠã¿ãŸãããã
å®è¡äžã®åŠçãäžæããå
ã»ã©ã®first_api.R
ã«æ¬¡ã®ã³ãŒããè¿œå ããŸãã
#* @get /operation operation <- function(a, b) { as.numeric(a) + as.numeric(b) }
ãã®é¢æ°ã¯aãšbãšããïŒã€ã®åŒæ°ãæã€ãããããç°¡åãªé¢æ°ã§ããRã§å®è¡ãããšä»¥äžã®çµæãè¿ããŸãã
operation(a = 1, b = 4)
## [1] 5
å
ã»ã©ãšåæ§ããŒã«ã«ãã¹ããžã¢ã¯ã»ã¹ããŸãããä»åºŠã¯é¢æ°ã®å®çŸ©ã«åŒæ°ãæå®ããã®ã§ãURLã«ãã®åŒæ°ã®å€ã«ã€ããŠããã©ã¡ãŒã¿ãšããŠæå®ããå¿
èŠããããŸãããã©ã¡ãŒã¿ã¯ãšã³ããã€ã³ãã®åŸã«?
ãã€ããŠãparameter=A
ã®ãããªåœ¢ã§æå®ããŸãããããã©ã¡ãŒã¿ãè€æ°ããå Žåã«ã¯&
ã䜿ããŸããRã§å®è¡ããçµæãšåãå€ãåŸãã«ã¯http://localhost:8000/operation?a=1&b=4
ãšãªããŸãããã£ãããªã®ã§ä»åºŠã¯çµæãRã§åãåããŸããããçŸåšå®è¡äžã®Rãšã¯å¥ã«æ°ãã«Rãèµ·åãã次ã®ã³ãŒããå®è¡ããŸãã
plumb("160312_api_with_prlumber/first_api.R") %$% run(port = 8000)
library(httr) GET("http://localhost:8000/operation?a=1&b=4") %>% content() # [[1]] # [1] 5
ð·{plumber}
ã®äœ¿ãæ¹
å
ã®äŸã§èŠãããã«{plumber}
ã§ã¯APIãšããŠæ©èœãããRãã¡ã€ã«ãšplumb()
é¢æ°ã®å®è¡ã«ããåäœããŸãã{plumber}
ããã±ãŒãžãå©çšããéã®å€§ããªå©ç¹ãšããŠãæ¢åã®Rã³ãŒãã«ã¯æãã€ããã«APIåã§ããç¹ããããplumb()
ãå®è¡ããã ãã§ãæ軜ã«APIãµãŒããŒãçšæã§ããããšã«ãªããŸãã
first_api.R
ã®äžèº«ãæ¹ããŠèŠãŠã¿ãŸãã
#* @get /hello hw <- function() { return("Hello world!") } #* @post /operation operation <- function(a, b) { as.numeric(a) + as.numeric(b) }
Rã³ãŒãã®åã«å®£èšãã#* @get /hello
ã®éšåã{plumber}
ã§ã¯éèŠã«ãªã£ãŠããŸãã@get
ãšããã®ã¯ããã®APIãGETã¡ãœããã§åŒã³åºãããããšãæå®ããŠããã/hello
ã®éšåãæäŸãããAPIã®çš®é¡ã決ãããšã³ããã€ã³ããšãªããŸãããšã³ããã€ã³ãã¯http://localhost:8000/hello
ã®ããã«äžããããŸãããã®ãšã³ããã€ã³ãã®å®çŸ©ã¯#'
ãš#*
ã§ã§ããŸããã#'
ã®æ¹ã¯Rããã±ãŒãžäœæã®éã«å©çšãããRoxygenã®ãã®ãšæ··åããã®ã§é¿ããã»ããè¯ãã§ãã
ãã¡ãããGET以å€ã®POSTãPUTãšãã£ãhttpã¡ãœãããå©çšã§ããŸãã
å©çšäŸ
{plumber}
ã䜿ãã°Rã䜿ã£ãŠäœå³ãããã®ãURLããŒã¹ã§ååŸãããããµãŒããŒãšããŠæ©èœãããã³ã³ãã¥ãŒã¿ã«ä¿åãããŠãããã¡ã€ã«ã®å€ãèªã¿èŸŒããšãã£ãããšãå¯èœã§ãã
ã«ãŒãã£ã³ã°ã®æå®
ãã©ã¡ãŒã¿æ°ãå€ãããããªãããšãã£ãæã«ã¯ã«ãŒãã£ã³ã°ãèšå®ãããšè¯ãã§ãããã
#* @get /iris/<sp>/<n:int> function(n, sp) { iris %>% dplyr::filter(Species == sp) %>% .[as.integer(n), ] }
library(httr) GET("http://localhost:8000", path = "iris/setosa/3") %>% content() # [[1]] # [[1]]$Sepal.Length # [1] 4.7 # # [[1]]$Sepal.Width # [1] 3.2 # # [[1]]$Petal.Length # [1] 1.3 # # [[1]]$Petal.Width # [1] 0.2 # # [[1]]$Species # [1] "setosa"
ç»åã®æç»
ããããã®çµæãAPIãšããŠæšæ¥åŽããã«ã¯@png
ãšããç¹æ®ãªãšã³ããã€ã³ããæå®ããŸããåŒæ°ãçšæããŠãããšå©çšè
ãä»»æã®å€ãæå®ã§ããã®ã§å®çšçã§ããã
#* @get /ggp2dens #* @png ggp2dens <- function(seed = rnorm(1), fill.colour = "tomato", alpha = 1) { library(ggplot2) set.seed(seed) p <- data.frame(x = rnorm(100)) %>% ggplot(aes(x)) + geom_density(fill = fill.colour, alpha = alpha) print(p) }
# çŽæ¥ãç»åãã¡ã€ã«ãããŠã³ããŒã download.file(url = "http://localhost:8000/ggp2dens?seed=71&fill.colour=forestgreen", destfile = "res_plot.png") # äœå³é åã«ãããã plot(0:1, 0:1, type = "n") GET("http://localhost:8000/ggp2dens?seed=71&fill.colour=tomato&alpha=0.5") %>% content() %>% rasterImage(0, 0, 1, 1)
HTTPãã¡ã€ã«ã«åã蟌ã
JavaScriptã䜿ã£ãŠãset.seed()
ã®å€ãå©çšè
ã®ã¢ã¯ã·ã§ã³ã«ãã£ãŠå¡ãã€ã¶ãã®è²ãå€æŽããŸãã
ãããªã©ãã
é¢æ°ãäœæããæã«ã¯ãããã€ã泚æãå¿ èŠã§ãã
- ãã©ã¡ãŒã¿ã¯åºæ¬çã«æååãšããŠæ±ãããã®ã§ãæ°å€ãæž¡ãéã«ã¯
as.numeric()
ãas.integer()
ã®æå®ãããŠãã {ggplot2}
ã®ããããã«ã¯print()
ã䜿ããªããŠã¯ãããªã- é¢æ°å ã§åŒæ°ã®å€ãå¥ã®é¢æ°ã«åŒãæž¡ãããã®...åŒæ°ã¯å©çšã§ããªã
ãããã¯ãã¡ãªäŸã§ãã
#* @post /operation operation <- function(a, b) { a + b } #* @get /ggp2dens #* @png ggp2dens <- function(seed = rnorm(1), ...) { library(ggplot2) set.seed(seed) ggplot(data.frame(x = rnorm(100)), aes(x)) + geom_density(...) }
ä»åã¯{plumber}
ã®çŽ¹ä»ãšããããç°¡åãªäŸã ãã«ãªã£ãŠããŸããŸãããã{plumber}
ã®å©çšäŸ¡å€ã¯ãã£ãšå€ãã¯ãã§ãã
{plumber}
ããã±ãŒãžã®è¯ããšããããŸãšãããš
- æ¢åã®Rã³ãŒããç°¡åã«APIãšããŠå©çšã§ãã
- Rã®åŒ·åãªæ©èœïŒçµ±èšãäœå³ïŒãAPIãšããŠäœ¿çšã§ããã
- Shinyãšçµã¿åãããŠãŠã§ãã¢ããªãäœãããïŒLondonRã®è³æã§ã¯Shinyã䜿ã£ãŠããïŒ
ãšããæãã§ããããã
ãã詳ããåŠã³ãã人ã¯ïŒæã«LondonRã§çºè¡šãããè³æ(zipãã¡ã€ã«)ãã³ãŒãä»ãã§åèã«ãªããŸãã