Skip to content

Conversation

ttskch
Copy link
Contributor

@ttskch ttskch commented Sep 22, 2025

Q A
Branch? 4.2
Tickets Related to #6960
License MIT
Doc PR N/A

This PR makes @id and @type properties required only in the JSON-LD schema for output.

@ttskch ttskch force-pushed the fix/jsonschema-jsonld branch from 6ea2a72 to ff5e438 Compare September 22, 2025 14:18
@ttskch ttskch marked this pull request as draft September 22, 2025 15:17
@ttskch ttskch changed the title refactor(jsonschema/jsonld): remove unnecessary codes fix(jsonschema/jsonld): force input schema to json format instead of jsonld format Sep 22, 2025
@ttskch ttskch marked this pull request as ready for review September 22, 2025 16:01
@soyuka
Copy link
Member

soyuka commented Sep 26, 2025

Interesting, but its possible when using JSON-LD to have @id or @context (though they're not required). They'll not appear in the schema anymore from what I read but are they allowed?

@ttskch
Copy link
Contributor Author

ttskch commented Sep 26, 2025

@soyuka

its possible when using JSON-LD to have @id or @context (though they're not required)

I see. If so, when using JSON-LD, @id and @type should be required in the output schema, and they should be optional in the input schema. This means we'll need to generate two schemas like Book.jsonld.output and Book.jsonld.input (as I suggested in #6485).

Would it be ok to modify this PR like that?

@ttskch ttskch force-pushed the fix/jsonschema-jsonld branch from 834d183 to 638ad92 Compare September 26, 2025 18:52
@ttskch
Copy link
Contributor Author

ttskch commented Sep 26, 2025

like this. (Just a PoC, don't merge yet.)

@ttskch
Copy link
Contributor Author

ttskch commented Sep 26, 2025

Example of output result

1 2

openapi.json

{
    "components": {
        "schemas": {
            "Book": {
                "type": "object",
                "properties": {
                    "id": {
                        "readOnly": true,
                        "type": "integer"
                    },
                    "title": {
                        "type": "string"
                    }
                },
                "required": [
                    "title"
                ]
            },
            "Book.jsonld.input": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/HydraItemBaseSchema"
                    },
                    {
                        "$ref": "#/components/schemas/Book"
                    }
                ]
            },
            "Book.jsonld.output": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/HydraOutputBaseSchema"
                    },
                    {
                        "$ref": "#/components/schemas/Book"
                    }
                ]
            },
            "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"
                    }
                }
            }
        }
    }
}

Reproducer

https://github.com/ttskch/api-platform-core-7397

@soyuka
Copy link
Member

soyuka commented Sep 27, 2025

Nice this looks fine! Can the output stay Book.jsonld?

@ttskch ttskch changed the title fix(jsonschema/jsonld): force input schema to json format instead of jsonld format fix(jsonschema/jsonld): make @id and @type properties required only in the JSON-LD schema for output Sep 27, 2025
@ttskch
Copy link
Contributor Author

ttskch commented Sep 27, 2025

@soyuka I fixed in 479f46b and updated the PR title and description.

Example of output result

1 2

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

https://github.com/ttskch/api-platform-core-7397

@ttskch
Copy link
Contributor Author

ttskch commented Sep 27, 2025

I'm still working to fix the CI error.

@ttskch ttskch force-pushed the fix/jsonschema-jsonld branch from 10ebeab to 1cda6cf Compare September 27, 2025 15:15
…ferencing it

It cannot always be referenced, as there may be resources that don't have a JSON schema but only a JSON-LD schema.
It's not certain at the time the JSON-LD schema is being generated whether a JSON schema will ultimately be defined.
Therefore, the JSON schema will be referenced only if it's already defined.
@ttskch ttskch force-pushed the fix/jsonschema-jsonld branch from 1cda6cf to 5fdaa77 Compare September 27, 2025 15:17
@soyuka
Copy link
Member

soyuka commented Sep 27, 2025

I can take a look if you want, and I may move this test to phpunit I thought that keeping Book.jsonld would do the trick but its probably looking for Book.jsonld-input ^^. Let me know if I should fix this.

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.

2 participants