Skip to content

Commit b7f20d4

Browse files
committed
Add a document presenting general design considerations
1 parent 2df20c2 commit b7f20d4

File tree

4 files changed

+82
-31
lines changed

4 files changed

+82
-31
lines changed

core/data-persisters.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ This interface defines only 3 methods:
2424

2525
* `persist`: to create or update the given data
2626
* `delete`: to delete the given data
27-
* `support`: to tell if the given data can be handled by this specific data persister
27+
* `support`: checks whether the given data is supported by this data persister
2828

2929
Here is an implementation example:
3030

@@ -54,10 +54,10 @@ final class BlogPostDataPersister implements DataPersisterInterface
5454
}
5555
```
5656

57-
If service autowiring and autoconfiguration are enabled (it's the case by default), you are done!
57+
If service autowiring and autoconfiguration are enabled (they are by default), you are done!
5858

5959
Otherwise, if you use a custom dependency injection configuration, you need to register the corresponding service and add the
60-
`api_platform.data_persister` tag to it. The `priority` attribute can be used to order persisters.
60+
`api_platform.data_persister` tag. The `priority` attribute can be used to order persisters.
6161

6262
```yaml
6363
# api/config/services.yaml

core/data-providers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ final class BlogPostCollectionDataProvider implements CollectionDataProviderInte
5858
}
5959
```
6060

61-
If you use the default configuration, the corresponding service will be automatically registered thanks to the [autowiring](https://symfony.com/doc/current/service_container/autowiring.html).
61+
If you use the default configuration, the corresponding service will be automatically registered thanks to [autowiring](https://symfony.com/doc/current/service_container/autowiring.html).
6262
To declare the service explicitly, or to set a custom priority, you can use the following snippet:
6363

6464
```yaml

