JSON LD serialization from schema.org - schema.org

The following example is given on the json-ld playground.
Person example(expanded):
json-ld:
{
"#context": "http://schema.org/",
"#type": "Person",
"name": "Jane Doe",
"jobTitle": "Professor",
"telephone": "(425) 123-4567",
"url": "http://www.janedoe.com"
}
after serializtion to expanded:
[
{
"#type": [
"http://schema.org/Person"
],
"http://schema.org/jobTitle": [
{
"#value": "Professor"
}
],
"http://schema.org/name": [
{
"#value": "Jane Doe"
}
],
"http://schema.org/telephone": [
{
"#value": "(425) 123-4567"
}
],
"http://schema.org/url": [
{
"#id": "http://www.janedoe.com"
}
]
}
]
I ask myself where does the serializer gets the information to map the properties to the right subsequent schema (name). To achieve that, it must be able to get hold on to the person json ld schema. But if I go to https://schema.org/Person I get an HTML back and not a JSON-LD file.
So where does the serialization knowledge come from?

Jay is correct that the knowledge comes from the #context. This can be specified in a couple of ways:
Inline, using an object value for #context (or an array, which includes an object),
By directly retrieving a context from the URL specified (e.g., https://json-ld.org/contexts/person.jsonld),
By having the server do context-negotiation on the request, as an HTTP request includes an Accept header preferring JSON-LD (see Interpreting JSON as JSON-LD) such as the following:
GET /ordinary-json-document.json HTTP/1.1
Host: example.com
Accept: application/ld+json,application/json,*/*;q=0.1
Or, as is presently deployed by schema.org, by returning a Link header along with a GET or HEAD request identifying the location of the actual context to load (See Alternate Document Location):
HTTP/1.1 200 OK
...
Content-Type: text/html
Link: <alternate.jsonld>; rel="alternate"; type="application/ld+json"
This last case is used by schema.org because of the challenges of making HTTP Content-Negotiation work properly on certain static site generators. If you to a HEAD request at https://schema.org, you'll get back headers including the following:
HTTP/2 200
link: </docs/jsonldcontext.jsonld>; rel="alternate"; type="application/ld+json"
A conforming JSON-LD processor (such as on the json-ld.org playground) knows to follow this link to find the actual context.
In the case of the Person example, "Person" and the other keys are turned into IRIs based on instructions in that context file such as the following:
{
"#context": {
...
"schema": "http://schema.org/",
"Person": {"#id": "schema:Person"},
"name": { "#id": "schema:name"},
"jobTitle": { "#id": "schema:jobTitle"},
"telephone": { "#id": "schema:telephone"},
"url": { "#id": "schema:url", "#type": "#id"},
...
}
}
Note that in the case of "url", it also knows that the value of that property should be treated as an IRI, rather than a text string.

Related

Creating a domain in Plesk's REST API

So, experimenting with Plesk's REST API (available as of version 17.8) for a project at work, and I'm starting to get a feel for it. I've been trying to experiment with adding a domain, but it's been giving me errors when I have to specify the hosting type.
The request body itself is as follows:
{
"name":"example.com",
"hosting_type":"virtual",
"description":"Description goes here"
}
This gets the following cryptic response:
{
"code": 1014,
"message": "htype\/vrt_hst is specified but there is no hosting\/vrt_hst"
}
Per the documentation provided at /api/v2/swagger.yml, any of the following values should be allowed: virtual, standard_forwarding, frame_forwarding, none
No matter what I put in, however, I get a variant of the response above (htype\/{type} is specified but there is no hosting\/{type}).
At this point I'm kind of stuck; I'm not sure what to check, and any references when I try to look up the error code go to references on Plesk's XML API instead. What's the missing link here needed to get the request to work?
It looks like system user is not specified - hosting_settings. Try to add domain with full json request. Here is example:
{
"name": "example.com",
"description": "My website",
"hosting_type": "virtual",
"hosting_settings": {
"ftp_login": "test_login",
"ftp_password": "test_pwd"
},
"base_domain": {
"id": 7,
"name": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"parent_domain": {
"id": 7,
"name": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"owner_client": {
"id": 7,
"login": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1",
"external_id": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"ipv4": [
"212.192.122.46"
],
"ipv6": [
"2002:5bcc:18fd:c:123:123:123:123"
],
"plan": {
"name": "Unlimited"
}
}
Examples for REST API https://app.swaggerhub.com/apis/plesk/api/v2#/Domains/post_domains

Validate referential integrity of object arrays with Joi

I'm trying to validate that the data I am returned it sensible. Validating data types is done. Now I want to validate that I've received all of the data needed to perform a task.
Here's a representative example:
{
"things": [
{
"id": "00fb60c7-520e-4228-96c7-13a1f7a82749",
"name": "Thing 1",
"url": "https://lolagons.com"
},
{
"id": "709b85a3-98be-4c02-85a5-e3f007ce4bbf",
"name": "Thing 2",
"url": "https://lolfacts.com"
}
],
"layouts": {
"sections": [
{
"id": "34f10988-bb3d-4c38-86ce-ed819cb6daee",
"name": "Section 1",
"content:" [
{
"type": 2,
"id": "00fb60c7-520e-4228-96c7-13a1f7a82749" //Ref to Thing 1
}
]
}
]
}
}
So every Section references 0+ Things, and I want to validate that every id value returned in the Content of Sections also exists as an id in Things.
The docs for Object.assert(..) implies that I need a concrete reference. Even if I do the validation within the Object.keys or Array.items, I can't resolve the reference at the other end.
Not that it matters, but my context is that I'm validating HTTP responses within IcedFrisby, a Frisby.js fork.
This wasn't really solveable in the way I asked (i.e. with Joi).
I solved this for my context by writing a plugin for icedfrisby (published on npm here) which uses jsonpath to fetch each id in Content and each id in Things. The plugin will then assert that all of the first set exist within the second.

What exactly are pointers in Schema.org and how to use them with JSON-LD?

The schema.org docs refer sometimes to "pointers". E.g. Product schema has the property isSimilarTo.
I do understand, that I could use a Productor a Service directly. E.g.:
<script type="application/ld+json">
{
"#context": "http://schema.org/",
"#type": "Product",
"name": "BMW",
"isSimilarTo": {
"#type": "Product",
"name": "Mercedes Benz"
},
"offers": {
"#type": "Offer",
"priceCurrency": "EUR",
"price": "100000.00"
}
}
</script>
Is this the only and the correct way using and interpreting the term 'pointer' in this context? For a pointer, I would rather expect some value (an ID or an URL or similar) just pointing to another product or service.
Your example is correct, and it follows Schema.org’s recommendation for the expected value of the isSimilarTo property. But Schema.org allows URI values for each property, even for those that don’t explicitly list URL as expected value.
So you could also use:
"isSimilarTo": {
"#id": "https://example.com/products/mercedes-benz#this"
},
Note that consumers (like Google) don’t necessarily follow these references. You could also use both ways: provide the data (or some of it) on the current page, and refer to the item’s URI:
"isSimilarTo": {
"#id": "https://example.com/products/mercedes-benz#this",
"#type": "Product",
"name": "Mercedes Benz",
"url": "https://example.com/products/mercedes-benz"
},

Should links in json-api responses be encoded?

Should the query params in links appearing in JSON-API responses be percent-encoded?
The examples from jsonapi.org are not encoded, as in:
{
"links": {
"self": "http://example.com/articles",
"next": "http://example.com/articles?page[offset]=2",
"last": "http://example.com/articles?page[offset]=10"
},
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
}
]
}
However, there is also a note regarding encoding parameters in requests:
GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json
Note: The above example URI shows unencoded [ and ] characters simply for readability. In practice, these characters must be percent-encoded, per the requirements in RFC 3986.
Does this note apply only to requests? Or should responses also be percent-encoded, as in:
{
"links": {
"self": "http://example.com/articles",
"next": "http://example.com/articles?page%5Boffset%5D=2",
"last": "http://example.com/articles?page%5Boffset%5D=10"
},
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
}
]
}
Yes, the note about encoding URI's in your question applies only to the request, not the response
With a json string returned inside a response, the only thing required to escape is the double quote character "
GET requests (not responses) are a different ball of wax. Anything in a GET request passed as a parameter in the URL must be URL encoded. So if you have a parameter url=http://some.url.com, the url on the right of the parameter assignment needs encoding.
It's tricky with POST and PUT requests. Depending on the content type set in the header you may need to encode. If your content type is application/json, you should not need to url encode anyting in your json string, (excluding the before mentioned ").
Now, if the specificed content encoding you state doesn't match what your sending (or if you didn't explicitly add one and it defaults to something), like if you send content-type: application/x-www-form-urlencoded but send a json string, the API service may or may not accept it and who know what how it will treat the content inside as far a url decoding it.

Getting specific headers along with other body data in Users.thread: get

You can very easily select what headers you want in a Users.thread: get-request, like so:
format = metadata
metadataHeaders = From
GET https://www.googleapis.com/gmail/v1/users/me/threads/14eaffaf5e3e8242?metadataHeaders=From&format=metadata&key={YOUR_API_KEY}
Response:
{
"id": "14eaffaf5e3e8242",
"historyId": "510358",
"messages": [
{
"id": "14eaffaf5e3e8242",
"threadId": "14eaffaf5e3e8242",
"labelIds": [
"SENT",
"INBOX",
"IMPORTANT"
],
"snippet": "Wow Emil!",
"historyId": "510292",
"internalDate": "1437471536000",
"payload": {
"mimeType": "multipart/mixed",
"headers": [
{
"name": "From", // I just got the header I asked for.
"value": "Emil Tholin <emtholin#gmail.com>"
}
]
},
"sizeEstimate": 9260
}, ...
}
You can also get certain parts of the body very easily. E.g. here I ask for the attachmentIds of all the attachments in the message body:
field = messages/id,messages/payload/parts/body/attachmentId
GET https://www.googleapis.com/gmail/v1/users/me/threads/14eaffaf5e3e8242?fields=messages%2Fid%2Cmessages%2Fpayload%2Fparts%2Fbody%2FattachmentId&key={YOUR_API_KEY}
Response:
{
"messages": [
{
"id": "14eaffaf5e3e8242",
"payload": {
"parts": [
{
"body": { // This message had an attachment.
"attachmentId": "ANGjdJ_0lphTo48BO0xBT_YOSo3tYah23hzpjyATe3GwfziK0I6401P_8-ZYoGuCQPHhpPP0-S_pjL68WIEZzQ0tu72RcIOE4UY3kA4u8PjXPf3Cm5PxVJjmH9N0hm0fFX31RYo8bfZQ6l7bDbYbnCSZbckG7g8enGaKMPbBzIEEC4HXr_YghOYWSfrXKXiFLnxWN4LfsFk3IXUN2tVvMe_0xMhDDfBlqYPnXHr2PhPghq7bQojNxiH4YziIqaKmwiU4xqVfygbae-K-_Q2blyz0EgI4OXjMzwz56Q5e1w"
}
}
]
}
},
{
"id": "14eaffb277b61cd0" // This message had no attachment.
}, ...
]
}
As you can see in the first request, no part of the body is retrieved when asking for specific metadata headers. Individual fields are also hard to pick out in the fields-parameter, since headers are not key-value pairs, but objects on the form { "name": <HEADER_NAME>, "value": <HEADER_VALUE> }.
Is there any way to combine these two requests? I would like to get all the relevant metadata about a message at the same time as getting how many attachments there are in the message.
From Users.threads.get.
"metadata": Returns email headers with message metadata such as identifiers and labels.
The fields parameter is only used to limit the amount of data returned. Since metadata mode is already a limited response you can't use fields to get data outside of that subset. Your best option would be to use your second example with fields and then filter the metadata values locally.