Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Multi-Page {shiny} apps with {brochure}

Colin Fay
February 16, 2022

Building Multi-Page {shiny} apps with {brochure}

NHS-R / 2022-02-16

Colin Fay

February 16, 2022
Tweet

More Decks by Colin Fay

Other Decks in Technology

Transcript

  1. BUILDING MULTI-PAGE {SHINY} APPS WITH {BROCHURE} NHS-R / 2022-02-16 COLIN

    FAY
  2. > whoami Colin FAY - Data Science Engineering & R-Hacker

    at ThinkR. Hyperactive open source developer, lead developer of the {golem} project, author of the Engineering Production Grade Shiny Apps book. https://rtask.thinkr.fr https://twitter.com/_colinfay https://github.com/colinfay https://colinfay.me Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 2 / 23
  3. Data Science engineering, focused on R  Training  Software

    Engineering  R in production  Consulting Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 3 / 23
  4. BUILDING MULTI-PAGE {SHINY} APPS WITH {BROCHURE}

  5. Multiple Page Shiny Apps with {brochure} Colin FAY (@_ColinFay) -

    https://rtask.thinkr.fr 5 / 23
  6. I know what you're thinking 🤔 Colin FAY (@_ColinFay) -

    https://rtask.thinkr.fr 6 / 23
  7. YASE (Yet Another Shiny Extension) Colin FAY (@_ColinFay) - https://rtask.thinkr.fr

    7 / 23
  8. Ok let me explain 🗣 Colin FAY (@_ColinFay) - https://rtask.thinkr.fr

    8 / 23
  9. (Because yes, there's a rational explaination) Colin FAY (@_ColinFay) -

    https://rtask.thinkr.fr 9 / 23
  10. 10(*) types of webapps Multi-page apps The "traditionnal" way of

    building content on the web. Each time you move from one page to another, the whole content is reloaded. This is how most websites work. Single page apps More "modern" way to build apps. The HTML/CSS/JS is uploaded one time, and its content is updated via JavaScript requests to the server. This is how {shiny} works. (*) Sorry for everyone not getting the joke, I just read a book about binary numbers and wanted to sound smart. Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 10 / 23
  11. What's wrong with the way {shiny} works? Nothing, but let's

    take a step back What do I need when I build a web app? Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 11 / 23
  12. What do I need when building a web app ?

     Multiple paths (real ones): /, /analysis, /results, /contact...  Not load the whole app everytime  Cookies  Healtcheck  HTTP method support (POST, PUT, DELETE, etc.)  HTTP code support (200, 300, 400...)  Tweak http requests and responses And many others things Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 12 / 23
  13. But why would I want that? Serving static, pure HTML

    landing pages Being able to point to specific part of the app (not 'open the app, click there and there and see') Lower the load on the server by serving static HTML elements Monitor your app via healthcheck Identify the user when they come back to the app POST elements to the server Add a 404 page for unreachable pages Redirect pages to others Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 13 / 23
  14. HERE COMES {BROCHURE}!

  15. Previous works {blaze} https://github.com/nteetor/blaze {shiny.router} https://github.com/Appsilon/shiny.router => Not really multi-page,

    but "hack" your browser path by using URL fragments A Fragment URL Specifies A Location Within A Page Url fragments create history in your browser but don't reload the full page Are not sent as part of the http request (so it can be harder to log what's happening in the app) => Don't have all the features from the last slide Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 15 / 23
  16. Basic brochure library(shiny) library(brochure) brochureApp( page( href = "/", ui

    = fluidPage( plotOutput("plot") ), server = function(input, output, session) { output$plot <- renderPlot({ plot(iris) }) } ), page( href = "/page2", ui = fluidPage( h1("This is my second page") ) ) ) Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 16 / 23
  17. About HTTP

  18. log_where <- function(req) { cli::cat_rule( sprintf( "%s - %s", Sys.time(),

    req$PATH_INFO ) ) req } brochureApp( req_handlers = list( log_where ) ) Cookies, request and response handlers Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 18 / 23
  19. Cookies, request and response handlers login <- function() { page(

    href = "/login", ui = tagList( h1("You've just logged!") ), server = function(input, output, session) { }, res_handlers = list( ~ set_cookie(.x, "BROCHURECOOKIE", 12) ) ) } Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 19 / 23
  20. brochureApp( # Pages page_1(), page_2(), page_contact(), page( href = "/check",

    ui = tagList(), # This req_handler will returns # an httpResponse, it will be # returned directly to the browser req_handlers = list( # Exported since shiny 1.6.0 ~ shiny::httpResponse( 200, content = "OK" ) ) ) ) > httr::GET('http://url/check') Response [http://url/check] Date: 2022-02-16 12:19 Status: 200 Content-Type: text/html; charset=UTF-8 Size: 2 B Simple healthcheck Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 20 / 23
  21. Demo time Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 21 / 23

  22. 📖 engineering-shiny.org/ Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 22 / 23

  23. Thx! Questions? Find me Online colin@thinkr.fr https://twitter.com/_colinfay https://twitter.com/thinkr_fr https://github.com/ColinFay https://thinkr.fr/

    https://rtask.thinkr.fr/ https://colinfay.me/ Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 23 / 23