Skip to content

Commit

Permalink
Merge 3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Nov 24, 2023
2 parents 814deaf + ea06124 commit 4072445
Show file tree
Hide file tree
Showing 32 changed files with 216 additions and 106 deletions.
2 changes: 1 addition & 1 deletion admin/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To use it, use the `OpenApiAdmin` component, with the entrypoint of the API and
import { OpenApiAdmin } from "@api-platform/admin";

export default () => (
<OpenApiAdmin entrypoint="https://demo.api-platform.com" docEntrypoint="https://demo.api-platform.com/docs.json" />
<OpenApiAdmin entrypoint="https://demo.api-platform.com" docEntrypoint="https://demo.api-platform.com/docs.jsonopenapi" />
);
```

Expand Down
2 changes: 1 addition & 1 deletion admin/real-time-mercure.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { OpenApiAdmin } from "@api-platform/admin";
export default () => (
<OpenApiAdmin
entrypoint="https://demo.api-platform.com"
docEntrypoint="https://demo.api-platform.com/docs.json"
docEntrypoint="https://demo.api-platform.com/docs.jsonopenapi"
mercure={{ hub: "https://mercure.rocks/hub" }}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion core/content-negotiation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Using the raw JSON or raw XML formats is discouraged, prefer using JSON-LD inste

API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://tools.ietf.org/html/rfc5789) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), Hydra and JSON:API error formats.

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/formats?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Formats screencast"><br>Watch the Formats screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/formats?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Formats screencast"><br>Watch the Formats screencast</a></p>

API Platform will automatically detect the best resolving format depending on:

Expand Down
141 changes: 138 additions & 3 deletions core/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,39 @@ API Platform automatically sends the appropriate HTTP status code to the client:
unexpected ones. It also provides a description of the error in [the Hydra error format](https://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors)
or in the format described in the [RFC 7807](https://tools.ietf.org/html/rfc7807), depending of the format selected during the [content negotiation](content-negotiation.md).

## Converting PHP Exceptions to HTTP Errors
# Errors

## Backward compatibility with < 3.1

Use the following configuration:

```yaml
api_platform:
defaults:
rfc_7807_compliant_errors: false
```
This can also be configured on an `ApiResource` or in an `HttpOperation`, for example:

```php
#[ApiResource(extraProperties: ['rfc_7807_compliant_errors' => false])
```

## Exception status code decision

There are many ways of configuring the exception status code we recommend reading the guides on how to use an [Error Provider](/docs/guides/error-provider) or create an [Error Resource](/docs/guides/error-resource).

1. we look at `exception_to_status` and take one if there's a match
2. If your exception is a `Symfony\Component\HttpKernel\Exception\HttpExceptionInterface` we get its status.
3. If the exception is a `ApiPlatform\Metadata\Exception\ProblemExceptionInterface` and there is a status we use it
4. Same for `ApiPlatform\Metadata\Exception\HttpExceptionInterface`
5. We have some defaults:
- `Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface` => 400
- `ApiPlatform\Validator\Exception\ValidationException` => 422
6. the status defined on an `ErrorResource`
7. 500 is the fallback

## Exception to status

The framework also allows you to configure the HTTP status code sent to the clients when custom exceptions are thrown
on an API Platform resource operation.
Expand Down Expand Up @@ -101,14 +133,14 @@ the error will be returned in this format as well:
}
```

## Message Scope
### Message Scope

Depending on the status code you use, the message may be replaced with a generic one in production to avoid leaking unwanted information.
If your status code is >= 500 and < 600, the exception message will only be displayed in debug mode (dev and test). In production, a generic message matching the status code provided will be shown instead. If you are using an unofficial HTTP code, a general message will be displayed.

In any other cases, your exception message will be sent to end users.

## Fine-grained Configuration
### Fine-grained Configuration

The `exceptionToStatus` configuration can be set on resources and operations:

Expand Down Expand Up @@ -140,3 +172,106 @@ class Book

Exceptions mappings defined on operations take precedence over mappings defined on resources, which take precedence over
the global config.

## Control your exceptions

With `rfc_7807_compliant_errors` a few things happen. First Hydra exception are compatible with the JSON Problem specification. Default exception that are handled by API Platform in JSON will be returned as `application/problem+json`.

To customize the API Platform response, replace the `api_platform.state.error_provider` with your own provider:

```php
<?php
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ApiResource\Error;
use ApiPlatform\State\ProviderInterface;
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
#[AsAlias('api_platform.state.error_provider')]
#[AsTaggedItem('api_platform.state.error_provider')]
final class ErrorProvider implements ProviderInterface
{
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$request = $context['request'];
$format = $request->getRequestFormat();
$exception = $request->attributes->get('exception');
/** @var \ApiPlatform\Metadata\HttpOperation $operation */
$status = $operation->getStatus() ?? 500;
// You don't have to use this, you can use a Response, an array or any object (preferably a resource that API Platform can handle).
$error = Error::createFromException($exception, $status);
// care about hiding informations as this can be a security leak
if ($status >= 500) {
$error->setDetail('Something went wrong');
}
return $error;
}
}
```

```yaml
api_platform.state.error_provider:
class: 'App\State\ErrorProvider'
tags:
- key: 'api_platform.state.error_provider'
name: 'api_platform.state_provider'
```

Note that our validation exception have their own error provider at:

```yaml
api_platform.validator.state.error_provider:
tags:
- key: 'api_platform.validator.state.error_provider'
name: 'api_platform.state_provider'
```

## Domain exceptions

Another way of having full control over domain exceptions is to create your own Error resource:

```php
<?php
namespace App\ApiResource;
use ApiPlatform\Metadata\ErrorResource;
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
#[ErrorResource]
class Error extends \Exception implements ProblemExceptionInterface
{
public function getType(): string
{
return 'teapot';
}
public function getTitle(): ?string
{
return null;
}
public function getStatus(): ?int
{
return 418;
}
public function getDetail(): ?string
{
return 'I am teapot';
}
public function getInstance(): ?string
{
return null;
}
}
```

We recommend using the `\ApiPlatform\Metadata\Exception\ProblemExceptionInterface` and the `\ApiPlatform\Metadata\Exception\HttpExceptionInterface`. For security reasons we add: `normalizationContext: ['ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString']]` because you usually don't want these. You can override this context value if you want.
4 changes: 2 additions & 2 deletions core/extending-jsonld-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## JSON-LD

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/json-ld?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="JSON-LD screencast"><br>Watch the JSON-LD screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/json-ld?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="JSON-LD screencast"><br>Watch the JSON-LD screencast</a></p>

API Platform provides the possibility to extend the JSON-LD context of properties. This allows you to describe JSON-LD-typed
values, inverse properties using the `@reverse` keyword and you can even overwrite the `@id` property this way. Everything you define
Expand Down Expand Up @@ -63,7 +63,7 @@ Note that you do not have to provide the `@id` attribute. If you do not provide

## Hydra

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/hydra?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Hydra screencast"><br>Watch the Hydra screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/hydra?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Hydra screencast"><br>Watch the Hydra screencast</a></p>

It's also possible to replace the Hydra context used by the documentation generator:

Expand Down
2 changes: 1 addition & 1 deletion core/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ For instance, if you want to send a mail after a resource has been persisted, bu

To replace existing API Platform services with your decorators, [check out how to decorate services](https://symfony.com/doc/current/service_container/service_decoration.html).

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform-security/service-decoration?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Service Decoration screencast"><br>Watch the Service Decoration screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform-security/service-decoration?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Service Decoration screencast"><br>Watch the Service Decoration screencast</a></p>
2 changes: 1 addition & 1 deletion core/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ By default, all filters are disabled. They must be enabled explicitly.
When a filter is enabled, it automatically appears in the [OpenAPI](openapi.md) and [GraphQL](graphql.md) documentations.
It is also automatically documented as a `hydra:search` property for JSON-LD responses.

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/filters?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Filtering and Searching screencast"><br>Watch the Filtering & Searching screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/filters?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Filtering and Searching screencast"><br>Watch the Filtering & Searching screencast</a></p>

## Doctrine ORM and MongoDB ODM Filters

Expand Down
2 changes: 1 addition & 1 deletion core/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ and what [JSON-LD](https://json-ld.org/) and [Hydra](https://www.hydra-cg.com/)

## Mapping the Entities

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/api-resource?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Create an API Resource screencast"><br>Watch the Create an API Resource screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/api-resource?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Create an API Resource screencast"><br>Watch the Create an API Resource screencast</a></p>

API Platform is able to automatically expose entities mapped as "API resources" through a REST API supporting CRUD
operations.
Expand Down
2 changes: 1 addition & 1 deletion core/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ This bundle is extensively tested (unit and functional). The [`Fixtures/` direct

## Screencasts

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/tracks/rest?cid=apip#api-platform"><img src="../distribution/images/symfonycasts-player.png" alt="SymfonyCasts, API Platform screencasts"></a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/tracks/rest?cid=apip#api-platform"><img src="/docs/distribution/images/symfonycasts-player.png" alt="SymfonyCasts, API Platform screencasts"></a></p>

The easiest and funniest way to learn how to use API Platform is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform)!
4 changes: 2 additions & 2 deletions core/jwt.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The tokens are signed by the server's key, so the server is able to verify that
API Platform allows to easily add a JWT-based authentication to your API using [LexikJWTAuthenticationBundle](https://github.com/lexik/LexikJWTAuthenticationBundle).

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/symfony-rest4/json-web-token?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="JWT screencast"><br>Watch the LexikJWTAuthenticationBundle screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/symfony-rest4/json-web-token?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="JWT screencast"><br>Watch the LexikJWTAuthenticationBundle screencast</a></p>

## Installing LexikJWTAuthenticationBundle

Expand Down Expand Up @@ -116,7 +116,7 @@ also want to [configure Swagger UI for JWT authentication](#documenting-the-auth

### Adding Authentication to an API Which Uses a Path Prefix

If your API uses a [path prefix](https://symfony.com/doc/current/routing/external_resources.html#prefixing-the-urls-of-imported-routes), the security configuration would look something like this instead:
If your API uses a [path prefix](https://symfony.com/doc/current/routing/external_resources.html#route-groups-and-prefixes), the security configuration would look something like this instead:

```yaml
# api/config/packages/security.yaml
Expand Down
6 changes: 4 additions & 2 deletions core/mongodb.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ docker compose build php
Add a MongoDB image to the docker-compose file:

```yaml
# docker-compose.yml
# ...
# compose.yaml

services:
# ...
db-mongodb:
# In production, you may want to use a managed database service
image: mongo
Expand Down
8 changes: 4 additions & 4 deletions core/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ API Platform natively supports the [OpenAPI](https://www.openapis.org/) API spec

![Screenshot](../distribution/images/swagger-ui-1.png)

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/open-api-spec?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="OpenAPI screencast"><br>Watch the OpenAPI screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/open-api-spec?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="OpenAPI screencast"><br>Watch the OpenAPI screencast</a></p>

The specification of the API is available at the `/docs.json` path.
The specification of the API is available at the `/docs.jsonopenapi` path.
By default, OpenAPI v3 is used.
You can also get an OpenAPI v3-compliant version thanks to the `spec_version` query parameter: `/docs.json?spec_version=3`
You can also get an OpenAPI v3-compliant version thanks to the `spec_version` query parameter: `/docs.jsonopenapi?spec_version=3`

It also integrates a customized version of [Swagger UI](https://swagger.io/swagger-ui/) and [ReDoc](https://rebilly.github.io/ReDoc/), some nice tools to display the
API documentation in a user friendly way.
Expand Down Expand Up @@ -583,7 +583,7 @@ You may want to copy the [one shipped with API Platform](https://github.com/api-
[AWS API Gateway](https://aws.amazon.com/api-gateway/) supports OpenAPI partially, but it [requires some changes](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html).
API Platform provides a way to be compatible with Amazon API Gateway.

To enable API Gateway compatibility on your OpenAPI docs, add `api_gateway=true` as query parameter: `http://www.example.com/docs.json?api_gateway=true`.
To enable API Gateway compatibility on your OpenAPI docs, add `api_gateway=true` as query parameter: `http://www.example.com/docs.jsonopenapi?api_gateway=true`.
The flag `--api-gateway` is also available through the command-line.

## OAuth
Expand Down
16 changes: 8 additions & 8 deletions core/operation-path-naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ Pre-registered resolvers are available and can easily be overridden.

There are two pre-registered operation path naming services:

Service name | Entity name | Path result
------------------------------------------------------|--------------|----------------
`api_platform.path_segment_name_generator.underscore` | `MyResource` | `/my_resources`
`api_platform.path_segment_name_generator.dash` | `MyResource` | `/my-resources`
Service name | Entity name | Path result
---------------------------------------------------------------|--------------|----------------
`api_platform.metadata.path_segment_name_generator.underscore` | `MyResource` | `/my_resources`
`api_platform.metadata.path_segment_name_generator.dash` | `MyResource` | `/my-resources`

The default resolver is `api_platform.path_segment_name_generator.underscore`.
The default resolver is `api_platform.metadata.path_segment_name_generator.underscore`.
To change it to the dash resolver, add the following lines to `api/config/packages/api_platform.yaml`:

```yaml
# api/config/packages/api_platform.yaml
api_platform:
path_segment_name_generator: api_platform.path_segment_name_generator.dash
path_segment_name_generator: api_platform.metadata.path_segment_name_generator.dash
```
## Create a Custom Operation Path Resolver
Expand All @@ -27,14 +27,14 @@ Let's assume we need URLs without separators (e.g. `api.tld/myresources`)

### Defining the Operation Segment Name Generator

Make sure the custom segment generator implements [`ApiPlatform\Operation\PathSegmentNameGeneratorInterface`](https://github.com/api-platform/core/blob/main/src/Operation/PathSegmentNameGeneratorInterface.php):
Make sure the custom segment generator implements [`ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface`](https://github.com/api-platform/core/blob/main/src/Metadata/Operation/PathSegmentNameGeneratorInterface.php):

```php
<?php
// api/src/Operation/SingularPathSegmentNameGenerator.php
namespace App\Operation;
use ApiPlatform\Operation\PathSegmentNameGeneratorInterface;
use ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface;
class SingularPathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
Expand Down
2 changes: 1 addition & 1 deletion core/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
API Platform relies on the concept of operations. Operations can be applied to a resource exposed by the API. From
an implementation point of view, an operation is a link between a resource, a route and its related controller.

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/operations?cid=apip"><img src="../distribution/images/symfonycasts-player.png" alt="Operations screencast"><br>Watch the Operations screencast</a></p>
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/operations?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Operations screencast"><br>Watch the Operations screencast</a></p>

API Platform automatically registers typical [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations
and describes them in the exposed documentation (Hydra and Swagger). It also creates and registers routes corresponding
Expand Down
Loading

0 comments on commit 4072445

Please sign in to comment.