Parse raw JSON

Jul 29, 2024·
Kennedy Mwavu
Kennedy Mwavu
· 2 min read

TL;DR: See the parser.

Sometimes you need to parse requests which have raw JSON in the body.

ambiorix::parse_multipart() only works for ‘form-data’. But Ambiorix does not limit you to that. You can write your own request parsers or make use of other packages. In this case, we’ll use webutils::parse_http().

Example

Say we want to select columns and filter rows in the iris dataset when the request body is a JSON object like this:

{
    "cols": ["Sepal.Length", "Petal.Width", "Species"],
    "species": ["virginica", "setosa"]
}

Parser

Let’s write the parser:

box::use(
  webutils[parse_http],
)

#' Parse HTTP request
#'
#' @description
#' Parses the body of an HTTP request based on the `Content-Type` of the
#' request header.
#' @details
#' Currently supports three most common types:
#' - application/x-www-form-urlencoded
#' - multipart/form-data
#' - application/json
#' @param req Request object.
#' @return Named list. Data associated with the request.
#' @export
parse_req <- \(req) {
  parse_http(
    body = req$rook.input$read(),
    content_type = req$CONTENT_TYPE
  )
}

With this, you can parse requests inside your handlers like so:

req_data <- parse_req(req)

Reprex

Here’s a full reprex:

box::use(
  ambiorix[Ambiorix],
  webutils[parse_http],
)

#' Handle POST at '/'
#'
#' @param req Request object.
#' @param res Response object.
#' @return `res$json()`
#' @export
home_post <- \(req, res) {
  content_type <- req$CONTENT_TYPE
  body <- req$rook.input$read()

  if (length(body) == 0L) {
    response <- list(
      code = 400L,
      msg = "Invalid request"
    )

    return(
      res$set_status(400L)$json(response)
    )
  }

  postdata <- parse_http(body, content_type)

  # filter & select as necessary:
  row_inds <- iris$Species %in% postdata$species
  col_inds <- colnames(iris) %in% postdata$cols
  data <- iris[row_inds, col_inds, drop = FALSE]

  response <- list(
    code = 200L,
    msg = "success",
    data = data
  )

  res$json(response)
}

app <- Ambiorix$new(port = 3000, host = "127.0.0.1")

app$
  post("/", home_post)$
  start()
Kennedy Mwavu
Authors
Software Developer
I write R for fun & profit.