Skip to content

docs: Revamp API Platform Admin docs #2141

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

Open
wants to merge 39 commits into
base: 4.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
505e82f
docs: revamp the admin index page
slax57 Mar 7, 2025
c873a42
docs: revamp the getting started section
slax57 Mar 7, 2025
db1cb96
docs: revamp schema.org doc
slax57 Mar 7, 2025
a9ac94e
docs: revamp the customizing the guessers doc
slax57 Mar 7, 2025
73a1fbe
docs: add new customizing the admin page
slax57 Mar 10, 2025
ade232e
docs: update handling relations doc
slax57 Mar 10, 2025
9dbcf96
docs: update validation doc
slax57 Mar 10, 2025
52a2656
docs: update file upload doc
slax57 Mar 12, 2025
aeb023a
docs: update performance doc
slax57 Mar 12, 2025
6d4f5a7
[no ci] docs: update components reference doc
slax57 Mar 12, 2025
24c87b8
docs: update authentication doc
slax57 Mar 12, 2025
8bfb644
fix linter issues
slax57 Mar 12, 2025
371d14c
doc: handling relations: add more links to RA doc
slax57 Mar 12, 2025
fe56516
comply with foolish linter rules
slax57 Mar 12, 2025
de13c04
fix links and make navigation more consistent
slax57 Mar 12, 2025
5890a02
fix linter blockquote issue
slax57 Mar 13, 2025
ea4865a
docs: apply review on components reference
slax57 Mar 13, 2025
dc28485
docs: apply review on handling relations
slax57 Mar 13, 2025
17b67e8
docs: revamp the handling relations doc
slax57 Mar 14, 2025
9036ebe
docs: apply review on authentication support doc
slax57 Mar 14, 2025
25b56df
Merge remote-tracking branch 'origin/4.1' into revamp-admin-docs
slax57 Mar 14, 2025
2f2ffbb
docs: update the admin outline (menu)
slax57 Mar 14, 2025
2348e35
fix linter again and again
slax57 Mar 14, 2025
078a77e
docs: add section about Validation With React Admin Inputs
slax57 Mar 14, 2025
3254a5d
docs: schema: add screenshots for name instead of IRI
slax57 Mar 14, 2025
ae0b3a2
docs: minor updates after self-review
slax57 Mar 14, 2025
932bfa4
docs: add sections about replacing field/input with RA components
slax57 Mar 14, 2025
49ebea2
docs: add request example in performance section
slax57 Mar 14, 2025
9c6b238
docs: fix all anchor links (because of hugo)
slax57 Mar 14, 2025
f596da2
Merge remote-tracking branch 'origin/4.1' into revamp-admin-docs
slax57 Mar 14, 2025
c1b8466
fix releases.md lint issues
slax57 Mar 17, 2025
427153f
fix validation.md lint issues
slax57 Mar 17, 2025
a5e00b8
Apply suggestions from code review
slax57 Mar 25, 2025
1f24654
rename schema-org.md to schema.md
slax57 Mar 25, 2025
ebb35a7
fix env variable instructions are specific to Vite
slax57 Mar 25, 2025
9651e83
fix linter error on NextJS
slax57 Mar 25, 2025
4c0e28b
keep ShowGuesser in ReviewShow
slax57 Apr 1, 2025
fcf328d
keep using EditGuesser where possible
slax57 Apr 1, 2025
3d785e4
Merge remote-tracking branch 'origin/4.1' into revamp-admin-docs
slax57 Apr 1, 2025
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
462 changes: 462 additions & 0 deletions admin/advanced-customization.md

Large diffs are not rendered by default.

137 changes: 82 additions & 55 deletions admin/authentication-support.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
# Authentication Support

