Skip to content
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

fix(serializer) Restore the use of placeholders named differently than id #5738

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
7a78fbe
Merge pull request #5356 from api-platform/3.1
soyuka Jan 22, 2023
c353e5a
fix(graphql): do not add id field if operation already has a dedicate…
jotwea Jan 23, 2023
851aa37
feat(graphql)!: add extra args for custom queries or mutations (#5359)
alanpoulain Jan 24, 2023
1b7acfa
refactor(metadata): metadata common abstract class (#5364)
Byidi Jan 26, 2023
7438eab
Merge branch '3.1' into chore/merge-3.1
alanpoulain Feb 1, 2023
657ed0f
Merge pull request #5386 from alanpoulain/chore/merge-3.1
alanpoulain Feb 1, 2023
51e4295
fix: missing parent construct calls with named arguments (#5387)
alanpoulain Feb 1, 2023
9b4b58c
Merge 3.1
soyuka Feb 3, 2023
9d63dad
Merge 3.1
soyuka Mar 13, 2023
ccecfbb
ci: add GitHub Actions concurrency (#5471)
vincentchalamon Mar 17, 2023
ebebc46
Merge 3.1 into main
soyuka Mar 20, 2023
8e0d936
Merge 3.1
soyuka Mar 23, 2023
ccef472
fix(openapi): use 3.1 version (#5489)
soyuka Mar 23, 2023
26cd25c
refactor(metadata): replace HttpOperation constants by raw strings (#…
Apr 21, 2023
db93dbc
docs: adr refactor state management (#4655)
dunglas Apr 25, 2023
f66bc9c
chore: fix code style (#5581)
colinodell May 3, 2023
7a1d351
feat(tests): add a method to generate the IRI from a resource (#5582)
GaryPEGEOT May 5, 2023
bf4b0e4
Merge 3.1
soyuka May 9, 2023
b546e85
style: symfony rules has use_nullable_type_declaration to false
soyuka May 23, 2023
9116f15
fix(symfony): provider can throw validation exception (#5586)
soyuka May 11, 2023
502234c
fix: allowed composite identifiers with differents types
Sarahshr May 22, 2023
33b1658
fix(serializer): disable_type_enforcement with null values (#5593)
soyuka May 23, 2023
8adfbe5
ci: php8 is allowed
soyuka May 23, 2023
4998150
fix(metadata): convert composite uri variables w/ proper type
soyuka May 23, 2023
4fa2736
ci: phpstan
soyuka May 23, 2023
932be55
cs: remove print
soyuka May 23, 2023
1b574eb
Merge pull request #5598 from soyuka/merge-31
soyuka May 23, 2023
1c79c30
ci: duplicated section
soyuka May 24, 2023
039ba86
test: invalid configuration exception
soyuka May 24, 2023
4ef0ef8
feat: error as resources, jsonld errors are now problem-compliant (#5…
JacquesDurand Jun 5, 2023
6babb3d
feat: replace doctrine/inflector by symfony/string (#5637)
Romaixn Jul 5, 2023
d793ffb
feat: union/intersect types (#5470)
vincentchalamon Jul 6, 2023
d971c2e
cs: various fixes
soyuka Jul 6, 2023
31a3e87
Merge branch 3.1 into main
soyuka Jul 6, 2023
bdbab30
cs
soyuka Jul 7, 2023
2df34d8
tests
soyuka Jul 7, 2023
c9d729e
tests
soyuka Jul 7, 2023
72817e6
Merge pull request #5652 from soyuka/merge31
soyuka Jul 7, 2023
27f2096
test: remove legacy inflector (#5656)
soyuka Jul 10, 2023
3af59e6
docs: improve README [skip ci]
dunglas Jul 19, 2023
c6d9755
Merge remote-tracking branch 'upstream/3.1'
dunglas Jul 20, 2023
f4dbd17
Merge branch '3.1'
dunglas Jul 24, 2023
370bd07
chore: apply a micro-optimization to explode() calls (#5690)
dunglas Jul 24, 2023
24133df
fix: merge (#5693)
dunglas Jul 24, 2023
c66023e
Merge remote-tracking branch 'upstream/3.1'
dunglas Jul 28, 2023
11c1300
fix: previous merge
dunglas Jul 28, 2023
fc35cef
chore: cleanup previous merge
dunglas Jul 28, 2023
b8ca845
test: fix error normalizer tests
dunglas Jul 28, 2023
ccadd22
Merge 3.1
soyuka Aug 3, 2023
4650918
Merge pull request #5714 from soyuka/merge
soyuka Aug 3, 2023
cdd426f
Merge 3.1
soyuka Aug 3, 2023
566727b
test: guides would not fail (#5724)
soyuka Aug 6, 2023
5e4b1da
Merge 3.1
soyuka Aug 8, 2023
5bc422c
Merge pull request #5727 from soyuka/merge
soyuka Aug 8, 2023
92a81f0
feat(graphql): allow to disable the introspection query (#5711)
epourail Aug 8, 2023
b659aa7
Closes #5736.
Aerendir Aug 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions .github/workflows/guides.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
restore-keys: ${{ runner.os }}-composer-
- name: Install project dependencies
working-directory: docs
run: composer install --no-interaction --no-progress --ansi
run: composer install --no-interaction --no-progress --ansi && composer require webonyx/graphql-php
- name: Test guides
working-directory: docs
env:
Expand All @@ -53,10 +53,5 @@ jobs:
for d in guides/*.php; do
rm -f var/data.db
echo "Testing guide $d"
pdg-phpunit $d
code=$?
if [[ $code -ne 0 ]]; then
break
fi
pdg-phpunit $d || exit 1
done
exit $code
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# API Platform Core

API Platform Core is an easy to use and powerful system to create [hypermedia-driven REST](https://en.wikipedia.org/wiki/HATEOAS) and [GraphQL](https://graphql.org/) APIs.
API Platform Core is an easy-to-use and powerful system to create [hypermedia-driven REST](https://en.wikipedia.org/wiki/HATEOAS) and [GraphQL](https://graphql.org/) APIs.
It is a component of the [API Platform framework](https://api-platform.com) and it can be integrated
with [the Symfony framework](https://symfony.com) using the bundle distributed with the library.

It natively supports popular open formats including [JSON for Linked Data (JSON-LD)](https://json-ld.org), [Hydra Core Vocabulary](https://www.hydra-cg.com), [OpenAPI v2 (formerly Swagger) and v3](https://www.openapis.org), [HAL](https://tools.ietf.org/html/draft-kelly-json-hal-08) and [Problem Details](https://tools.ietf.org/html/rfc7807).
It natively supports popular open formats including [JSON for Linked Data (JSON-LD)](https://json-ld.org), [Hydra Core Vocabulary](https://www.hydra-cg.com), [OpenAPI v2 (formerly Swagger) and v3](https://www.openapis.org), [JSON:API](https://jsonapi.org/), [HAL](https://tools.ietf.org/html/draft-kelly-json-hal-08) and [Problem Details](https://tools.ietf.org/html/rfc7807).

Build a working and fully-featured CRUD API in minutes. Leverage the awesome features of the tool to develop complex and
high performance API-first projects. Extend or override everything you want.
Build a working and fully-featured web API in minutes. Leverage the awesome features of the tool to develop complex and
high-performance API-first projects. Extend or override everything you want.

[![GitHub Actions](https://github.com/api-platform/core/workflows/CI/badge.svg?branch=main)](https://github.com/api-platform/core/actions?query=workflow%3ACI+branch%3Amain)
[![Codecov](https://codecov.io/gh/api-platform/core/branch/main/graph/badge.svg)](https://codecov.io/gh/api-platform/core/branch/main)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/api-platform/core/badges/quality-score.png?b=main)](https://scrutinizer-ci.com/g/api-platform/core/?branch=main)

## Documentation

Expand Down
54 changes: 54 additions & 0 deletions docs/adr/0005-refactor-state-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Refactor State Management

* Status: proposed
* Deciders: @dunglas, @soyuka, @alanpoulain

## Context and Problem Statement

Since version 2.2, we support both REST and GraphQL API styles out of the box.
This leads to some code duplication to extract states from request bodies (write requests),
and to generate resource representations from states retrieved from the data source.

The REST susbystem uses [Symfony-specific kernel event listeners](https://api-platform.com/docs/core/events/#built-in-event-listeners)
while the GraphQL subsystem relies on [an ad-hoc resolver system](https://api-platform.com/docs/core/graphql/#workflow-of-the-resolvers).

Also, while it's possible [to use API Platform as a standalone PHP library](https://api-platform.com/docs/core/bootstrap/),
this requires writing boilerplate code doing mostly what is done in the Symfony-specific listeners.
As we're working on integrating API Platform with Laravel, the Laravel package will contain similar code to the one in the Symfony
event listeners too.

As Martin Fowler writes in the _Patterns of Enterprise Application Architecture_:

> There’s just one controller, so you can easily enhance its behavior at
runtime with decorators [Gang of Four](https://en.wikipedia.org/wiki/Design_Patterns). You can have decorators for
authentication, character encoding, internationalization, and so forth,
and add them using a configuration file or even while the server is
running. ([Alur et al.](http://www.corej2eepatterns.com/InterceptingFilter.htm) describe this approach in detail under the name
Intercepting Filter.)

For API Platform 3, we refactored the whole metadata susbsytem to be more flexible, powerful, and covering more use cases.
This led to the refactoring of the two main interfaces allowing to plug a data source in API Platform: the state provider and the state processor interfaces.

Leveraging these new interfaces, it should be possible to simplify the code base and to remove most code duplication by transforming most of the code currently
stored in the kernel event listeners and in the GraphQL resolvers in dedicated state processors and state providers.

## Decision Outcome

1. Move the logic currently stored in `ReadListener`, `DeserializeListener`, `DenyAccessListener`, `ValidateListener`, `WriteListener` and `SerializeListener` in classes implementing the `StateProcessorInterface` or `StateProviderInterface`. These classes will implement the decorator pattern. All classes will be composed to create a chain. The classes containing Symfony-specific and/or Doctrine-specific logic will then be able to be easily replaced by other implementations (Laravel, PSR-7, super-globals...).
2. Remove the corresponding listeners.
3. Replace `PlaceholderController` by a controller calling the main `StateProcessor` and `StateProvider` objects directly.
4. Remove the GraphQL resolvers, call the main `StateProcessor` and StateProvider objects directly.

Consenquently, transforming the raw request body (e.g. the raw JSON document) to a PHP data structure will be the responsibility of a processor.
The default one will use the Symfony Serializer component to do so, but this will give the opportunity to the user to replace this class by one using another Serializer if necessary.
This will also allow the user to access the raw body if necessary, and will enable a whole class of optimizations, extra validations (e.g. validating a raw JSON string against a JSON Schema) etc.
Similarly, transforming PHP data structures into strings to be stored in response bodies will now be the responsibility of a state provider.

This will reduce the weigth of the code base and improve the whole design of API Platform.

This new design will also replace what we currently call [the "DTO" feature](https://api-platform.com/docs/core/dto/): a "data transformer" will now be just another state provider or processor.

Finally, the `resumable()` method will be removed from these interfaces. The decorator pattern allows, by ordering the composed objects, to achieve the same result with more flexibility.

To help using API Platform without Symfony, we could provide factories building the correct chain of data providers and persisters without relying on the Symfony Dependency Injection Component.

5 changes: 3 additions & 2 deletions features/hal/problem.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ Feature: Error handling valid according to RFC 7807 (application/problem+json)
And the JSON should be equal to:
"""
{
"type": "https://tools.ietf.org/html/rfc2616#section-10",
"type": "/validation_errors/c1051bb4-d103-4f74-8988-acbcafc7fdc3",
"title": "An error occurred",
"detail": "name: This value should not be blank.",
"status": "422",
"violations": [
{
"propertyPath": "name",
Expand All @@ -44,7 +45,7 @@ Feature: Error handling valid according to RFC 7807 (application/problem+json)
Then the response status code should be 400
And the response should be in JSON
And the header "Content-Type" should be equal to "application/problem+json; charset=utf-8"
And the JSON node "type" should be equal to "https://tools.ietf.org/html/rfc2616#section-10"
And the JSON node "type" should be equal to "/errors/400"
And the JSON node "title" should be equal to "An error occurred"
And the JSON node "detail" should be equal to 'Nested documents for attribute "relatedDummy" are not allowed. Use IRIs instead.'
And the JSON node "trace" should exist
121 changes: 121 additions & 0 deletions features/main/union_intersect_types.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
Feature: Union/Intersect types

Scenario Outline: Create a resource with union type
When I add "Content-Type" header equal to "application/ld+json"
And I add "Accept" header equal to "application/ld+json"
And I send a "POST" request to "/issue-5452/books" with body:
"""
{
"number": <number>,
"isbn": "978-3-16-148410-0"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@type": {
"type": "string",
"pattern": "^Book$"
},
"@context": {
"type": "string",
"pattern": "^/contexts/Book$"
},
"@id": {
"type": "string",
"pattern": "^/.well-known/genid/.+$"
},
"number": {
"type": "<type>"
},
"isbn": {
"type": "string",
"pattern": "^978-3-16-148410-0$"
}
},
"required": [
"@type",
"@context",
"@id",
"number",
"isbn"
]
}
"""
Examples:
| number | type |
| "1" | string |
| 1 | integer |

Scenario: Create a resource with valid intersect type
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/issue-5452/books" with body:
"""
{
"number": 1,
"isbn": "978-3-16-148410-0",
"author": "/issue-5452/authors/1"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@type": {
"type": "string",
"pattern": "^Book$"
},
"@context": {
"type": "string",
"pattern": "^/contexts/Book$"
},
"@id": {
"type": "string",
"pattern": "^/.well-known/genid/.+$"
},
"number": {
"type": "integer"
},
"isbn": {
"type": "string",
"pattern": "^978-3-16-148410-0$"
},
"author": {
"type": "string",
"pattern": "^/issue-5452/authors/1$"
}
},
"required": [
"@type",
"@context",
"@id",
"number",
"isbn",
"author"
]
}
"""

Scenario: Create a resource with invalid intersect type
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/issue-5452/books" with body:
"""
{
"number": 1,
"isbn": "978-3-16-148410-0",
"library": "/issue-5452/libraries/1"
}
"""
Then the response status code should be 400
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON node "hydra:description" should be equal to 'Could not denormalize object of type "ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\ActivableInterface", no supporting normalizer found.'
24 changes: 13 additions & 11 deletions features/openapi/docs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Feature: Documentation support
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json; charset=utf-8"
# Context
And the JSON node "openapi" should be equal to "3.0.0"
And the JSON node "openapi" should be equal to "3.1.0"
# Root properties
And the JSON node "info.title" should be equal to "My Dummy API"
And the JSON node "info.description" should contain "This is a test API."
Expand Down Expand Up @@ -86,19 +86,19 @@ Feature: Documentation support
{
"default": "male",
"example": "male",
"type": "string",
"type": ["string", "null"],
"enum": [
"male",
"female",
null
],
"nullable": true
]
}
"""
And the "playMode" property exists for the OpenAPI class "VideoGame"
And the "playMode" property for the OpenAPI class "VideoGame" should be equal to:
"""
{
"owl:maxCardinality": 1,
"type": "string",
"format": "iri-reference"
}
Expand Down Expand Up @@ -238,8 +238,7 @@ Feature: Documentation support
"type": "string"
},
"property": {
"type": "string",
"nullable": true
"type": ["string", "null"]
},
"required": {
"type": "boolean"
Expand Down Expand Up @@ -310,12 +309,15 @@ Feature: Documentation support
And the "resourceRelated" property for the OpenAPI class "Resource" should be equal to:
"""
{
"readOnly":true,
"anyOf":[
"owl:maxCardinality": 1,
"readOnly": true,
"anyOf": [
{
"$ref": "#/components/schemas/ResourceRelated"
},
{
"$ref":"#/components/schemas/ResourceRelated"
"type": "null"
}
],
"nullable":true
]
}
"""
Loading
Loading