Skip to main content

Input validation

info

While Charon was built framework agnostic, in this documentation we assume you are using our Laravel branch.

Input validation

All generated resources have a 'validate' method that checks if the provided content matches the validation rules. The validate() method takes a Context object to specify which validation rules should be checked. The validate() method throws a ResourceValidationException that can be transformed in an array of validation error messages.

public function store(Request $request)
{
$writeContext = $this->getContext(Action::CREATE);
$inputResource = $this->bodyToResource($writeContext);

try {
$inputResource->validate($writeContext);

// also see if we can create this entity.
$this->authorizeCreateFromResource($request, $inputResource);

} catch (ResourceValidationException $e) {
return $this->getValidationErrorResponse($e);
}

[...]
}

/**
* @param ResourceValidationException $e
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function getValidationErrorResponse(ResourceValidationException $e)
{
$errors = [];
foreach ($e->getMessages()->toMap() as $fieldErrorMessages) {
foreach ($fieldErrorMessages as $fieldErrorMessage) {

$errors[] = [
'title' => 'Could not decode resource.',
'detail' => $fieldErrorMessage
];
}
}

return Response::json([ 'errors' => $errors ])
->header('Content-type', 'application/vnd.api+json')
->setStatusCode(422);
}

tip

This functionality is readily available in the CrudController trait that can be used in your Controller

Validation rules

The default field validation rules are simple:

/**
* Class PetDefinition
* @package CatLab\Petstore\Definitions
*/
class PetDefinition extends ResourceDefinition
{
/**
* PetDefinition constructor.
*/
public function __construct()
{
parent::__construct(Pet::class);

$this
->identifier('id')
->int()

->field('name')
->writeable()
->string()
->required()
->visible(true)

->field('status')
->enum([ 'available', 'reserved', 'sold' ])
->visible(true)

->field('colors')
->enum([ 'black', 'white', 'brown', 'purple' ])
->required()
->allowMultiple()
->visible(true);
}
}

This will create a Pet resource where:

  • 'name' must be provided and must be a string
  • 'status' is optionally provided, but when provided must be one of the provided enum values
  • 'colors' is required and must be an array where all values must be in the provided enum values list

Custom validators

In order to implement more complex validation rules, a Validator may be provided.

class PetDefinition extends ResourceDefinition
{
/**
* PetDefinition constructor.
*/
public function __construct()
{
parent::__construct(Pet::class);

$this
->identifier('id')
->int()

->relationship('photos', PhotoDefinition::class)
->many()
->visible()
->expandable()
->writeable()
->url('/api/v1/pets/{model.id}/photos')

->validator(new PetValidator())
;
}
}
class PetValidator implements Validator
{

/**
* @param $value
* @return mixed
* @throws RequirementValidationException
*/
public function validate($value)
{
/** @var RESTResource $value */

// A pet must have at least one picture.
$photos = $value->getProperties()->getFromName('photos')->getValue();

if ($photos === null || count($photos) < 2) {
throw ValidatorValidationException::make($this, $value);
}
}

/**
* @param ValidatorValidationException $exception
* @return Message
*/
public function getErrorMessage(ValidatorValidationException $exception) : Message
{
return new Message('Pets must have at least one photo.');
}
}