API Platform Admin delegates the authentication support to React Admin.
Refer to [the chapter dedicated to authentication in the React Admin documentation](https://marmelab.com/react-admin/Authentication.html)
for more information.

Refer to the [Auth Provider Setup](https://marmelab.com/react-admin/Authentication.html) documentation for more information.

**Tip:** Once you have set up the authentication, you can also configure React Admin to perform client-side Authorization checks. Refer to the [Authorization](https://marmelab.com/react-admin/Permissions.html) documentation for more information.

## HydraAdmin

The authentication layer for [HydraAdmin component](https://api-platform.com/docs/admin/components/#hydra)
consists of a few parts, which need to be integrated together.
Enabling authentication support for [`<HydraAdmin>` component](./components.md#hydra) consists of a few parts, which need to be integrated together.

In the following steps, we will see how to:

- Make authenticated requests to the API (i.e. include the `Authorization` header)
- Redirect users to the login page if they are not authenticated
- Clear expired tokens when encountering unauthorized `401` response

### Authentication
### Make Authenticated Requests

Add the Bearer token from `localStorage` to request headers.
First, we need to implement a `getHeaders` function, that will add the Bearer token from `localStorage` (if there is one) to the `Authorization` header.

```typescript
const getHeaders = () =>
Expand All @@ -20,9 +27,13 @@ const getHeaders = () =>
: {};
```

Extend the Hydra fetch function with custom headers for authentication.
Then, extend the Hydra `fetch` function to use the `getHeaders` function to add the `Authorization` header to the requests.

```typescript
import {
fetchHydra as baseFetchHydra,
} from "@api-platform/admin";

const fetchHydra = (url, options = {}) =>
baseFetchHydra(url, {
...options,
Expand All @@ -31,11 +42,14 @@ const fetchHydra = (url, options = {}) =>

```

### Login Redirection
### Redirect To Login Page

Redirect users to a `/login` path, if no token is available in the `localStorage`.
Then, we'll create a `<RedirectToLogin>` component, that will redirect users to the `/login` route if no token is available in the `localStorage`, and call the dataProvider's `introspect` function otherwise.

```tsx
import { Navigate } from "react-router-dom";
import { useIntrospection } from "@api-platform/admin";

```typescript
const RedirectToLogin = () => {
const introspect = useIntrospection();

Expand All @@ -47,13 +61,16 @@ const RedirectToLogin = () => {
};
```

### API Documentation Parsing
### Clear Expired Tokens

Extend the `parseHydraDocumentaion` function from the [API Doc Parser library](https://github.com/api-platform/api-doc-parser)
to handle the documentation parsing. Customize it to clear
expired tokens when encountering unauthorized `401` response.
Now, we will extend the `parseHydraDocumentaion` function (imported from the [@api-platform/api-doc-parser](https://github.com/api-platform/api-doc-parser) library).

We will customize it to clear expired tokens when encountering unauthorized `401` response.

```typescript
import { parseHydraDocumentation } from "@api-platform/api-doc-parser";
import { ENTRYPOINT } from "config/entrypoint";

const apiDocumentationParser = (setRedirectToLogin) => async () => {
try {
setRedirectToLogin(false);
Expand All @@ -72,11 +89,16 @@ const apiDocumentationParser = (setRedirectToLogin) => async () => {
};
```

### Data Provider
### Extend The Data Provider

Initialize the hydra data provider with custom headers and the documentation parser.
Now, we can initialize the Hydra data provider with the custom `fetchHydra` (with custom headers) and `apiDocumentationParser` functions created earlier.

```typescript
import {
hydraDataProvider as baseHydraDataProvider,
} from "@api-platform/admin";
import { ENTRYPOINT } from "config/entrypoint";

const dataProvider = (setRedirectToLogin) =>
baseHydraDataProvider({
entrypoint: ENTRYPOINT,
Expand All @@ -85,12 +107,12 @@ const dataProvider = (setRedirectToLogin) =>
});
```

### Export Admin Component
### Update The Admin Component

Export the Hydra admin component, and track the users' authentication status.
Lastly, we can stitch everything together in the `Admin` component.

```typescript
// components/admin/Admin.tsx
```tsx
// src/Admin.tsx

import Head from "next/head";
import { useState } from "react";
Expand All @@ -106,14 +128,14 @@ import { parseHydraDocumentation } from "@api-platform/api-doc-parser";
import authProvider from "utils/authProvider";
import { ENTRYPOINT } from "config/entrypoint";

// Auth, Parser, Provider calls
// Functions and components created in the previous steps:
const getHeaders = () => {...};
const fetchHydra = (url, options = {}) => {...};
const RedirectToLogin = () => {...};
const apiDocumentationParser = (setRedirectToLogin) => async () => {...};
const dataProvider = (setRedirectToLogin) => {...};

const Admin = () => {
export const Admin = () => {
const [redirectToLogin, setRedirectToLogin] = useState(false);

return (
Expand Down Expand Up @@ -142,29 +164,32 @@ const Admin = () => {
</>
);
};
export default Admin;
```

### Additional Notes
### Example Implementation

For the implementation of the admin component, you can find a working example in the [API Platform's demo application](https://github.com/api-platform/demo/blob/4.0/pwa/components/admin/Admin.tsx).

## OpenApiAdmin

This section explains how to set up and customize the [OpenApiAdmin component](https://api-platform.com/docs/admin/components/#openapi) authentication layer.
It covers:
* Creating a custom HTTP Client
* Data and rest data provider configuration
* Implementation of an auth provider
This section explains how to set up and customize the [`<OpenApiAdmin>` component](./components.md/#openapi) to enable authentication.

### Data Provider & HTTP Client
In the following steps, we will see how to:

Create a custom HTTP client to add authentication tokens to request headers.
Configure the `openApiDataProvider`, and
inject the custom HTTP client into the [Simple REST Data Provider for React-Admin](https://github.com/Serind/ra-data-simple-rest).
- Make authenticated requests to the API (i.e. include the `Authorization` header)
- Implement an authProvider to redirect users to the login page if they are not authenticated, and clear expired tokens when encountering unauthorized `401` response

### Making Authenticated Requests

First, we need to create a custom `httpClient` to add authentication tokens (via the the `Authorization` HTTP header) to requests.

We will then configure `openApiDataProvider` to use [`ra-data-simple-rest`](https://github.com/marmelab/react-admin/blob/master/packages/ra-data-simple-rest/README.md), a simple REST dataProvider for React Admin, and make it use the `httpClient` we created earlier.

**File:** `src/components/jsonDataProvider.tsx`
```typescript
// src/dataProvider.ts

const getAccessToken = () => localStorage.getItem("token");

const httpClient = async (url: string, options: fetchUtils.Options = {}) => {
options.headers = new Headers({
...options.headers,
Expand All @@ -177,32 +202,31 @@ const httpClient = async (url: string, options: fetchUtils.Options = {}) => {
return await fetchUtils.fetchJson(url, options);
};

const jsonDataProvider = openApiDataProvider({
const dataProvider = openApiDataProvider({
dataProvider: simpleRestProvider(API_ENTRYPOINT_PATH, httpClient),
entrypoint: API_ENTRYPOINT_PATH,
docEntrypoint: API_DOCS_PATH,
});
```

> [!NOTE]
> The `simpleRestProvider` provider expect the API to include a `Content-Range` header in the response.
> You can find more about the header syntax in the [Mozilla’s MDN documentation: Content-Range](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range).
>
> The `getAccessToken` function retrieves the JWT token stored in the browser.
**Note:** The `simpleRestProvider` provider expect the API to include a `Content-Range` header in the response. You can find more about the header syntax in the [Mozilla’s MDN documentation: Content-Range](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range).

**Note:** The `getAccessToken` function retrieves the JWT token stored in the browser's localStorage. Replace it with your own logic in case you don't store the token that way.

### Authentication and Authorization
### Creating The AuthProvider

Create and export an `authProvider` object that handles authentication and authorization logic.
Now let's create and export an `authProvider` object that handles authentication and authorization logic.

**File:** `src/components/authProvider.tsx`
```typescript
// src/authProvider.ts

interface JwtPayload {
exp?: number;
iat?: number;
roles: string[];
sub: string;
username: string;
}

const getAccessToken = () => localStorage.getItem("token");

const authProvider = {
login: async ({username, password}: { username: string; password: string }) => {
const request = new Request(API_AUTH_PATH, {
Expand Down Expand Up @@ -242,7 +266,7 @@ const authProvider = {
const decoded = jwtDecode<JwtPayload>(token);

return Promise.resolve({
id: "",
id: decoded.sub,
fullName: decoded.username,
avatar: "",
});
Expand All @@ -253,20 +277,23 @@ const authProvider = {
export default authProvider;
```

### Export OpenApiAdmin Component
### Updating The Admin Component

**File:** `src/App.tsx`
```typescript
import {OpenApiAdmin} from '@api-platform/admin';
import authProvider from "./components/authProvider";
import jsonDataProvider from "./components/jsonDataProvider";
import {API_DOCS_PATH, API_ENTRYPOINT_PATH} from "./config/api";
Finally, we can update the `Admin` component to use the `authProvider` and `dataProvider` we created earlier.

```tsx
// src/Admin.tsx

import { OpenApiAdmin } from '@api-platform/admin';
import authProvider from "./authProvider";
import dataProvider from "./dataProvider";
import { API_DOCS_PATH, API_ENTRYPOINT_PATH } from "./config/api";

export default () => (
<OpenApiAdmin
entrypoint={API_ENTRYPOINT_PATH}
docEntrypoint={API_DOCS_PATH}
dataProvider={jsonDataProvider}
dataProvider={dataProvider}
authProvider={authProvider}
/>
);
Expand Down
Loading