Commit dc3ba2b1 authored by alexpott's avatar alexpott

Issue #1910658 by klausi: Implement entity validation API for REST entity resources.

parent bb654e16
...@@ -95,6 +95,9 @@ public function post($id, EntityInterface $entity = NULL) { ...@@ -95,6 +95,9 @@ public function post($id, EntityInterface $entity = NULL) {
throw new AccessDeniedHttpException(t('Access denied on creating field @field.', array('@field' => $field_name))); throw new AccessDeniedHttpException(t('Access denied on creating field @field.', array('@field' => $field_name)));
} }
} }
// Validate the received data before saving.
$this->validate($entity);
try { try {
$entity->save(); $entity->save();
watchdog('rest', 'Created entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id())); watchdog('rest', 'Created entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id()));
...@@ -159,6 +162,9 @@ public function patch($id, EntityInterface $entity = NULL) { ...@@ -159,6 +162,9 @@ public function patch($id, EntityInterface $entity = NULL) {
$original_entity->set($field_name, $field->getValue()); $original_entity->set($field_name, $field->getValue());
} }
} }
// Validate the received data before saving.
$this->validate($original_entity);
try { try {
$original_entity->save(); $original_entity->save();
watchdog('rest', 'Updated entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id())); watchdog('rest', 'Updated entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id()));
...@@ -202,4 +208,28 @@ public function delete($id) { ...@@ -202,4 +208,28 @@ public function delete($id) {
} }
throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id))); throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
} }
/**
* Verifies that the whole entity does not violate any validation constraints.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* If validation errors are found.
*/
protected function validate(EntityInterface $entity) {
$violations = $entity->validate();
if (count($violations) > 0) {
$message = "Unprocessable Entity: validation failed.\n";
foreach ($violations as $violation) {
$message .= $violation->getPropertyPath() . ': ' . $violation->getMessage() . "\n";
}
// Instead of returning a generic 400 response we use the more specific
// 422 Unprocessable Entity code from RFC 4918. That way clients can
// distinguish between general syntax errors in bad serializations (code
// 400) and semantic errors in well-formed requests (code 422).
throw new HttpException(422, $message);
}
}
} }
...@@ -106,6 +106,15 @@ public function testCreate() { ...@@ -106,6 +106,15 @@ public function testCreate() {
$this->assertResponse(403); $this->assertResponse(403);
$this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.');
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
$entity->set('uuid', $this->randomName(129));
$invalid_serialized = $serializer->serialize($entity, $this->defaultFormat);
$response = $this->httpRequest('entity/' . $entity_type, 'POST', $invalid_serialized, $this->defaultMimeType);
$this->assertResponse(422);
$error = drupal_json_decode($response);
$this->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: This value is too long. It should have <em class=\"placeholder\">128</em> characters or less.\n");
// Try to create an entity without proper permissions. // Try to create an entity without proper permissions.
$this->drupalLogout(); $this->drupalLogout();
$this->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType); $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
......
...@@ -124,6 +124,15 @@ public function testPatchUpdate() { ...@@ -124,6 +124,15 @@ public function testPatchUpdate() {
$loaded_entity = entity_load($entity_type, 9999, TRUE); $loaded_entity = entity_load($entity_type, 9999, TRUE);
$this->assertFalse($loaded_entity, 'Entity 9999 was not created.'); $this->assertFalse($loaded_entity, 'Entity 9999 was not created.');
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
$entity->set('uuid', $this->randomName(129));
$invalid_serialized = $serializer->serialize($entity, $this->defaultFormat);
$response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $invalid_serialized, $this->defaultMimeType);
$this->assertResponse(422);
$error = drupal_json_decode($response);
$this->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: This value is too long. It should have <em class=\"placeholder\">128</em> characters or less.\n");
// Try to update an entity without proper permissions. // Try to update an entity without proper permissions.
$this->drupalLogout(); $this->drupalLogout();
$this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, $this->defaultMimeType); $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, $this->defaultMimeType);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment