Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create GeoJSON serializer #830

Merged
merged 11 commits into from Sep 28, 2021
Merged

Create GeoJSON serializer #830

merged 11 commits into from Sep 28, 2021

Conversation

JosiahParry
Copy link
Contributor

@JosiahParry JosiahParry commented Sep 22, 2021

Pull Request

This pull requests implements a geojson serializer. The serializer utilizes geojsonsf. The serializer only supports objects of class sf and sfc.

Please note that devtools::check() fails due to hookable.R#3 and it cannot find the namespace. As such I cannot provide check results without fiddling with code that is not mine.

No code was modified, only added. As such there should be no breaking features or breaking backwards compatibility.


At present, the only way to provide geojson—that I am aware of—via plumber API is to utilize sf to write to a temporary file. read that tempfile via readLines() and use a cat serializer to return the exact json that was written by sf. This serializer removes the need to create hacky solutions for those who would like to return geojson from a plumber API.

library(sf)
library(plumber)

nc <- st_read(system.file("shape/nc.shp", package="sf"))

#* @apiTitle GeoJSON serializer

#* Test sfc object
#* @param id The row ID to print. Must be between 1 - 100.
#* @get /sfc
#* @serializer geojson
function(id = "") {
  nc[["geometry"]][as.integer(id)]
}

#* Test sf object
#* @param id The row ID to print. Must be between 1 - 100.
#* @get /sf
#* @serializer geojson
function(id = "") {
  nc[as.integer(id),]
}

#* Test parsing of geojson
#* @parser geojson
#* @post /parse
function(req, res) {
  st_coordinates(req$body)
}

PR task list:

  • Update NEWS
  • Add tests
  • Update documentation with devtools::document()

@CLAassistant
Copy link

CLAassistant commented Sep 22, 2021

CLA assistant check
All committers have signed the CLA.

@JosiahParry JosiahParry changed the title Create GeoJSON Create GeoJSON serializer Sep 22, 2021
@meztez
Copy link
Collaborator

meztez commented Sep 23, 2021

As an alternative. You can register a serializer or a parser directly on the fly. Here is a an example using xml.

library(plumber)
library(xml2)

serializer_xml <- function(..., type = "application/xml") {
  serializer_content_type(type, function(val) {
    as.character(xml2::as_xml_document(val, ...))
  })
}
register_serializer("xml", serializer_xml)

parser_xml <- function(...) {
  parser_text(function(txt_value) {
    xml2::as_list(xml2::read_xml(txt_value, ...))
  })
}
register_parser("xml", parser_xml, fixed = c("text/xml", "application/xml"), regex = "/xml$")

#* @post /score/xml
#* @serializer xml
#* @parser xml
#* @parser multi
#* @param info:file
#* @param report:file
#* @param debug
function(info, report, req) {
  process_input(info, report)
}

Copy link
Collaborator

@schloerke schloerke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes: https://datatracker.ietf.org/doc/html/rfc7946#section-12 defines application/geo+json as the standard Content-Type for geojson data

DESCRIPTION Outdated Show resolved Hide resolved
DESCRIPTION Outdated Show resolved Hide resolved
R/serializer.R Outdated Show resolved Hide resolved
tests/testthat/test-serializer-geojson.R Show resolved Hide resolved
tests/testthat/test-serializer-geojson.R Outdated Show resolved Hide resolved
R/serializer.R Outdated Show resolved Hide resolved
@schloerke
Copy link
Collaborator

Thank you @JosiahParry !

Is there a way to close the round trip loop by adding a geojson parser? (Be able to both parse and serialize geojson information). @meztez's comment above gives a quick example on how to implement a parser.


If you run into more serializers/parsers that you believe are commonly used, please feel free to add another PR 😄

@JosiahParry
Copy link
Contributor Author

@schloerke thanks for the comments!
Will do. I'll make your changes and also add the parser.

@meztez
Copy link
Collaborator

meztez commented Sep 23, 2021

geojsonsf use a different R json library. I wonder if this could be avoided to reduce plumber depencies?

@schloerke
Copy link
Collaborator

@meztez , do you think these codes should live within the geojson pkg?

I don't remember the setup for broom's integration with other packages. I'm guessing this is closed to that situation

@JosiahParry
Copy link
Contributor Author

@meztez No libraries were added to Imports as such the dependency tree remains the same. There is no effect on plumber dependencies.

@meztez
Copy link
Collaborator

meztez commented Sep 23, 2021

@meztez No libraries were added to Imports as such the dependency tree remains the same. There is no effect on plumber dependencies.

Great! In that case, should we prepend call to geojsonsf function with a requireNamespace check?
https://github.com/rstudio/plumber/search?q=requireNamespace&type=code

@JosiahParry thanks a lot for this contribution

R/serializer.R Show resolved Hide resolved
R/parse-body.R Outdated Show resolved Hide resolved
R/serializer.R Outdated Show resolved Hide resolved
R/parse-body.R Show resolved Hide resolved
R/parse-body.R Outdated Show resolved Hide resolved
- Update namespace w/ devtools::document()
- Update news under "New features"
- Move check for `geojsonsf` package to top of function
- Add `application/vdn.geo+json` as valid content type
@JosiahParry
Copy link
Contributor Author

All requested changes should be addressed in most recent commit.

@schloerke schloerke merged commit 06e46f3 into rstudio:master Sep 28, 2021
@JosiahParry
Copy link
Contributor Author

Exciting!!! Thanks all for your guidance :)

schloerke added a commit that referenced this pull request Jun 2, 2022
* main:
  Fix Content-Length header on HTTP responses which forbid it (#760)
  Generate docs and fix existing tests (#860)
  decode static URI before serving (#754)
  Update feather serializer; Add parquet serializer (#849)
  remove author in pkgdown; have website build again
  Fix plumber website. Use tidytemplate (#851)
  Runtime Vignette typo (#848)
  GHA v2 (#842)
  master -> main (#839)
  Create GeoJSON serializer and parser (#830)
  Add details about named functions as router modifiers (#824)
  Parser params should be in a `list()` (#827)
  Test on ubuntu 18/20 and use relative R versions (#828)
  Shared secret rejections are not errors (#809)
  Fix tag endpoint block annotation spelling to `@tag` (#800)
  Add ORCID info (#794)
  Add blog post link to website (#792)
  Use serializer Content-Type header for PlumberEndpoint API spec (#789)
  Use dev version (#790)
  v1.1.0 (#752)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants