Skip to content

Document the general design (RAD, CQRS, CQS, event sourcing...) and data persisters #518

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

Merged
merged 2 commits into from
Jul 4, 2018

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jun 29, 2018


* `persist`: to create or update the given data
* `delete`: to delete the given data
* `support`: to tell if the given data xcan be handled by this specific data persister
Copy link
Member

Choose a reason for hiding this comment

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

-xcan
+can

public function persist($data)
{
// call your persistence layer to save $data
return $data;
Copy link
Member

Choose a reason for hiding this comment

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

IIRC the return type is void.

Copy link
Member Author

Choose a reason for hiding this comment

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

It has been changed by api-platform/core#1967

is enabled by default. It is able to persist and delete objects that are also mapped as [Doctrine entities](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/basic-mapping.html).

However, you may want to store data to other persistence layers (ElasticSearch or MongoDB), to separate the public model
of the API and the internal model mapped with the database; or to use patterns such as [CQRS](https://martinfowler.com/bliki/CQRS.html)
Copy link
Member

Choose a reason for hiding this comment

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

, instead of ; and remove or?
Missing , after [CQRS](https://martinfowler.com/bliki/CQRS.html)?

Copy link
Member Author

Choose a reason for hiding this comment

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

No for CQRS, it's the description of CQRS :)

* `delete`: to delete the given data
* `support`: to tell if the given data can be handled by this specific data persister

Here is an example implementation:
Copy link
Member

Choose a reason for hiding this comment

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

Missing of?

Copy link
Member Author

Choose a reason for hiding this comment

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

why? Looks correct to me

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

sample implementation then?

Copy link
Member

Choose a reason for hiding this comment

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

Of course I'm not sure at all.

Copy link
Member Author

Choose a reason for hiding this comment

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

or "implementation example"

Copy link
Member Author

Choose a reason for hiding this comment

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

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

Otherwise, if you use a custom dependency injection configuration, you need to register the corresponding service and add the
`api_platform.data_persister` tag to it. As for collection data providers, the `priority` attribute can be used to order
Copy link
Member

Choose a reason for hiding this comment

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

As for collection data providers
As when you have more than one data provider?

Copy link
Member Author

Choose a reason for hiding this comment

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

it refers to the example in the "collection data providers" docs, maybe should I add a link

@dunglas dunglas force-pushed the data-persister branch 2 times, most recently from 9614431 to c1a1fe1 Compare June 29, 2018 15:36
@dunglas dunglas changed the title Add docs for data persisters Document general design considerations (RAD, CQRS, CQS, event sourcing...) and data persisters Jun 29, 2018
@dunglas dunglas changed the title Document general design considerations (RAD, CQRS, CQS, event sourcing...) and data persisters Document the general design (RAD, CQRS, CQS, event sourcing...) and data persisters Jun 29, 2018
Copy link

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

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

I like this kind of "design statement", makes things very clear 👍

@dunglas dunglas force-pushed the data-persister branch 3 times, most recently from 57c4882 to a272144 Compare June 29, 2018 16:02
@@ -12,16 +12,17 @@
1. [Installing API Platform Core](core/getting-started.md#installing-api-platform-core)
2. [Before Reading this Documentation](core/getting-started.md#before-reading-this-documentation)
3. [Mapping the Entities](core/getting-started.md#mapping-the-entities)
3. [Configuration](core/configuration.md)
Copy link
Contributor

Choose a reason for hiding this comment

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

You could put everything at 1 and don't bother with incrementing everything again, Markdown will do it for you 😉

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes but it’s less readable when reading the text file directly. Anyway we’re working on a TOC generator. Dropping this file will make contributions lot easier and less error prone.

Copy link
Contributor

@bendavies bendavies left a comment

Choose a reason for hiding this comment

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

Some general readability comments!


* `persist`: to create or update the given data
* `delete`: to delete the given data
* `support`: to tell if the given data can be handled by this specific data persister
Copy link
Contributor

Choose a reason for hiding this comment

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

Checks whether the given data is supported by this data persister.

}
```

If service autowiring and autoconfiguration are enabled (it's the case by default), you are done!
Copy link
Contributor

Choose a reason for hiding this comment

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

it's the case -> they are

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

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

Choose a reason for hiding this comment

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

remove to it

@@ -58,7 +58,8 @@ final class BlogPostCollectionDataProvider implements CollectionDataProviderInte
}
```

Then declare a Symfony service, for example:
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).
Copy link
Contributor

Choose a reason for hiding this comment

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

the autowiring -> autowiring

core/design.md Outdated

Then, it's up to the developer to feed API Platform with an hydrated instance of this API resource object by implementing
the [`DataProviderInterface`](data-providers.md). Basically, the data provider will query the persistence system (RDBMS,
document or graph DB, external API...), and must hydrate and return the POPO that has been designed in the first time.
Copy link
Contributor

Choose a reason for hiding this comment

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

in the first time -> as mentioned above

core/design.md Outdated
document or graph DB, external API...), and must hydrate and return the POPO that has been designed in the first time.

When updating a state (`POST`, `PUT`, `PATCH`, `DELETE` HTTP methods), it's up to the developer to persist properly the
data provided by API Platform's resource object [hydrated by the serializer](serialization.md) to the persistence system.
Copy link
Contributor

Choose a reason for hiding this comment

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

remove to the persistence system ?

core/design.md Outdated
data provided by API Platform's resource object [hydrated by the serializer](serialization.md) to the persistence system.
To do so, there is another interface to implement: [`DataPersisterInterface`](data-persisters.md).

Here is the reverse operation, this class will read the API resource object (the one marked with `@ApiResource`) and:
Copy link
Contributor

Choose a reason for hiding this comment

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

i'm not sure what Here is the reverse operation is meant to mean here, but doesn't make much sense.

core/design.md Outdated
* or populate an event store;
* or persist the data in any other useful way.

The logic to execute in data persisters is the responsibility of application developers, and is **out of the API Platform's
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic to execute in data persisters => The logic of custom data persisters

core/design.md Outdated
* to create projections in standard RDBMS (Postgres, MariaDB...) tables or views
* to map those projections with read-only Doctrine entity classes **and** to mark those classes with `@ApiResource`

Then you can benefit of all built-in Doctrine filters, sorting, pagination, auto-joins, etc provided by API Platform.
Copy link
Contributor

@bendavies bendavies Jul 1, 2018

Choose a reason for hiding this comment

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

Then you can benefit of all built-in -> You can then benefit from the built-in

core/design.md Outdated
@@ -0,0 +1,51 @@
# General Design Considerations

Because to create a working web API you only need to describe the structure of data to expose, API Platform is both [a "design-first"
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you only need to describe the structure of the data to expose, API Platform is...

@dunglas
Copy link
Member Author

dunglas commented Jul 4, 2018

Thank you very much for proof-reading @bendavies!

@dunglas dunglas dismissed meyerbaptiste’s stale review July 4, 2018 12:00

comments addressed

@dunglas dunglas merged commit 9900196 into api-platform:2.2 Jul 4, 2018
@dunglas dunglas deleted the data-persister branch July 4, 2018 12:10
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.

6 participants