-
-
Notifications
You must be signed in to change notification settings - Fork 935
fix(jsonschema/jsonld): make @id and @type properties required only in the JSON-LD schema for output
#7397
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
Conversation
6ea2a72 to
ff5e438
Compare
|
Interesting, but its possible when using JSON-LD to have |
I see. If so, when using JSON-LD, Would it be ok to modify this PR like that? |
834d183 to
638ad92
Compare
|
like this. (Just a PoC, don't merge yet.) |
|
Nice this looks fine! Can the |
@id and @type properties required only in the JSON-LD schema for output
|
@soyuka I fixed in 479f46b and updated the PR title and description. Example of output result
openapi.json{
"openapi": "3.1.0",
"info": {
"title": "Hello API Platform",
"description": "",
"version": "1.0.0"
},
"servers": [
{
"url": "/",
"description": ""
}
],
"paths": {
"/api/books": {
"get": {
"operationId": "api_books_get_collection",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book collection",
"content": {
"application/ld+json": {
"schema": {
"type": "object",
"description": "Book.jsonld collection.",
"allOf": [
{
"$ref": "#/components/schemas/HydraCollectionBaseSchema"
},
{
"type": "object",
"properties": {
"hydra:member": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
}
}
]
}
}
}
}
},
"summary": "Retrieves the collection of Book resources.",
"description": "Retrieves the collection of Book resources.",
"parameters": [
{
"name": "page",
"in": "query",
"description": "The collection page number",
"required": false,
"deprecated": false,
"schema": {
"type": "integer",
"default": 1
},
"style": "form",
"explode": false
}
]
},
"post": {
"operationId": "api_books_post",
"tags": [
"Book"
],
"responses": {
"201": {
"description": "Book resource created",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
},
"links": {}
},
"400": {
"description": "Invalid input",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
},
"422": {
"description": "An error occurred",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
}
},
"links": {}
}
},
"summary": "Creates a Book resource.",
"description": "Creates a Book resource.",
"parameters": [],
"requestBody": {
"description": "The new Book resource",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld.input"
}
}
},
"required": true
}
}
},
"/api/books/{id}": {
"get": {
"operationId": "api_books_id_get",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book resource",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Retrieves a Book resource.",
"description": "Retrieves a Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
]
},
"delete": {
"operationId": "api_books_id_delete",
"tags": [
"Book"
],
"responses": {
"204": {
"description": "Book resource deleted"
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Removes the Book resource.",
"description": "Removes the Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
]
},
"patch": {
"operationId": "api_books_id_patch",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book resource updated",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
},
"links": {}
},
"400": {
"description": "Invalid input",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
},
"422": {
"description": "An error occurred",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
}
},
"links": {}
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Updates the Book resource.",
"description": "Updates the Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
],
"requestBody": {
"description": "The updated Book resource",
"content": {
"application/merge-patch+json": {
"schema": {
"$ref": "#/components/schemas/Book"
}
}
},
"required": true
}
}
}
},
"components": {
"schemas": {
"Book": {
"type": "object",
"properties": {
"id": {
"readOnly": true,
"type": "integer"
},
"title": {
"type": "string"
}
},
"required": [
"title"
]
},
"Book.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraOutputBaseSchema"
},
{
"$ref": "#/components/schemas/Book"
}
]
},
"Book.jsonld.input": {
"allOf": [
{
"$ref": "#/components/schemas/HydraItemBaseSchema"
},
{
"$ref": "#/components/schemas/Book"
}
]
},
"ConstraintViolation": {
"type": "object",
"description": "Unprocessable entity",
"properties": {
"status": {
"default": 422,
"type": "integer"
},
"violations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"propertyPath": {
"type": "string",
"description": "The property path of the violation"
},
"message": {
"type": "string",
"description": "The message associated with the violation"
}
}
}
},
"detail": {
"readOnly": true,
"type": "string"
},
"type": {
"readOnly": true,
"type": "string"
},
"title": {
"readOnly": true,
"type": [
"string",
"null"
]
},
"instance": {
"readOnly": true,
"type": [
"string",
"null"
]
}
}
},
"ConstraintViolation.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraOutputBaseSchema"
},
{
"$ref": "#/components/schemas/ConstraintViolation"
}
]
},
"Error": {
"type": "object",
"description": "A representation of common errors.",
"properties": {
"title": {
"readOnly": true,
"description": "A short, human-readable summary of the problem.",
"type": "string"
},
"detail": {
"readOnly": true,
"description": "A human-readable explanation specific to this occurrence of the problem.",
"type": "string"
},
"status": {
"type": "number",
"examples": [
404
],
"default": 400
},
"instance": {
"readOnly": true,
"description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.",
"type": [
"string",
"null"
]
},
"type": {
"readOnly": true,
"description": "A URI reference that identifies the problem type",
"type": "string"
}
}
},
"Error.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraOutputBaseSchema"
},
{
"$ref": "#/components/schemas/Error"
}
]
},
"HydraCollectionBaseSchema": {
"type": "object",
"required": [
"hydra:member"
],
"properties": {
"hydra:member": {
"type": "array"
},
"hydra:totalItems": {
"type": "integer",
"minimum": 0
},
"hydra:view": {
"type": "object",
"properties": {
"@id": {
"type": "string",
"format": "iri-reference"
},
"@type": {
"type": "string"
},
"hydra:first": {
"type": "string",
"format": "iri-reference"
},
"hydra:last": {
"type": "string",
"format": "iri-reference"
},
"hydra:previous": {
"type": "string",
"format": "iri-reference"
},
"hydra:next": {
"type": "string",
"format": "iri-reference"
}
},
"example": {
"@id": "string",
"type": "string",
"hydra:first": "string",
"hydra:last": "string",
"hydra:previous": "string",
"hydra:next": "string"
}
},
"hydra:search": {
"type": "object",
"properties": {
"@type": {
"type": "string"
},
"hydra:template": {
"type": "string"
},
"hydra:variableRepresentation": {
"type": "string"
},
"hydra:mapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@type": {
"type": "string"
},
"variable": {
"type": "string"
},
"property": {
"type": [
"string",
"null"
]
},
"required": {
"type": "boolean"
}
}
}
}
}
}
}
},
"HydraItemBaseSchema": {
"type": "object",
"properties": {
"@context": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"@vocab": {
"type": "string"
},
"hydra": {
"type": "string",
"enum": [
"http://www.w3.org/ns/hydra/core#"
]
}
},
"required": [
"@vocab",
"hydra"
],
"additionalProperties": true
}
]
},
"@id": {
"type": "string"
},
"@type": {
"type": "string"
}
}
},
"HydraOutputBaseSchema": {
"required": [
"@id",
"@type"
],
"type": "object",
"properties": {
"@context": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"@vocab": {
"type": "string"
},
"hydra": {
"type": "string",
"enum": [
"http://www.w3.org/ns/hydra/core#"
]
}
},
"required": [
"@vocab",
"hydra"
],
"additionalProperties": true
}
]
},
"@id": {
"type": "string"
},
"@type": {
"type": "string"
}
}
}
},
"responses": {},
"parameters": {},
"examples": {},
"requestBodies": {},
"headers": {},
"securitySchemes": {}
},
"security": [],
"tags": [
{
"name": "Book",
"description": "Resource 'Book' operations."
}
],
"webhooks": {}
}Reproducer |
|
I'm still working to fix the CI error. |
1cda6cf to
5fdaa77
Compare
|
I can take a look if you want, and I may move this test to phpunit I thought that keeping |
cb98a29 to
b0cac3a
Compare
b0cac3a to
5fdaa77
Compare
fa1305f to
ad9be8a
Compare
|
rebased with current 4.2 |
e92aeff to
d1e60d9
Compare
|
@soyuka I've mostly revised the existing tests to match the implementation. The only thing I'm unsure of is how to properly modify The new schema uses |
|
can you check my patch? |
b3ab513 to
c33a778
Compare
If we were to delegate the processing to the original `SchemaFactory` while keeping the `jsonld` format, the `$definitionName` would be `Book.jsonld` instead of `Book` at [here](https://github.com/api-platform/core/blob/v4.2.1/src/JsonSchema/SchemaFactory.php#L84), and the `Book.jsonld` schema would be returned as is at [here](https://github.com/api-platform/core/blob/v4.2.1/src/JsonSchema/SchemaFactory.php#L106-L109), so the input schema would be the same jsonld schema as the output schema.
c33a778 to
13e4ea3
Compare
9516deb to
50a46f7
Compare
|
I tried using As I understand it, even if So your only options are to either generate an alias schema for input, such as I have updated this PR to the bare minimum and rebased it with the latest 4.2. Here's what it currently works below. What about this? Example of output result of reproducer
openapi.json of reproducer{
"openapi": "3.1.0",
"info": {
"title": "Hello API Platform",
"description": "",
"version": "1.0.0"
},
"servers": [
{
"url": "/",
"description": ""
}
],
"paths": {
"/api/books": {
"get": {
"operationId": "api_books_get_collection",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book collection",
"content": {
"application/ld+json": {
"schema": {
"type": "object",
"description": "Book.jsonld collection.",
"allOf": [
{
"$ref": "#/components/schemas/HydraCollectionBaseSchema"
},
{
"type": "object",
"properties": {
"hydra:member": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
}
}
]
}
}
}
}
},
"summary": "Retrieves the collection of Book resources.",
"description": "Retrieves the collection of Book resources.",
"parameters": [
{
"name": "page",
"in": "query",
"description": "The collection page number",
"required": false,
"deprecated": false,
"schema": {
"type": "integer",
"default": 1
},
"style": "form",
"explode": false
}
]
},
"post": {
"operationId": "api_books_post",
"tags": [
"Book"
],
"responses": {
"201": {
"description": "Book resource created",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
},
"links": {}
},
"400": {
"description": "Invalid input",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
},
"422": {
"description": "An error occurred",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
}
},
"links": {}
}
},
"summary": "Creates a Book resource.",
"description": "Creates a Book resource.",
"parameters": [],
"requestBody": {
"description": "The new Book resource",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book"
}
}
},
"required": true
}
}
},
"/api/books/{id}": {
"get": {
"operationId": "api_books_id_get",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book resource",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Retrieves a Book resource.",
"description": "Retrieves a Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
]
},
"delete": {
"operationId": "api_books_id_delete",
"tags": [
"Book"
],
"responses": {
"204": {
"description": "Book resource deleted"
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Removes the Book resource.",
"description": "Removes the Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
]
},
"patch": {
"operationId": "api_books_id_patch",
"tags": [
"Book"
],
"responses": {
"200": {
"description": "Book resource updated",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Book.jsonld"
}
}
},
"links": {}
},
"400": {
"description": "Invalid input",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
},
"422": {
"description": "An error occurred",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConstraintViolation"
}
}
},
"links": {}
},
"404": {
"description": "Not found",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Updates the Book resource.",
"description": "Updates the Book resource.",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Book identifier",
"required": true,
"deprecated": false,
"schema": {
"type": "string"
},
"style": "simple",
"explode": false
}
],
"requestBody": {
"description": "The updated Book resource",
"content": {
"application/merge-patch+json": {
"schema": {
"$ref": "#/components/schemas/Book"
}
}
},
"required": true
}
}
}
},
"components": {
"schemas": {
"Book": {
"type": "object",
"properties": {
"id": {
"readOnly": true,
"type": "integer"
},
"title": {
"type": "string"
}
},
"required": [
"title"
]
},
"Book.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraItemBaseSchema"
},
{
"type": "object",
"properties": {
"id": {
"readOnly": true,
"type": "integer"
},
"title": {
"type": "string"
}
},
"required": [
"title"
]
}
]
},
"ConstraintViolation": {
"type": "object",
"description": "Unprocessable entity",
"properties": {
"status": {
"default": 422,
"type": "integer"
},
"violations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"propertyPath": {
"type": "string",
"description": "The property path of the violation"
},
"message": {
"type": "string",
"description": "The message associated with the violation"
}
}
}
},
"detail": {
"readOnly": true,
"type": "string"
},
"type": {
"readOnly": true,
"type": "string"
},
"title": {
"readOnly": true,
"type": [
"string",
"null"
]
},
"instance": {
"readOnly": true,
"type": [
"string",
"null"
]
}
}
},
"ConstraintViolation.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraItemBaseSchema"
},
{
"type": "object",
"properties": {
"status": {
"default": 422,
"type": "integer"
},
"violations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"propertyPath": {
"type": "string",
"description": "The property path of the violation"
},
"message": {
"type": "string",
"description": "The message associated with the violation"
}
}
}
},
"detail": {
"readOnly": true,
"type": "string"
},
"description": {
"readOnly": true,
"type": "string"
},
"type": {
"readOnly": true,
"type": "string"
},
"title": {
"readOnly": true,
"type": [
"string",
"null"
]
},
"instance": {
"readOnly": true,
"type": [
"string",
"null"
]
}
}
}
],
"description": "Unprocessable entity"
},
"Error": {
"type": "object",
"description": "A representation of common errors.",
"properties": {
"title": {
"readOnly": true,
"description": "A short, human-readable summary of the problem.",
"type": "string"
},
"detail": {
"readOnly": true,
"description": "A human-readable explanation specific to this occurrence of the problem.",
"type": "string"
},
"status": {
"type": "number",
"examples": [
404
],
"default": 400
},
"instance": {
"readOnly": true,
"description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.",
"type": [
"string",
"null"
]
},
"type": {
"readOnly": true,
"description": "A URI reference that identifies the problem type",
"type": "string"
}
}
},
"Error.jsonld": {
"allOf": [
{
"$ref": "#/components/schemas/HydraItemBaseSchema"
},
{
"type": "object",
"properties": {
"title": {
"readOnly": true,
"description": "A short, human-readable summary of the problem.",
"type": "string"
},
"detail": {
"readOnly": true,
"description": "A human-readable explanation specific to this occurrence of the problem.",
"type": "string"
},
"status": {
"type": "number",
"examples": [
404
],
"default": 400
},
"instance": {
"readOnly": true,
"description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.",
"type": [
"string",
"null"
]
},
"type": {
"readOnly": true,
"description": "A URI reference that identifies the problem type",
"type": "string"
},
"description": {
"readOnly": true,
"type": [
"string",
"null"
]
}
}
}
],
"description": "A representation of common errors."
},
"HydraCollectionBaseSchema": {
"type": "object",
"required": {
"0": "hydra:member",
"items": {
"type": "object"
}
},
"properties": {
"hydra:member": {
"type": "array"
},
"hydra:totalItems": {
"type": "integer",
"minimum": 0
},
"hydra:view": {
"type": "object",
"properties": {
"@id": {
"type": "string",
"format": "iri-reference"
},
"@type": {
"type": "string"
},
"hydra:first": {
"type": "string",
"format": "iri-reference"
},
"hydra:last": {
"type": "string",
"format": "iri-reference"
},
"hydra:previous": {
"type": "string",
"format": "iri-reference"
},
"hydra:next": {
"type": "string",
"format": "iri-reference"
}
},
"example": {
"@id": "string",
"type": "string",
"hydra:first": "string",
"hydra:last": "string",
"hydra:previous": "string",
"hydra:next": "string"
}
},
"hydra:search": {
"type": "object",
"properties": {
"@type": {
"type": "string"
},
"hydra:template": {
"type": "string"
},
"hydra:variableRepresentation": {
"type": "string"
},
"hydra:mapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@type": {
"type": "string"
},
"variable": {
"type": "string"
},
"property": {
"type": [
"string",
"null"
]
},
"required": {
"type": "boolean"
}
}
}
}
}
}
}
},
"HydraItemBaseSchema": {
"type": "object",
"properties": {
"@context": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"@vocab": {
"type": "string"
},
"hydra": {
"type": "string",
"enum": [
"http://www.w3.org/ns/hydra/core#"
]
}
},
"required": [
"@vocab",
"hydra"
],
"additionalProperties": true
}
]
},
"@id": {
"type": "string"
},
"@type": {
"type": "string"
}
},
"required": [
"@id",
"@type"
]
}
},
"responses": {},
"parameters": {},
"examples": {},
"requestBodies": {},
"headers": {},
"securitySchemes": {}
},
"security": [],
"tags": [
{
"name": "Book",
"description": "Resource 'Book' operations."
}
],
"webhooks": {}
}
|






This PR makes
@idand@typeproperties required only in the JSON-LD schema for output.