Skip to content

fix(jsonapi): add missing "included" schema parts#6277

Merged
soyuka merged 6 commits into
api-platform:mainfrom
GwendolenLynch:fix/jsonapi
Apr 5, 2024
Merged

fix(jsonapi): add missing "included" schema parts#6277
soyuka merged 6 commits into
api-platform:mainfrom
GwendolenLynch:fix/jsonapi

Conversation

@GwendolenLynch

Copy link
Copy Markdown
Contributor
Q A
Branch? main
Tickets Related #6250
License MIT

Per https://jsonapi.org/format/#fetching-includes which the serializer already handles beautifully.

Comment thread src/JsonApi/JsonSchema/SchemaFactory.php Outdated
Comment thread src/JsonApi/JsonSchema/SchemaFactory.php Outdated
@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 2 times, most recently from 41aa9e5 to 42d718a Compare April 3, 2024 08:09
@GwendolenLynch

GwendolenLynch commented Apr 3, 2024

Copy link
Copy Markdown
Contributor Author

@soyuka I have had to proof-of-concept a slightly different approach in a junk commit for review & discussion on where to go from here 🌞

Problem
Both the base and JSON:API schema factories needs to be able to reliably know the schema component "definition name" for a resource. That requires both of the getMetadata() & buildDefinitionName methods from ApiPlatform\JsonSchema\SchemaFactory.

Approach

  1. I have moved buildDefinitionName and its dependant methods to ApiPlatform\JsonSchema\DefinitionNameFactory and making that a container service api_platform.json_schema.definition_name_factory that injects into the schema factories as needed.
  2. getMetadata() and friends I put into ApiPlatform\JsonSchema\ResourceMetadataTrait

Questions

  1. Is this (generally) an acceptable direction in this case?
  2. What namespaces would you like those two new files in?

Advice and guidance warmly welcomed!

Edit: I've started breaking out more of the logic in the trait/

@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 6 times, most recently from 8f12a2a to 1cdb34a Compare April 3, 2024 12:06

@soyuka soyuka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring actually I think that it's a good idea to have a Trait to share the logic, not sure about adding a new interface though as buildDefinitionName is private anyways. Can that work only using the Trait?

Also don't put another author then yourself (no author phpdoc is also fine) and I think that the trait should be @internal so that we can make updates to it in the future without breaking userland.

Comment thread src/JsonApi/JsonSchema/SchemaFactory.php Outdated
return $schema;
return $this->schemaFactory->buildSchema($className, $format, $type, $operation, $schema, $serializerContext, $forceCollection);
}
$schema = $this->schemaFactory->buildSchema($className, $format, $type, $operation, $schema, [], $forceCollection);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would you reset the context?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping you'd bring this up 👍

I haven't mapped it out fully yet, but the JSON:API serializer seems to mostly ignore normalization groups (c.f. include query parameter.

So if it is not a jsonapi format, just pass it on as-is, else generate the schema without groups. Hadn't gotten past that so far. I got distracted with enums.

@soyuka soyuka Apr 3, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you mention the json:api specification in a comment (e.g: the JSON:API serializer ignores normalization groups and uses an include parameter)?

side note I've come accross:

$operationInputSchema = $this->jsonSchemaFactory->buildSchema($resourceClass, $operationFormat, Schema::TYPE_INPUT, $operation, $schema, null, $forceSchemaCollection);

Looks like we don't send the context from the openapi factory but I'm not sure why.

Comment thread src/JsonSchema/DefinitionNameFactory.php Outdated
Comment thread src/JsonSchema/DefinitionNameFactory.php Outdated
Comment thread src/JsonSchema/DefinitionNameFactoryInterface.php Outdated
Comment thread src/JsonSchema/ResourceMetadataTrait.php Outdated
Comment thread src/JsonSchema/ResourceMetadataTrait.php
Comment thread src/JsonSchema/SchemaFactory.php Outdated
Comment thread src/JsonSchema/SchemaFactory.php Outdated
@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 2 times, most recently from 04107af to 0d141a5 Compare April 3, 2024 15:00
@GwendolenLynch

Copy link
Copy Markdown
Contributor Author

[…] not sure about adding a new interface though as buildDefinitionName is private anyways. Can that work only using the Trait?

It can. I chose to externalise it as a guess as to what you'd choose … plus the thought that definition name generation becomes implementation override-able.

Your call 👍

@soyuka

soyuka commented Apr 3, 2024

Copy link
Copy Markdown
Member

Indeed but as long as you use the shortName the extension point exists no? If you are in a weird case you need to decorate the SchemaFactory.

@GwendolenLynch

Copy link
Copy Markdown
Contributor Author

As I understand it, it depends on how formats: config is set-up.

Assume you have the resource Foo.

If you set, for example, one format in the formats key:

api_platform:
    formats:
        jsonapi:  ['application/vnd.api+json']

… then patch_formats will default to application/merge-patch+json so you will end up with two definitions:

  • Foo (write operations)
  • Foo.jsonapi (read operations)

However, if you configure a non application/merge-patch+json in patch_formats:

api_platform:
    formats:
        jsonapi:  ['application/vnd.api+json']
    patch_formats:
        jsonapi:  ['application/vnd.api+json']

… you will end up with one definition:

  • Foo.jsonapi

Now if you add (de)normalization groups all bets are off. Hence the refactoring in this PR.

I did not know all that a couple of weeks ago, so yeah 😇

@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 2 times, most recently from e06b7df to 1e7d6a3 Compare April 3, 2024 16:07
@GwendolenLynch

Copy link
Copy Markdown
Contributor Author

One other thing that came to mind with having it separate is unit testing. It makes that part of the process distinctly testable.

Disclaimer: I can be overly obsessive about unit tests and the "…one thing well" principle. 😊

@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 6 times, most recently from ab0e57a to 823d8d3 Compare April 3, 2024 18:49
Comment thread src/JsonSchema/DefinitionNameFactory.php Outdated
Comment thread src/Symfony/Bundle/Resources/config/json_schema.xml Outdated
Comment thread src/JsonSchema/DefinitionNameFactoryInterface.php
Comment thread src/JsonSchema/DefinitionNameFactoryInterface.php
Comment thread src/JsonSchema/ResourceMetadataTrait.php
Comment thread src/JsonSchema/ResourceMetadataTrait.php

@soyuka soyuka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, few leftovers

Comment thread src/JsonSchema/DefinitionNameFactory.php Outdated
@GwendolenLynch GwendolenLynch force-pushed the fix/jsonapi branch 2 times, most recently from e47c42d to 6eacdcc Compare April 4, 2024 15:37
Comment thread src/JsonSchema/DefinitionNameFactory.php Outdated
Comment thread src/JsonSchema/ResourceMetadataTrait.php Outdated
Comment thread src/Symfony/Bundle/Resources/config/jsonapi.xml Outdated
@soyuka soyuka merged commit 678eb4f into api-platform:main Apr 5, 2024
@GwendolenLynch GwendolenLynch deleted the fix/jsonapi branch April 5, 2024 09:29
@GwendolenLynch

Copy link
Copy Markdown
Contributor Author

Thanks @soyuka!

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