core/design.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# General Design Considerations
2+
3+
Since you only need to describe the structure of the data to expose, API Platform is both [a "design-first" and "code-first"](https://swagger.io/blog/api-design/design-first-or-code-first-api-development/)
4+
API framework. However, the "design-first" methodology is strongly recommended: first you design the **public shape** of
5+
API endpoints.
6+
7+
To do so, you have to write a plain old PHP object representing the input and output of your endpoint. This is the class
8+
that is [marked with the `@ApiResource` annotation](../distribution/index.md).
9+
This class **doesn't have** to be mapped with Doctrine ORM, or any other persistence system. It must be simple (it's usually
10+
just a data structure with no or minimal behaviors) and will be automatically converted to [Hydra](extending-jsonld-context.md),
11+
[OpenAPI / Swagger](swagger.md) and [GraphQL](graphql.md) documentations or schemas by API Platform (there is a 1-1 mapping
12+
between this class and those docs).
13+
14+
Then, it's up to the developer to feed API Platform with an hydrated instance of this API resource object by implementing
15+
the [`DataProviderInterface`](data-providers.md). Basically, the data provider will query the persistence system (RDBMS,
16+
document or graph DB, external API...), and must hydrate and return the POPO that has been designed as mentioned above.
17+
18+
When updating a state (`POST`, `PUT`, `PATCH`, `DELETE` HTTP methods), it's up to the developer to properly persist the
19+
data provided by API Platform's resource object [hydrated by the serializer](serialization.md).
20+
To do so, there is another interface to implement: [`DataPersisterInterface`](data-persisters.md).
21+
22+
This class will read the API resource object (the one marked with `@ApiResource`) and:
23+
24+
* persist it directly in the database;
25+
* or hydrate a DTO then trigger a command;
26+
* or populate an event store;
27+
* or persist the data in any other useful way.
28+
29+
The logic of data persisters is the responsibility of application developers, and is **out of the API Platform's scope**.
30+
31+
For [Rapid Application Development](https://en.wikipedia.org/wiki/Rapid_application_development), convenience and prototyping,
32+
**if and only if the class marked with `@ApiResource` is also a Doctrine entity**, the developer can use the Doctrine
33+
ORM's data provider and persister implementations shipped with API Platform.
34+
35+
In this case, the public (`@ApiResource`) and internal (Doctrine entity) data model are shared. Then, API Platform will
36+
be able to query, filter, paginate and persist automatically data.
37+
This is approach is super-convenient and efficient, but is probably **not a good idea** for non-[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
38+
and/or large systems.
39+
Again, it's up to the developers to use, or to not use those built-in data providers/persisters depending of the business
40+
they are dealing with. API Platform makes it easy to create custom data providers and persisters, and to implement appropriate
41+
patterns such as [CQS](https://www.martinfowler.com/bliki/CommandQuerySeparation.html) or [CQRS](https://martinfowler.com/bliki/CQRS.html).
42+
43+
Last but not least, to create [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html)-based systems, a convenient
44+
approach is:
45+
46+
* to persist data in an event store using a custom [data persister](data-persisters.md)
47+
* to create projections in standard RDBMS (Postgres, MariaDB...) tables or views
48+
* to map those projections with read-only Doctrine entity classes **and** to mark those classes with `@ApiResource`
49+
50+
You can then benefit from the built-in Doctrine filters, sorting, pagination, auto-joins, etc provided by API Platform.

index.md

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@
1212
1. [Installing API Platform Core](core/getting-started.md#installing-api-platform-core)
1313
2. [Before Reading this Documentation](core/getting-started.md#before-reading-this-documentation)
1414
3. [Mapping the Entities](core/getting-started.md#mapping-the-entities)
15-
3. [Configuration](core/configuration.md)
16-
4. [Operations](core/operations.md)
15+
3. [General Design Considerations](core/design.md)
16+
4. [Configuration](core/configuration.md)
17+
5. [Operations](core/operations.md)
1718
1. [Enabling and Disabling Operations](core/operations.md#enabling-and-disabling-operations)
1819
2. [Configuring Operations](core/operations.md#configuring-operations)
1920
3. [Subresources](core/operations.md#subresources)
2021
4. [Creating Custom Operations and Controllers](core/operations.md#creating-custom-operations-and-controllers)
2122
1. [Recommended Method](core/operations.md#recommended-method)
2223
2. [Alternative Method](core/operations.md#alternative-method)
23-
5. [Overriding Default Order](core/default-order.md)
24-
6. [Filters](core/filters.md)
24+
6. [Overriding Default Order](core/default-order.md)
25+
7. [Filters](core/filters.md)
2526
1. [Doctrine ORM Filters](core/filters.md#doctrine-orm-filters)
2627
1. [Search Filter](core/filters.md#search-filter)
2728
2. [Date Filter](core/filters.md#date-filter)
@@ -42,7 +43,7 @@
4243
1. [Using Doctrine Filters](core/filters.md#using-doctrine-filters)
4344
2. [Overriding Extraction of Properties from the Request](core/filters.md#overriding-extraction-of-properties-from-the-request)
4445
4. [ApiFilter Annotation](core/filters.md#apifilter-annotation)
45-
7. [The Serialization Process](core/serialization.md)
46+
8. [The Serialization Process](core/serialization.md)
4647
1. [Overall Process](core/serialization.md#overall-process)
4748
2. [Available Serializers](core/serialization.md#available-serializers)
4849
3. [The Serialization Context, Groups and Relations](core/serialization.md#the-serialization-context-groups-and-relations)
@@ -58,35 +59,35 @@
5859
9. [Decorating a Serializer and Add Extra Data](core/serialization.md#decorating-a-serializer-and-add-extra-data)
5960
10. [Entity Identifier Case](core/serialization.md#entity-identifier-case)
6061
11. [Embedding the JSON-LD Context](core/serialization.md#embedding-the-json-ld-context)
61-
8. [Validation](core/validation.md)
62+
9. [Validation](core/validation.md)
6263
1. [Using Validation Groups](core/validation.md#using-validation-groups)
6364
2. [Using Validation Groups on operations](core/validation.md#using-validation-groups-on-operations)
6465
3. [Dynamic Validation Groups](core/validation.md#dynamic-validation-groups)
6566
4. [Error Levels and Payload Serialization](core/validation.md#error-levels-and-payload-serialization)
66-
9. [Error Handling](core/errors.md)
67+
10. [Error Handling](core/errors.md)
6768
1. [Converting PHP Exceptions to HTTP Errors](core/errors.md#converting-php-exceptions-to-http-errors)
68-
10. [Pagination](core/pagination.md)
69+
11. [Pagination](core/pagination.md)
6970
1. [Disabling the Pagination](core/pagination.md#disabling-the-pagination)
7071
2. [Changing the Number of Items per Page](core/pagination.md#changing-the-number-of-items-per-page)
7172
3. [Partial Pagination](core/pagination.md#partial-pagination)
72-
11. [The Event System](core/events.md)
73-
12. [Content Negotiation](core/content-negotiation.md)
73+
12. [The Event System](core/events.md)
74+
13. [Content Negotiation](core/content-negotiation.md)
7475
1. [Enabling Several Formats](core/content-negotiation.md#enabling-several-formats)
7576
2. [Registering a Custom Serializer](core/content-negotiation.md#registering-a-custom-serializer)
7677
3. [Creating a Responder](core/content-negotiation.md#creating-a-responder)
7778
4. [Writing a Custom Normalizer](core/content-negotiation.md#writing-a-custom-normalizer)
78-
13. [Using External JSON-LD Vocabularies](core/external-vocabularies.md)
79-
14. [Extending JSON-LD context](core/extending-jsonld-context.md)
80-
15. [Data Providers](core/data-providers.md)
79+
14. [Using External JSON-LD Vocabularies](core/external-vocabularies.md)
80+
15. [Extending JSON-LD context](core/extending-jsonld-context.md)
81+
16. [Data Providers](core/data-providers.md)
8182
1. [Custom Collection Data Provider](core/data-providers.md#custom-collection-data-provider)
8283
2. [Custom Item Data Provider](core/data-providers.md#custom-item-data-provider)
8384
3. [Injecting the Serializer in an `ItemDataProvider`](core/data-providers.md#injecting-the-serializer-in-an-itemdataprovider)
84-
16. [Data Persisters](core/data-persisters.md)
85-
17. [Extensions](core/extensions.md)
85+
17. [Data Persisters](core/data-persisters.md)
86+
18. [Extensions](core/extensions.md)
8687
1. [Custom Extension](core/extensions.md#custom-extension)
8788
2. [Filter upon the current user](core/extensions.md#example)
88-
18. [Security](core/security.md)
89-
19. [Performance](core/performance.md)
89+
19. [Security](core/security.md)
90+
20. [Performance](core/performance.md)
9091
1. [Enabling the Built-in HTTP Cache Invalidation System](core/performance.md#enabling-the-builtin-http-cache-invalidation-system)
9192
2. [Enabling the Metadata Cache](core/performance.md#enabling-the-metadata-cache)
9293
3. [Using PPM (PHP-PM)](core/performance.md#using-ppm-php-pm)
@@ -98,32 +99,32 @@
9899
3. [Override at Resource and Operation Level](core/performance.md#override-at-resource-and-operation-level)
99100
4. [Disable Eager Loading](core/performance.md#disable-eager-loading)
100101
3. [Partial Pagination](core/performance.md#partial-pagination)
101-
20. [Operation Path Naming](core/operation-path-naming.md)
102+
21. [Operation Path Naming](core/operation-path-naming.md)
102103
1. [Configuration](core/operation-path-naming.md#configuration)
103104
2. [Create a Custom Operation Path Naming](core/operation-path-naming.md#create-a-custom-operation-path-resolver)
104105
1. [Defining the Operation Path Naming](core/operation-path-naming.md#defining-the-operation-path-resolver)
105106
2. [Registering the Service](core/operation-path-naming.md#registering-the-service)
106107
3. [Configure it](core/operation-path-naming.md#configure-it)
107-
21. [Accept application/x-www-form-urlencoded Form Data](core/form-data.md)
108-
22. [FOSUserBundle Integration](core/fosuser-bundle.md)
108+
22. [Accept application/x-www-form-urlencoded Form Data](core/form-data.md)
109+
23. [FOSUserBundle Integration](core/fosuser-bundle.md)
109110
1. [Installing the Bundle](core/fosuser-bundle.md#installing-the-bundle)
110111
2. [Enabling the Bridge](core/fosuser-bundle.md#enabling-the-bridge)
111112
3. [Creating a `User` Entity with Serialization Groups](core/fosuser-bundle.md#creating-a-user-entity-with-serialization-groups)
112-
23. [Adding a JWT authentication using LexikJWTAuthenticationBundle](core/jwt.md)
113+
24. [Adding a JWT authentication using LexikJWTAuthenticationBundle](core/jwt.md)
113114
1. [Testing with Swagger](core/jwt.md#testing-with-swagger)
114115
2. [Testing with Behat](core/jwt.md#testing-with-behat)
115-
24. [NelmioApiDocBundle integration](core/nelmio-api-doc.md)
116-
25. [AngularJS Integration](core/angularjs-integration.md)
116+
25. [NelmioApiDocBundle integration](core/nelmio-api-doc.md)
117+
26. [AngularJS Integration](core/angularjs-integration.md)
117118
1. [Restangular](core/angularjs-integration.md#restangular)
118119
2. [ng-admin](core/angularjs-integration.md#ng-admin)
119-
26. [Swagger Support](core/swagger.md)
120+
27. [Swagger Support](core/swagger.md)
120121
1. [Override Swagger documentation](core/swagger.md#override-swagger-documentation)
121-
27. [GraphQL Support](core/graphql.md)
122+
28. [GraphQL Support](core/graphql.md)
122123
1. [Overall View](core/graphql.md#overall-view)
123124
2. [Enabling GraphQL](core/graphql.md#enabling-graphql)
124125
3. [GraphiQL](core/graphql.md#graphiql)
125-
28. [Handling Data Transfer Objects (DTOs)](core/dto.md)
126-
29. [Handling File Upload with VichUploaderBundle](core/file-upload.md)
126+
29. [Handling Data Transfer Objects (DTOs)](core/dto.md)
127+
30. [Handling File Upload with VichUploaderBundle](core/file-upload.md)
127128

128129
## The Schema Generator Component: Generate Data Models from Open Vocabularies
129130

0 commit comments

Comments
 (0)