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

Per-element control of unbox #75

Open
mmuurr opened this issue Nov 13, 2023 · 8 comments
Open

Per-element control of unbox #75

mmuurr opened this issue Nov 13, 2023 · 8 comments

Comments

@mmuurr
Copy link

mmuurr commented Nov 13, 2023

{jsonify} is great, but I struggle to use it as a mediator for communication with some external APIs due to one missing feature: element-level control of the unbox parameter (in to_json()).
A third-party API might expect this object:

{
  "unboxed_prop": "foo",
  "boxed_prop": ["variable", "length", "array"]
}

With {jsonlite}, we'd coerce the corresponding R object to something like:

x <- some_data_here()  ## may return a vector of length 0, 1, or more
list(
  unboxed_prop = "foo",
  boxed_prop = I(x)  ## 'protect' the value here with I()/AsIs
) |>
jsonlite::toJSON(auto_unbox = TRUE)

With I(x), boxed_prop is guaranteed to be JSON-encoded as an array regardless of length(x).

Is something like this possible with {jsonify}?

@dcooley
Copy link
Collaborator

dcooley commented Nov 13, 2023

These give the same output

x <- 1:3
l <- list(
  unboxed_prop = "foo",
  boxed_prop = I(x)  ## 'protect' the value here with I()/AsIs
)

l |> jsonlite::toJSON(auto_unbox = TRUE)
l |> jsonify::to_json(unbox = TRUE)

so I'm not really sure what your question is

@mmuurr
Copy link
Author

mmuurr commented Nov 13, 2023

When length(x) == 1, they yield different outputs:

x <- 1
l <- list(
  unboxed_prop = "foo",
  boxed_prop = I(x)  ## 'protect' the value here with I()/AsIs
)

l |> jsonlite::toJSON(auto_unbox = TRUE)  ## {"unboxed_prop":"foo","boxed_prop":[1]}
l |> jsonify::to_json(unbox = TRUE)  ## {"unboxed_prop":"foo","boxed_prop":1.0}

And here the key is that a receiver of this JSON may require that "boxed_prop" be an array, while also requiring the "unboxed_prop" is scalar.

@dcooley
Copy link
Collaborator

dcooley commented Nov 14, 2023

There's a working prototype on branch issue75 if you want to try it:

remotes::install_github("SymbolixAU/jsonify", ref = "issue75")

@mmuurr
Copy link
Author

mmuurr commented Nov 14, 2023

Thanks! I'll take a look over the next day or so and report back :-)

@dcooley
Copy link
Collaborator

dcooley commented Mar 19, 2024

Hi @mmuurr did this work for you?

@OlaCaster
Copy link

+1 on this request; jsonlite::unbox offers great flexibility and, as mentioned above, explicit control of unboxing may be required by the recipient

@dcooley
Copy link
Collaborator

dcooley commented Sep 23, 2024

This is working on branch issue75. I was waiting for the OP to test to see if it worked for them. Perhaps you could try it @OlaCaster and let me know if this works for your needs?

Install the issue75 branch with:

remotes::install_github("SymbolixAU/jsonify", ref = "issue75")

Then this should work

x <- 1
l <- list(
  unboxed_prop = "foo",
  boxed_prop = I(x)  ## 'protect' the value here with I()/AsIs
)

l |> jsonlite::toJSON(auto_unbox = TRUE)
# {"unboxed_prop":"foo","boxed_prop":[1]} 
l |> jsonify::to_json(unbox = TRUE)
# {"unboxed_prop":"foo","boxed_prop":[1.0]} 

@dcooley
Copy link
Collaborator

dcooley commented Sep 23, 2024

Note, however, using I() also prevents any length vectors being unboxed

x <- 1
l <- list(
  unboxed_prop = "foo",
  boxed_prop = I(c(x,x))  ## length > 1 vector
)

l |> jsonlite::toJSON(auto_unbox = TRUE)
# {"unboxed_prop":"foo","boxed_prop":[1,1]} 
l |> jsonify::to_json(unbox = TRUE)
# {"unboxed_prop":"foo","boxed_prop":[1.0,1.0]} 

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

No branches or pull requests

3 participants