Skip to content

[Admin] Server-side validation documentation #1265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 48 additions & 46 deletions admin/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,30 @@

### AdminGuesser

`<AdminGuesser>` creates a complete Admin Context and Interface, rendering automatically an [`<AdminUI>` component](https://marmelab.com/react-admin/Admin.html#unplugging-the-admin-using-admincontext-and-adminui) for resources exposed by a web API documented with any format supported by `@api-platform/api-doc-parser` (for Hydra documented APIs,
use the [`<HydraAdmin>`component](admin/components.md#hydraadmin) instead). It also creates a [`schemaAnalyzer`](admin/components.md#schemaAnalyzer) context, where the schemaAnalyzer service (for getting information about the provided API documentation) is stored.
`<AdminGuesser>` renders automatically an [<Admin> component](https://marmelab.com/react-admin/Admin.html) for resources exposed by a web API documented with any format supported by `@api-platform/api-doc-parser` (for Hydra documented APIs,
use the [<HydraAdmin> component](components.md#hydraadmin) instead).
It also creates a [schema analyzer](components.md#schemaanalyzer) context, where the `schemaAnalyzer` service (for getting information about the provided API documentation) is stored.

The `<AdminGuesser>` renders all exposed resources by default, but you can choose what resource you want to render by passing [`<ResourceGuesser>` components](admin/components/#resourceguesser) as children.
`<AdminGuesser>` renders all exposed resources by default, but you can choose what resource you want to render by passing [<ResourceGuesser> components](components.md#resourceguesser) as children.
Deprecated resources are hidden by default, but you can add them back using an explicit `<ResourceGuesser>` component.

```javascript
//App.js
import { AdminGuesser, ResourceGuesser } from '@api-platform/admin';
// App.js
import { AdminGuesser, ResourceGuesser } from "@api-platform/admin";

const App = () => (
<AdminGuesser
entrypoint={entrypoint}
dataProvider={dataProvider}
authProvider={authProvider}>
<ResourceGuesser
name"books"
list={BooksList}
show={BooksShow}
edit={BooksEdit}
create={BooksCreate} />
<ResourceGuesser name"authors" />
</AdminGuesser>
<ResourceGuesser
name"books"
list={BooksList}
show={BooksShow}
edit={BooksEdit}
create={BooksCreate} />
<ResourceGuesser name"authors" />
</AdminGuesser>
)

export default App;
Expand All @@ -44,12 +45,12 @@ export default App;

### ResourceGuesser

Based on React-Admin's [`<Resource>` component](https://marmelab.com/react-admin/Resource.html), the ResourceGuesser provides default props [`<CreateGuesser>`](admin/components.md#createguesser), [`<ListGuesser>`](admin/components.md#listguesser), [`<EditGuesser>`](admin/components.md#editguesser) and [`<ShowGuesser>`](admin/components.md#showguesser).
Otherwise you can pass it your own CRUD components using `create`, `list`, `edit`, `show` props.
Based on React Admin [<Resource> component](https://marmelab.com/react-admin/Resource.html), `ResourceGuesser` provides default props [<CreateGuesser>](components.md#createguesser), [<ListGuesser>](components.md#listguesser), [<EditGuesser>](components.md#editguesser) and [<ShowGuesser>](components.md#showguesser).
Otherwise, you can pass it your own CRUD components using `create`, `list`, `edit`, `show` props.

```javascript
// App.js
import { AdminGuesser, ResourceGuesser } from '@api-platform/admin';
import { AdminGuesser, ResourceGuesser } from "@api-platform/admin";

const App = () => (
<AdminGuesser
Expand All @@ -76,23 +77,23 @@ export default App;
|------|--------|-------|----------|--------------------------|
| name | string | - | yes | endpoint of the resource |

You can also use props accepted by React-Admin's [`<Resource>` component](https://marmelab.com/react-admin/Resource.html). For example, the props `list`, `show`, `create` & `edit`.
You can also use props accepted by React Admin [<Resource> component](https://marmelab.com/react-admin/Resource.html). For example, the props `list`, `show`, `create` or `edit`.

## Page Components

### ListGuesser

Based on React-Admin's [`<List>`](https://marmelab.com/react-admin/List.html), ListGuesser displays a list of resources in a [`<Datagrid>`](https://marmelab.com/react-admin/List.html#the-datagrid-component), according to children passed to it (usually [`<FieldGuesser>`](admin/components/#fieldguesser) or any [`field` component](https://marmelab.com/react-admin/Fields.html#basic-fields)
available in React-Admin).
Based on React Admin [<List>](https://marmelab.com/react-admin/List.html), ListGuesser displays a list of resources in a [<Datagrid>](https://marmelab.com/react-admin/List.html#the-datagrid-component), according to children passed to it (usually [<FieldGuesser>](components.md#fieldguesser) or any [field component](https://marmelab.com/react-admin/Fields.html#basic-fields)
available in React Admin).

Use `hasShow` and `hasEdit` props if you want to display `show` and `edit` buttons (both set to `true` by default).

By default, `<ListGuesser>` comes with [`<Pagination>`](admin/components.md#pagination).
By default, `<ListGuesser>` comes with [<Pagination>](components.md#pagination).

```javascript
// BooksList.js
import { FieldGuesser, ListGuesser } from '@api-platform/admin';
import { ReferenceField, TextField } from 'react-admin';
import { FieldGuesser, ListGuesser } from "@api-platform/admin";
import { ReferenceField, TextField } from "react-admin";

export const BooksList = props => (
<ListGuesser {...props}>
Expand All @@ -113,16 +114,16 @@ export const BooksList = props => (
| resource | string | - | yes | endpoint of the resource |
| filters | element | - | no | filters that can be applied to the list |

You can also use props accepted by React-Admin's [`<List>`](https://marmelab.com/react-admin/List.html).
You can also use props accepted by React Admin [<List>](https://marmelab.com/react-admin/List.html).

### CreateGuesser

Displays a creation page for a single item. Uses React-Admin's [`<Create>`](https://marmelab.com/react-admin/Edit.html) and [`<SimpleForm>`](https://marmelab.com/react-admin/CreateEdit.html#the-simpleform-component).
For simple inputs, you can pass as children API Platform Admin's [`<InputGuesser>`](admin/components.md#inputguesser), or any React-Admin's [`Input components`](https://marmelab.com/react-admin/Inputs.html#input-components) for more complex inputs.
Displays a creation page for a single item. Uses React Admin [<Create>](https://marmelab.com/react-admin/CreateEdit.html) and [<SimpleForm>](https://marmelab.com/react-admin/CreateEdit.html#the-simpleform-component) components.
For simple inputs, you can pass as children API Platform Admin [<InputGuesser>](components.md#inputguesser), or any React Admin [Input components](https://marmelab.com/react-admin/Inputs.html#input-components) for more complex inputs.

```javascript
// BooksCreate.js
import { CreateGuesser, InputGuesser } from '@api-platform/admin';
import { CreateGuesser, InputGuesser } from "@api-platform/admin";

export const BooksCreate = props => (
<CreateGuesser {...props}>
Expand All @@ -137,22 +138,21 @@ export const BooksCreate = props => (

#### CreateGuesser Props

| Name | Type | Value | required | Description |
| Name | Type | Value | required | Description |
|----------|------------------|-------|----------|--------------------------|
| children | node or function | - | no | - |
| resource | string | - | yes | endpoint of the resource |

You can also use props accepted by React-Admin's [`<Create>`](https://marmelab.com/react-admin/Edit.html).
You can also use props accepted by React Admin [<Create>](https://marmelab.com/react-admin/CreateEdit.html).

### EditGuesser

Displays an edition page for a single item. Uses React-Admin's [`<Edit>`](https://marmelab.com/react-admin/Edit.html) and [`<SimpleForm>`](https://marmelab.com/react-admin/CreateEdit.html#the-simpleform-component) components.
For simple inputs, you can use API Platform Admin's [`<InputGuesser>`](admin/components.md#inputguesser), or any React-Admin's [`Input components`](https://marmelab.com/react-admin/Inputs.html#input-components) for more complex inputs.
Displays an edition page for a single item. Uses React Admin [<Edit>](https://marmelab.com/react-admin/CreateEdit.html) and [<SimpleForm>](https://marmelab.com/react-admin/CreateEdit.html#the-simpleform-component) components.
For simple inputs, you can use API Platform Admin [<InputGuesser>](components.md#inputguesser), or any React Admin [Input components](https://marmelab.com/react-admin/Inputs.html#input-components) for more complex inputs.

```javascript
// BooksEdit.js
import { EditGuesser, InputGuesser } from '@api-platform/admin';
import { EditGuesser, InputGuesser } from "@api-platform/admin";

export const BooksEdit = props => (
<EditGuesser {...props}>
Expand All @@ -172,15 +172,15 @@ export const BooksEdit = props => (
| children | node or function | - | no | - |
| resource | string | - | yes | endpoint of the resource |

You can also use props accepted by React-Admin's [`<Edit>`](https://marmelab.com/react-admin/Edit.html).
You can also use props accepted by React Admin [<Edit>](https://marmelab.com/react-admin/CreateEdit.html).

### ShowGuesser

Displays a detailed page for one item. Based on React-Admin's [`<Show>` component](https://marmelab.com/react-admin/Show.html). You can pass [`<FieldGuesser>`](admin/components.md#fieldguesser) as children for simple fields, or use any of React-Admin's [`Basic Fields`](https://marmelab.com/react-admin/Fields.html#basic-fields) for more complex fields.
Displays a detailed page for one item. Based on React Admin [<Show> component](https://marmelab.com/react-admin/Show.html). You can pass [<FieldGuesser>](components.md#fieldguesser) as children for simple fields, or use any of React Admin [basic fields](https://marmelab.com/react-admin/Fields.html#basic-fields) for more complex fields.

```javascript
// BooksShow.js
import { FieldGuesser, ShowGuesser } from '@api-platform/admin';
import { FieldGuesser, ShowGuesser } from "@api-platform/admin";

export const BooksShow = props => (
<ShowGuesser {...props}>
Expand All @@ -200,17 +200,17 @@ export const BooksShow = props => (
| children | node or function | - | no | - |
| resource | string | - | yes | endpoint of the resource |

You can also use props accepted by React-Admin's [`<Show>` component](https://marmelab.com/react-admin/Show.html).
You can also use props accepted by React Admin [<Show> component](https://marmelab.com/react-admin/Show.html).

## Hydra

### HydraAdmin

Creates a complete Admin Context and Interface, as [`<AdminGuesser>`](/admin/components.md#adminguesser), but configured specially for [Hydra](https://www.hydra-cg.com/). If you want to use other formats (see supported formats: `@api-platform/api-doc-parser`) use the [`<AdminGuesser>`](admin/components.md#adminguesser) instead.
Creates a complete Admin, as [`<AdminGuesser>`](components.md#adminguesser), but configured specially for [Hydra](https://www.hydra-cg.com/). If you want to use other formats (see supported formats: `@api-platform/api-doc-parser`) use [<AdminGuesser>](components.md#adminguesser) instead.

```javascript
// App.js
import { HydraAdmin, ResourceGuesser } from '@api-platform/admin';
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";

const App = () => (
<HydraAdmin
Expand All @@ -232,28 +232,30 @@ export default App;
|------------|--------|-------|----------|-----------------------|
| entrypoint | string | - | yes | entrypoint of the API |

### dataProvider
### Data Provider

Based on React-Admin's `Create`, `Delete`, `getList`, `getManyReference`, `GetOne`, `Update` methods, the `dataProvider` is used by API Platform Admin to communicate with the API. In addition, the specific `introspect` method parses your API documentation.
Note that the `dataProvider` can be overrided to fit your API needs.
Based on React Admin `create`, `delete`, `getList`, `getManyReference`, `getOne`, `update` methods, the `dataProvider` is used by API Platform Admin to communicate with the API. In addition, the specific `introspect` method parses your API documentation.
Note that the `dataProvider` can be overridden to fit your API needs.

### schemaAnalyzer
### Schema Analyzer

Analyses your resources and retrieves their types according to the [Schema.org](https://schema.org) vocabulary.

## Other Components

### Pagination

Set by default in the [`<ListGuesser/>` component](/admin/components.md#listguesser), the `<Pagination/> component` uses React-Admin's [`<Pagination>` component](https://marmelab.com/react-admin/List.html#pagination). By default, it renders 30 items per page and displays a navigation UI. If you want to change the number of items per page or disable the pagination, see the [`Pagination` documentation](https://api-platform.com/docs/core/pagination/#pagination).
Set by default in the [<ListGuesser> component](components.md#listguesser), the `Pagination` component uses React Admin [<Pagination> component](https://marmelab.com/react-admin/List.html#pagination).
By default, it renders 30 items per page and displays a navigation UI. If you want to change the number of items per page or disable the pagination, see the [Pagination documentation](../core/pagination.md).
It is also capable to handle partial pagination.

### FieldGuesser

Renders fields according to their types, using [`schemaAnalyzer`](/admin/components.md#schemaanalyzer). Based on React-Admin's [`<ReferenceField>` component](https://marmelab.com/react-admin/Fields.html#referencefield).
Renders fields according to their types, using the [schema analyzer](components.md#schemaanalyzer). Based on React Admin [field components](https://marmelab.com/react-admin/Fields.html).

```javascript
// BooksShow.js
import { FieldGuesser, ShowGuesser } from '@api-platform/admin';
import { FieldGuesser, ShowGuesser } from "@api-platform/admin";

export const BooksShow = props => (
<ShowGuesser {...props}>
Expand All @@ -272,11 +274,11 @@ export const BooksShow = props => (
|--------|--------|-------|----------|--------------------------|
| source | string | - | yes | endpoint of the resource |

You can also use props accepted by React-Admin's [`Basic Fields`](https://marmelab.com/react-admin/Fields.html#basic-fields).
You can also use props accepted by React Admin [basic fields](https://marmelab.com/react-admin/Fields.html#basic-fields).

### InputGuesser

Uses React-Admin's [`<ReferenceInput>`](https://marmelab.com/react-admin/Inputs.html#referenceinput) to generate inputs according to your API documentation (e.g. number HTML input for numbers, checkbox for booleans, selectbox for relationships...)
Uses React Admin [input components](https://marmelab.com/react-admin/Inputs.html) to generate inputs according to your API documentation (e.g. number HTML input for numbers, checkbox for booleans, selectbox for relationships...).

#### InputGuesser Props

Expand Down
Binary file added admin/images/required-field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added admin/images/submission-error-field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion admin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ according to the API-first paradigm.
API Platform Admin parses the API documentation then uses the awesome [React Admin](https://marmelab.com/react-admin/)
library to expose a nice, responsive, management interface (Create-Retrieve-Update-Delete) for all documented resource types.

You can **customize everything** by using provided React Admin and [Material UI](https://material-ui.com/) components, or by writing your custom [React](https://reactjs.org/) components.
You can **customize everything** by using provided React Admin and [Material UI](https://material-ui.com/) components, or by writing your custom [React](https://reactjs.org/) components.

## Features

Expand Down
68 changes: 68 additions & 0 deletions admin/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Validation

API Platform Admin manages automatically two types of validation: client-side validation and server-side (or submission) validation.

## Client-side Validation

If the API documentation indicates that a field is mandatory,
API Platform Admin will automatically add a [required client-side validation](https://marmelab.com/react-admin/CreateEdit.html#per-input-validation-built-in-field-validators).

For instance, with API Platform Core as backend, if you write the following:

```php
<?php
// api/src/Entity/Book.php

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

/**
* @ApiResource
*/
class Book
{
/**
* @Assert\NotBlank
*/
public ?string $title = null;
}
```

If you create a new book and touch the "Title" field without typing, you will see:

![Required title field](images/required-field.png)

## Server-side Validation

When the form is submitted and if submission errors are received,
API Platform Admin will automatically show the errors for the corresponding fields.

To do so, it uses the [submission validation](https://marmelab.com/react-admin/CreateEdit.html#submission-validation) feature of React Admin,
and the mapping between the response and the fields is done by the [schema analyzer](components.md#schemaanalyzer) with its method `getSubmissionErrors`.

API Platform Core is supported by default, but if you use another backend, you will need to override the `getSubmissionErrors` method.

For example if you have this code:

```php
<?php
// api/src/Entity/Book.php

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

/**
* @ApiResource
*/
class Book
{
/**
* @Assert\Isbn
*/
public ?string $isbn = null;
}
```

If you submit the form with an invalid ISBN, you will see:

![Submission error field](images/submission-error-field.png)
1 change: 1 addition & 0 deletions outline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ chapters:
- getting-started
- handling-relations
- schema.org
- validation
- authentication-support
- file-upload
- performance
Expand Down