API Platform 4.1 - Documentation at the heart of API Discoverability
API Platform is a framework centered around API standards, assisting developers in maintaining and utilizing these specifications. With API Platform 4.1, our focus is on enhancing support for the Hydra specification, OpenAPI, and JSON Schema.
# OpenAPI improvements
# Create several versions of a specification
You can now decline a same OpenAPI specification in multiple versions using the x-apiplatform-tags
tag:
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
#[GetCollection(openapi: new Operation(extensionProperties: [OpenApiFactory::API_PLATFORM_TAG => ['customer', 'developer']]))]
#[Post(openapi: new Operation(extensionProperties: [OpenApiFactory::API_PLATFORM_TAG => 'developer']))]
class Book {}
Then, either use the query parameter for the web version such as /docs?filter_tags[]=customer
or through the command line:
bin/console api:openapi:export --filter-tags=customer
This will produce a specification including only the operations matching your tag.
# Error schemas
With the improvement of our implementation of the Problem Detail specification in 4.0 and the ability to declare error as API Resources, we were one step closer to being able to document their JSON Schema. Since 3.4, you could already add errors to an operation’s documentation:
#[GetCollection(errors: [MyDomainException::class])]
class Greeting
{
// ...
}
This is now also enabled for every standard responses we support. For example a 422 Unprocessable entity
is now documented in every supported formats:
The JSON Schema associated with an error is also available with more friendly documentation:
# Hydra
The hydra patch changes default hydra:title
and uses the resource shortname
. Previously the hydra:title
information was duplicating the hydra:description
. The rdfs:label
got removed from the hydra:Class
as it was used instead of the hydra:title
. On hydra:property
rdfs:label
got renamed to label
as the rdfs
namespace is available in the context.
The ApiPlatform\Metadata\ErrorResource
and the ConstraintViolation
(ValidationException
class) are now generated directly from your PHP classes, only our ConstraintViolationList
is hard-written and documents the ConstraintViolation::violation
property. Therefore, your own error resources are also documented. On top of that, we now set the rdfs:subClassOf
to hydra:Error
.
It’s possible to hide an hydra operation (#[Get(hideHydraOperation: true)]
), and to skip a documented property using
#[ApiProperty(hydra: false)]
on a class.
On write operations, we added the expectsHeader field.
# Query Parameters and filtering
You can now let API Platform send a validation error when a query parameter is used on your API but you don’t support it by enabling strictQueryParameters: true
(globally using defaults
, on a resource or an operation). On top of that vinceAmstoutz and myself worked on improving the declaration of Symfony filters within query parameters.
#[GetCollection(
parameters: [
'enabled' => new QueryParameter(
filter: new BooleanFilter(),
property: 'active',
),
],
)]
#[ORM\Entity]
class FilteredBooleanParameter
{
}
Previously, a filter had to be a Symfony service; now it’s a static instance. A filter is a callback where you should have everything needed to do the filtering:
public function apply(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void;
Therefore you shouldn’t need any dependency injection. We’ll never deprecate using a service but we feel that this approach is more user-friendly and it also improves to decoupling of the documentation. For that you get two new interfaces ApiPlatform\Metadata\JsonSchemaFilterInterface
and ApiPlatform\Metadata\OpenApiParameterFilterInterface
:
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
use ApiPlatform\Metadata\JsonSchemaFilterInterface;
public class MyDateFilter implements JsonSchemaFilterInterface, OpenApiParameterFilterInterface
/**
* @return array<string, string>
*/
public function getSchema(Parameter $parameter): array
{
return ['type' => 'date'];
}
public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null
{
$in = $parameter instanceof QueryParameter ? 'query' : 'header';
$key = $parameter->getKey();
return [
new OpenApiParameter(name: $key.'[after]', in: $in),
new OpenApiParameter(name: $key.'[before]', in: $in),
new OpenApiParameter(name: $key.'[strictly_after]', in: $in),
new OpenApiParameter(name: $key.'[strictly_before]', in: $in),
];
}
OpenAPI Parameter will use the getSchema
if none is provided. This gives more control on a filter without having to copy that filter to just change a part of the documentation.
# Laravel
Along Laravel 12 support (^4.0.19
), a BooleanFilter
was added, and we automatically register the model’s Policy when found. We improved the overall support of Eloquent. The default caching of our Metadata has been set to the file cache as it is more appropriate then using the global cache (you can still change this). Special thanks to toitzi and amermchaudhary for providing many fixes since the Laravel release!
# And more…
GromNaN from MongoDB improved the overall memory usage of our MongoDB collection provider! Elasticsearch 7 is supported again, we can configure GraphQl max query depth and max query complexity and so much more!
Check the full detailed release notes on Github.
Thanks to every contributor!
# What’s up next?
We’re working on adding more filters and refactoring our SearchFilter
. We will also focus on JSON Schema generation as they’re far from perfect, especially that we studied a nice optimisation where we mutualize Schemas with base schemas per formats. Take a sneak peak here. On the side we’re working on an Hypermedia HTTP Client that’s still in an experimentation phase.