When exposing API to external services, sticking to agreed schema is crucial. Decent API consumers will most probably validate incoming data.
How will your API look like when you won't give data in proper form as promised?
Without any additional effort you can validate JSON and XML data according to schemas.
At most JSON Schema draft 4 is supported by underlying justinrainbow/json-schema library. Simplest JSON schema below:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
}
},
"additionalProperties": false
}
XML schema validation is provided by PHP XML extension. Simplest XSD below:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xs:element name="testObjects" type="testObjects"/>
<xs:complexType name="testObjects">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="1" name="testObject" type="object"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="object">
<xs:sequence>
<xs:element minOccurs="1" name="string-property" type="xs:string"/>
<xs:element minOccurs="1" name="int-property" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
If your endpoint supports multiple formats divided by returned status codes you can setup it all in one single @ResponseSchemaValidator
annotation like:
/**
* @Route("/", name="my_route")
*
* @ResponseSchemaValidator(
* json={
* 200="@AppBundle/Resources/response_schema/my_route_200.json",
* 500="@AppBundle/Resources/response_schema/my_route_500.json"
* },
* xml={
* 200="@AppBundle/Resources/response_schema/my_route_200.xsd",
* 500="@AppBundle/Resources/response_schema/my_route_500.xsd"
* }
* )
*/
public function indexAction(): Response
If you use JSON validation only you can disable XML listener setting disable_xml_check_schema_subscriber
to true
.
The same goes for JSON disable_json_check_schema_subscriber
.
Normally failed schema validation results in \RuntimeException
which will most likely be translated into HTTP status 500 response.
If you need to alter this behaviour you can set your own listener using failed_schema_check_listener_service_id
and implementing onCheckResult
accepting Spiechu\SymfonyCommonsBundle\Event\ResponseSchemaCheck\CheckResult
object as parameter.
/**
* @param CheckResult $checkResult
*/
public function onCheckResult(CheckResult $checkResult): void
If you just want to add something custom just use your own listener listening on spiechu_symfony_commons.event.response_schema_check.check_result
event.
Some weird edge cases may result in format not found. Normally \RuntimeException
is thrown.
You can suppress this using throw_exception_when_format_not_found
set to false
.
Implementing validator for custom format
Imagine you want to validate CSV responses.
You need to create listener for spiechu_symfony_commons.event.response_schema_check.check_schema_csv
event accepting Spiechu\SymfonyCommonsBundle\Event\ResponseSchemaCheck\CheckRequest
object.
Listener needs to set Spiechu\SymfonyCommonsBundle\Service\SchemaValidator\ValidationResult
object into CheckRequest
.