json-ld
json-ld copied to clipboard
Feature/Discussion: Serde integration
Serde derives for json+ld would be a very helpful addition.
- Are there plans to add Serde derives?
- Do you have any ideas/plans about how to add context into that derive (for optional expansion/compression on serialization/deserialization)?
- Are there any in-progress solutions or discarded attempts?
I guess we could add support for ser/de a json_ld::syntax::context::Value
(JSON-LD Context), is that what you mean? A complete JSON-LD document is no different from a JSON document. I'm using the json-syntax
library for that part, so if you want serde support for an entire LD document, which is in fact a simple JSON document, we actually need json-syntax
to support serde.
By the way there have been a lot of attempts to support many json
libraries including serde-json
and it has failed for multiple reasons, primarily because those libraries lack support for preserving code mapping metadata.
What I would hope for is a way to inject a json-ld context into the top of a serde-json document generated from a #derive d struct (possibly with expansion but not really needed). That should be sufficient to make any json document a complete and compressed json-ld document?
I am both hunting for the efficiency and ergonomic gain from doing it in one step. (I've come to understand that json-ld often loses out performance due to first generating base json and in a separate step integrating the context.) But if you can make a more ergonomic way to convert a struct to json-ld without efficiency gains that would still be lovely.
I understand that it might not be feasible. I just feel that json-ld must support something similar to the struct derives in serde-json to be worth the effort in rust.
Some way to convert a struct directly into serde_json::Value seems to be the key, but I guess it isn't in your hands if there is no such way...
(I know that you can use a link header to inject a context separately, but the Hydra spec. is unclear on if this is supported so I'd rather have it in the same document.)
There have been a lot of development since you opened the issue, and I think I can finally give some good solutions.
So first, I've added support for serde for json_ld::syntax::Context
so what you could do now is something like this:
#[derive(serde::Serialize, serde::Deserialize)]
struct MyCompactJsonDocument {
#[serde(rename = "@context")]
json_ld_context: json_ld::syntax::Context,
name: String,
// ...
}
You could deserialize and use the result directly without going through json_ld
, but in that case your app won't be able to handle any JSON-LD document that deviate from this shape.
If you want a linked-data oriented serde
-like library, you can use linked-data
, which is supported by json-ld
. With linked-data
you can annotate your type with LD info like this:
#[derive(serde::Serialize, linked_data::Deserialize)]
#[ld(prefix("ex" = "http://example.org/"))]
struct MyCompactJsonDocument {
#[serde(rename = "@context")]
#[ld(ignore)]
json_ld_context: json_ld::syntax::Context, // you might need a newtype here to have a correct default value
#[ld("ex:name")]
name: String,
// ...
}
Now you still need to first deserialize to json_syntax::Value
, then expand into json_ld::ExpandedDocument
, but then you can use linked-data
to deserialize this expanded document into MyCompactJsonDocument
without too much struggle.
I can't do better than that, you have to go through an intermediate phase to handle linked data info (second case), or just ignore linked data and accept a single shape (first case).
To me this looks like a good solution. I've left that API design behind me a while ago now, but this seems like it improves the ergonomy for the relevant use-cases (and performance is probably a non-issue in nearly every case). Makes me tempted to try json-ld again "soon".
Feel free to consider this issue resolved.