├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── 1_Support_question.md │ └── 2_Documentation_issue.md ├── PULL_REQUEST_TEMPLATE.md ├── linters │ └── .textlintrc └── workflows │ ├── cd.yml │ └── ci.yml ├── .gitignore ├── .markdownlint.yml ├── .proselintrc.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── admin ├── advanced-customization.md ├── authentication-support.md ├── components.md ├── customizing.md ├── file-upload.md ├── getting-started.md ├── handling-relations.md ├── images │ ├── AutocompleteInput.png │ ├── admin-custom-edit-guesser.png │ ├── admin-custom-field.png │ ├── admin-custom-input.png │ ├── admin-custom-list-field-guesser.png │ ├── admin-custom-list-guesser.png │ ├── admin-custom-show-guesser.png │ ├── admin-datagrid.png │ ├── admin-default-list.png │ ├── admin-demo.gif │ ├── admin-demo.mp4 │ ├── admin-demo.webm │ ├── admin-filter.png │ ├── admin-form-layout.png │ ├── admin-menu-icons.png │ ├── admin-menu.png │ ├── admin-reference-record-count.png │ ├── admin-sort.png │ ├── admin-tabbed-show-layout.png │ ├── admin-undoable-mutation.png │ ├── admin-warnWhenUnsavedChanges.png │ ├── api-platform-admin-theme.png │ ├── api-platform-welcome-page.png │ ├── basic-admin-greetings.png │ ├── embedded-relation-ReferenceField.png │ ├── embedded-relation-ReferenceInput.png │ ├── embedded-relation-dot-notation.png │ ├── embedded-relation-full-object.png │ ├── embedded-relation-useEmbedded-false.png │ ├── react-admin-theme.png │ ├── related-record-with-iri.png │ ├── related-record-with-name.png │ ├── required-field.png │ └── submission-error-field.png ├── index.md ├── performance.md ├── real-time-mercure.md ├── schema.md └── validation.md ├── core ├── bootstrap.md ├── client-integration.md ├── configuration.md ├── content-negotiation.md ├── default-order.md ├── deprecations.md ├── design.md ├── doctrine-filters.md ├── dto.md ├── elasticsearch-filters.md ├── elasticsearch.md ├── errors.md ├── events.md ├── extending-jsonld-context.md ├── extending.md ├── extensions.md ├── external-vocabularies.md ├── filters.md ├── form-data.md ├── getting-started.md ├── graphql.md ├── identifiers.md ├── images │ ├── JWTAuthorizeButton.png │ ├── JWTConfigureApiKey.png │ ├── SerializerWorkflow.png │ ├── deprecated-graphiql.png │ ├── deprecated-swagger-ui.png │ ├── diagrams │ │ ├── api-platform-get-i-o.dia │ │ ├── api-platform-get-i-o.png │ │ ├── api-platform-get-i-o.svg │ │ ├── api-platform-post-i-o.dia │ │ ├── api-platform-post-i-o.png │ │ ├── api-platform-post-i-o.svg │ │ ├── api-platform-put-i-o.dia │ │ ├── api-platform-put-i-o.png │ │ ├── api-platform-put-i-o.svg │ │ └── resolvers-workflow.svg │ ├── jwt-token-swagger-ui.png │ ├── mercure-discovery.png │ ├── mercure-subscriptions.png │ ├── open-api-documented-error.png │ └── swagger-ui-modified.png ├── index.md ├── json-schema.md ├── jwt.md ├── mercure.md ├── mongodb.md ├── openapi.md ├── operation-path-naming.md ├── operations.md ├── pagination.md ├── performance.md ├── push-relations.md ├── security.md ├── serialization.md ├── state-processors.md ├── state-providers.md ├── subresources.md ├── testing.md ├── upgrade-guide.md ├── url-generation-strategy.md └── validation.md ├── create-client ├── custom.md ├── images │ ├── create-client-demo.gif │ ├── nextjs │ │ ├── create-client-nextjs-list.png │ │ └── create-client-nextjs-show.png │ ├── nuxt │ │ ├── create-client-nuxt-edit.png │ │ └── create-client-nuxt-list.png │ ├── react-native │ │ ├── create-client-react-native-add.png │ │ ├── create-client-react-native-delete.png │ │ ├── create-client-react-native-list.png │ │ └── create-client-react-native-show.png │ └── react │ │ ├── create-client-react-delete.png │ │ ├── create-client-react-edit.png │ │ ├── create-client-react-list-pagination.png │ │ ├── create-client-react-list.png │ │ └── create-client-react-show.png ├── index.md ├── nextjs.md ├── nuxt.md ├── quasar.md ├── react-native.md ├── react.md ├── troubleshooting.md ├── typescript.md ├── vuejs.md └── vuetify.md ├── deployment ├── docker-compose.md ├── heroku.md ├── images │ ├── deploy-result.png │ ├── digitalocean-dns.png │ ├── digitalocean-droplet.png │ ├── google-image-caddy-details.png │ └── google-image-overview.png ├── index.md ├── kubernetes.md ├── minikube.md └── traefik.md ├── extra ├── conduct.md ├── contribution-guides.md ├── enterprise.md ├── philosophy.md ├── releases.md ├── security.md └── troubleshooting.md ├── laravel ├── filters.md ├── images │ ├── basic-rest.png │ ├── books-collection.png │ ├── empty-docs.png │ ├── filters-documentation.png │ ├── form-request.png │ ├── graphql.png │ ├── property-placeholder.png │ ├── read-only.png │ └── title-filter.png ├── index.md ├── jwt.md ├── security.md ├── testing.md └── validation.md ├── outline.yaml ├── schema-generator ├── configuration.md ├── getting-started.md ├── images │ └── stoplight.png └── index.md └── symfony ├── caddy.md ├── controllers.md ├── debugging.md ├── file-upload.md ├── fosuser-bundle.md ├── images ├── NelmioApiDocBundle.png ├── api-platform-2.5-admin.png ├── api-platform-2.5-api.png ├── api-platform-2.5-bookshop-api.png ├── api-platform-2.5-graphql.png ├── api-platform-2.5-pwa-react.png ├── api-platform-2.5-welcome.png ├── api-platform-2.6-admin.png ├── api-platform-2.6-api.png ├── api-platform-2.6-bookshop-api.png ├── api-platform-2.6-bookshop-json-schemas.png ├── api-platform-2.6-graphql.png ├── api-platform-2.6-pwa-react.png ├── api-platform-2.6-welcome.png ├── api-platform-3.0-welcome.png ├── swagger-ui-1.png ├── swagger-ui-2.png └── symfonycasts-player.png ├── index.md ├── jwt.md ├── messenger.md ├── migrate-from-fosrestbundle.md ├── nelmio-api-doc.md ├── security.md ├── testing.md ├── user.md └── validation.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_style = space 10 | indent_size = 4 11 | 12 | # We recommend you to keep these unchanged 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | [*.json] 19 | indent_style = space 20 | indent_size = 2 21 | 22 | [*.md] 23 | trim_trailing_whitespace = false 24 | 25 | [*.neon] 26 | indent_style = tab 27 | indent_size = 4 28 | 29 | [*.xml] 30 | indent_style = space 31 | indent_size = 4 32 | 33 | [*.{yaml,yml}] 34 | indent_style = space 35 | indent_size = 2 36 | trim_trailing_whitespace = false 37 | 38 | [.circleci/config.yml] 39 | indent_style = space 40 | indent_size = 2 41 | 42 | [.github/workflows/*.yml] 43 | indent_style = space 44 | indent_size = 2 45 | 46 | [.gitmodules] 47 | indent_style = tab 48 | 49 | [.proselintrc] 50 | indent_style = space 51 | indent_size = 2 52 | 53 | [.travis.yml] 54 | indent_style = space 55 | indent_size = 2 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_Support_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ⛔ Support Question 3 | about: See https://api-platform.com/support/ for questions about using API Platform 4 | --- 5 | 6 | # Support question 7 | 8 | We use GitHub issues only to discuss bugs and new features. 9 | For this kind of questions about using API Platform, please use 10 | any of the support alternatives shown in [API Platform support](https://api-platform.com/support/). 11 | 12 | Thanks! 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_Documentation_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📄 Documentation issue 3 | about: Report a documentation issue 4 | --- 5 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /.github/linters/.textlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "terminology": { 4 | "exclude": [ 5 | "Node(?:js)?", 6 | "web[- ]?site(s)?" 7 | ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy Website 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | - "*.*" 9 | 10 | permissions: 11 | contents: read 12 | actions: read 13 | checks: write 14 | deployments: write 15 | pull-requests: read 16 | 17 | jobs: 18 | deploy: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout the website 22 | uses: actions/checkout@v4 23 | with: 24 | repository: api-platform/website 25 | ref: main 26 | 27 | - name: Get yarn cache directory path 28 | id: yarn-cache-dir-path 29 | run: echo "dir=$(yarn cache dir)" >> "$GITHUB_OUTPUT" 30 | 31 | - uses: actions/cache@v4 32 | id: yarn-cache 33 | with: 34 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 35 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 36 | restore-keys: | 37 | ${{ runner.os }}-yarn- 38 | 39 | - name: Setup Hugo 40 | uses: peaceiris/actions-hugo@v3 41 | with: 42 | hugo-version: "0.134.2" 43 | extended: true 44 | 45 | - name: Install php 46 | uses: shivammathur/setup-php@v2 47 | with: 48 | php-version: "8.2" 49 | tools: phive 50 | 51 | - name: Auth gcloud 52 | uses: google-github-actions/auth@v2 53 | with: 54 | credentials_json: ${{ secrets.BUCKET_CREDS }} 55 | 56 | - name: Set up Cloud SDK 57 | uses: google-github-actions/setup-gcloud@v2 58 | 59 | - name: Clone website 60 | uses: actions/checkout@v4 61 | with: 62 | repository: api-platform/docs-website 63 | path: docs-website 64 | 65 | - name: Install javascript packages 66 | working-directory: docs-website 67 | run: npm install 68 | 69 | - name: Fetch API Platform docs 70 | working-directory: docs-website 71 | run: tools/get-docs.sh 72 | 73 | - name: Fetch API Platform references and guides 74 | working-directory: docs-website 75 | run: tools/get-core-docs.sh 76 | 77 | - name: Build menu 78 | working-directory: docs-website 79 | run: node tools/menu.mjs 80 | 81 | - name: Hugo 82 | working-directory: docs-website 83 | run: hugo --minify 84 | 85 | - name: Deploy 86 | working-directory: docs-website 87 | run: gsutil -q -m rsync -d -r ./public gs://api-platform-website-v3/ 88 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint 3 | 4 | on: 5 | push: 6 | pull_request: 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | name: Lint 14 | runs-on: ubuntu-latest 15 | 16 | permissions: 17 | contents: read 18 | packages: read 19 | statuses: write 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Lint 28 | uses: super-linter/super-linter/slim@v7 29 | env: 30 | VALIDATE_EDITORCONFIG: false 31 | VALIDATE_JSCPD: false 32 | VALIDATE_MARKDOWN_PRETTIER: false 33 | DEFAULT_BRANCH: "origin/4.1" 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - uses: actions/cache@v4 37 | with: 38 | path: ~/.cache/pip 39 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} 40 | restore-keys: | 41 | ${{ runner.os }}-pip- 42 | 43 | - name: Install Proselint 44 | run: pip install --quiet --user proselint 45 | 46 | - name: Run Proselint 47 | run: find . -name '*.md' -exec proselint {} \; 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /website 2 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | MD013: 3 | line_length: 400 4 | no-inline-html: 5 | allowed_elements: [a, p, img, br] 6 | -------------------------------------------------------------------------------- /.proselintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": { 3 | "typography.symbols": false, 4 | "typography.exclamation": false, 5 | "hyperbole.misc": false, 6 | "cliches.misc": false, 7 | "lexical_illusions.misc": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the API Platform Documentation 2 | 3 | First of all, thank you for contributing, you're awesome! 4 | 5 | To have your code integrated in the API Platform documentation project, there are some rules to follow, but don't panic, it's easy! 6 | 7 | ## Reporting Bugs in the documentation 8 | 9 | Before submitting your issue: 10 | 11 | - Check if the bug is not already reported! 12 | - A clear title to resume the issue 13 | - A description of the workflow needed to reproduce the bug 14 | 15 | > [!NOTE] 16 | > Don't hesitate giving as much information as you can. 17 | 18 | ## Code of Conduct 19 | 20 | By contributing to this project, you agree to abide by our [Code of Conduct](https://github.com/api-platform/docs#coc-ov-file). We expect all contributors to foster a welcoming and inclusive environment. 21 | 22 | ## How to Contribute 23 | 24 | 1. Fork this repository by clicking the "Fork" button at the top right of the `api-platform/docs` repository page. 25 | 26 | 2. Clone the forked repository to your local machine: 27 | ```console 28 | git clone https://github.com/your-username/repository-name.git 29 | ``` 30 | 3. Create a new branch for your contribution: 31 | ```console 32 | git switch -c docs-your-branch-name 33 | ``` 34 | 4. Commit and push your changes 35 | 5. Submit a Pull Request. You must decide on what branch your changes will be based depending of the nature of the change. 36 | See [the dedicated documentation entry](https://api-platform.com/docs/extra/releases/). 37 | 38 | > [!TIP] 39 | > You can also contribute to improving the documentation directly by clicking on the 40 | > **"You can also help us improve the documentation of this page."** link, located at the end of each documentation page. 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

API Platform

2 | 3 | # API Platform Documentation 4 | 5 | [![Lint](https://github.com/api-platform/docs/actions/workflows/ci.yml/badge.svg)](https://github.com/api-platform/docs/actions/workflows/ci.yml) 6 | 7 | Welcome to the official documentation for [API Platform](https://api-platform.com), a powerful framework for building APIs and web applications. 8 | 9 | This repository contains all the API Platform documentation resources. 10 | 11 | ## Contributing 12 | 13 | Please check our [CONTRIBUTING file](/CONTRIBUTING.md) to contribute. 14 | 15 | -------------------------------------------------------------------------------- /admin/file-upload.md: -------------------------------------------------------------------------------- 1 | # Handling File Upload 2 | 3 | If you need to handle the file upload in the server part, please follow [the related documentation](../symfony/file-upload.md). 4 | 5 | This documentation assumes you have a `/media_objects` endpoint accepting `multipart/form-data`-encoded data. 6 | 7 | To manage the upload in the admin part, you need to [customize the guessed create or edit form](./customizing.md#from-inputguesser-to-react-admin-inputs). 8 | 9 | Add a [``](https://marmelab.com/react-admin/FileInput.html) as a child of the guesser. For example, for the create form: 10 | 11 | ```js 12 | import { 13 | HydraAdmin, 14 | ResourceGuesser, 15 | CreateGuesser, 16 | } from '@api-platform/admin'; 17 | import { FileField, FileInput } from 'react-admin'; 18 | 19 | const MediaObjectsCreate = () => ( 20 | 21 | 22 | 23 | 24 | 25 | ); 26 | 27 | export const App = () => ( 28 | 29 | 30 | {/* ... */} 31 | 32 | ); 33 | ``` 34 | 35 | And that's it! 36 | The guessers are able to detect that you have used a `FileInput` and are passing this information to the data provider, through a `hasFileField` field in the `extraInformation` object, itself in the data. 37 | If you are using the Hydra data provider, it uses a `multipart/form-data` request instead of a JSON-LD one. 38 | 39 | **Note:** In the case of the `EditGuesser`, the HTTP method used becomes a `POST` instead of a `PUT`, to prevent a [PHP bug](https://bugs.php.net/bug.php?id=55815). 40 | -------------------------------------------------------------------------------- /admin/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## API Platform Symfony variant 4 | 5 | If you use the [API Platform Symfony variant](../symfony/), good news, API Platform Admin is already installed! 🎉 6 | 7 | You can access it by visiting `/admin` on your API Platform application. 8 | 9 | When running locally, you can also click on the "Admin" button of the welcome page at [https://localhost](https://localhost). 10 | 11 | ![API Platform welcome page](./images/api-platform-welcome-page.png) 12 | 13 | Here is what it looks like with a simple API exposing a `Greetings` resource: 14 | 15 | ![Basic admin with the Greetings resource](./images/basic-admin-greetings.png) 16 | 17 | ## Manual Installation 18 | 19 | If you did not use the Symfony variant of API Platform and need to install API Platform Admin manually, follow this guide. 20 | 21 | First, let's scaffold a React Admin Application by using the [Create React Admin](https://marmelab.com/react-admin/CreateReactAdmin.html) tool: 22 | 23 | ```bash 24 | npx create-react-admin@latest my-admin 25 | cd my-admin 26 | ``` 27 | 28 | Then, install the `@api-platform/admin` library: 29 | 30 | ```bash 31 | npm install @api-platform/admin 32 | ``` 33 | 34 | Now you can use either: 35 | 36 | - [``](./getting-started.md#using-hydraadmin) to connect your app to an API exposing a Hydra documentation 37 | - [``](./getting-started.md#using-openapiadmin) to connect your app to an API exposing an OpenAPI documentation 38 | 39 | ## Using `HydraAdmin` 40 | 41 | You can use the [``](./components.md#hydraadmin) component exported by `@api-platform/admin` to connect your app to an API exposing a Hydra documentation. 42 | 43 | If you used Create React Admin, you can replace the content of `src/App.tsx` by: 44 | 45 | ```tsx 46 | import { HydraAdmin } from "@api-platform/admin"; 47 | 48 | // Replace with your own API entrypoint 49 | // For instance if https://example.com/api/books is the path to the collection of book resources, then the entrypoint is https://example.com/api 50 | export const App = () => ; 51 | ``` 52 | 53 | **Tip:** if you don't want to hardcode the API URL, you can [use an environment variable](https://vite.dev/guide/env-and-mode). 54 | 55 | Your new administration interface is ready! `HydraAdmin` will automatically fetch the Hydra documentation of your API and generate CRUD pages for all the resources it exposes. 56 | 57 | Type `npm run dev` to try it! 58 | 59 | ![Basic admin with the Greetings resource](./images/basic-admin-greetings.png) 60 | 61 | **Tip:** There are more props you can pass to the `HydraAdmin` component to customize the dataProvider or the connection to Mercure. Check the [API documentation](./components.md#hydraadmin) for more information. 62 | 63 | **Tip:** You may also need to configure your API to set the correct CORS headers. Refer to the [Configuring CORS](./getting-started.md#configuring-cors) section below to learn more. 64 | 65 | ## Using `OpenApiAdmin` 66 | 67 | You can use the [``](./components.md#openapiadmin) component exported by `@api-platform/admin` to connect your app to an API exposing an OpenAPI documentation. 68 | 69 | If you used Create React Admin, you can replace the content of `src/App.tsx` by: 70 | 71 | ```tsx 72 | import { OpenApiAdmin } from "@api-platform/admin"; 73 | 74 | // Replace with your own API entrypoint 75 | export const App = () => ( 76 | 80 | ); 81 | ``` 82 | 83 | **Tip:** If you don't want to hardcode the API URL, you can use an environment variable (see [Vite.js](https://vite.dev/guide/env-and-mode) or [Next.js](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables) docs). 84 | 85 | Your new administration interface is ready! `OpenApiAdmin` will automatically fetch the Hydra documentation of your API and generate CRUD pages for all the resources it exposes. 86 | 87 | Type `npm run dev` to try it! 88 | 89 | ![Basic admin with the Greetings resource](./images/basic-admin-greetings.png) 90 | 91 | **Tip:** There are more props you can pass to the `OpenApiAdmin` component to customize the dataProvider or the connection to Mercure. Check the [API documentation](./components.md#openapiadmin) for more information. 92 | 93 | **Tip:** You may also need to configure your API to set the correct CORS headers. Refer to the [Configuring CORS](./getting-started.md#configuring-cors) section below to learn more. 94 | 95 | ## Configuring CORS 96 | 97 | Be sure to make your API send proper [CORS HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) to allow 98 | the admin's domain to access it. 99 | 100 | To do so, if you use the API Platform Symfony variant, update the value of the `CORS_ALLOW_ORIGIN` parameter in `api/.env` (it will be set to `^https?://localhost:?[0-9]*$` 101 | by default). 102 | 103 | If you use a custom installation of Symfony and [API Platform Core](../core/), you will need to adjust the [NelmioCorsBundle configuration](https://github.com/nelmio/NelmioCorsBundle#configuration) to expose the `Link` HTTP header and to send proper CORS headers on the route under which the API will be served (`/api` by default). 104 | Here is a sample configuration: 105 | 106 | ```yaml 107 | # config/packages/nelmio_cors.yaml 108 | 109 | nelmio_cors: 110 | paths: 111 | '^/api/': 112 | origin_regex: true 113 | allow_origin: ['^http://localhost:[0-9]+'] # You probably want to change this regex to match your real domain 114 | allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] 115 | allow_headers: ['Content-Type', 'Authorization'] 116 | expose_headers: ['Link'] 117 | max_age: 3600 118 | ``` 119 | 120 | Clear the cache to apply this change: 121 | 122 | ```console 123 | bin/console cache:clear --env=prod 124 | ``` 125 | 126 | ## Next Step 127 | 128 | Learn how to add more features to your generated Admin by [Customizing the Schema](./schema.md). -------------------------------------------------------------------------------- /admin/images/AutocompleteInput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/AutocompleteInput.png -------------------------------------------------------------------------------- /admin/images/admin-custom-edit-guesser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-edit-guesser.png -------------------------------------------------------------------------------- /admin/images/admin-custom-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-field.png -------------------------------------------------------------------------------- /admin/images/admin-custom-input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-input.png -------------------------------------------------------------------------------- /admin/images/admin-custom-list-field-guesser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-list-field-guesser.png -------------------------------------------------------------------------------- /admin/images/admin-custom-list-guesser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-list-guesser.png -------------------------------------------------------------------------------- /admin/images/admin-custom-show-guesser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-custom-show-guesser.png -------------------------------------------------------------------------------- /admin/images/admin-datagrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-datagrid.png -------------------------------------------------------------------------------- /admin/images/admin-default-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-default-list.png -------------------------------------------------------------------------------- /admin/images/admin-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-demo.gif -------------------------------------------------------------------------------- /admin/images/admin-demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-demo.mp4 -------------------------------------------------------------------------------- /admin/images/admin-demo.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-demo.webm -------------------------------------------------------------------------------- /admin/images/admin-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-filter.png -------------------------------------------------------------------------------- /admin/images/admin-form-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-form-layout.png -------------------------------------------------------------------------------- /admin/images/admin-menu-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-menu-icons.png -------------------------------------------------------------------------------- /admin/images/admin-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-menu.png -------------------------------------------------------------------------------- /admin/images/admin-reference-record-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-reference-record-count.png -------------------------------------------------------------------------------- /admin/images/admin-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-sort.png -------------------------------------------------------------------------------- /admin/images/admin-tabbed-show-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-tabbed-show-layout.png -------------------------------------------------------------------------------- /admin/images/admin-undoable-mutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-undoable-mutation.png -------------------------------------------------------------------------------- /admin/images/admin-warnWhenUnsavedChanges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/admin-warnWhenUnsavedChanges.png -------------------------------------------------------------------------------- /admin/images/api-platform-admin-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/api-platform-admin-theme.png -------------------------------------------------------------------------------- /admin/images/api-platform-welcome-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/api-platform-welcome-page.png -------------------------------------------------------------------------------- /admin/images/basic-admin-greetings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/basic-admin-greetings.png -------------------------------------------------------------------------------- /admin/images/embedded-relation-ReferenceField.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/embedded-relation-ReferenceField.png -------------------------------------------------------------------------------- /admin/images/embedded-relation-ReferenceInput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/embedded-relation-ReferenceInput.png -------------------------------------------------------------------------------- /admin/images/embedded-relation-dot-notation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/embedded-relation-dot-notation.png -------------------------------------------------------------------------------- /admin/images/embedded-relation-full-object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/embedded-relation-full-object.png -------------------------------------------------------------------------------- /admin/images/embedded-relation-useEmbedded-false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/embedded-relation-useEmbedded-false.png -------------------------------------------------------------------------------- /admin/images/react-admin-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/react-admin-theme.png -------------------------------------------------------------------------------- /admin/images/related-record-with-iri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/related-record-with-iri.png -------------------------------------------------------------------------------- /admin/images/related-record-with-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/related-record-with-name.png -------------------------------------------------------------------------------- /admin/images/required-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/required-field.png -------------------------------------------------------------------------------- /admin/images/submission-error-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/admin/images/submission-error-field.png -------------------------------------------------------------------------------- /admin/index.md: -------------------------------------------------------------------------------- 1 | # The API Platform Admin 2 | 3 | 8 | 9 | API Platform **Admin** is a tool to automatically create a beautiful (Material Design) and fully-featured administration interface 10 | for any API implementing specification formats supported by [`@api-platform/api-doc-parser`](https://github.com/api-platform/api-doc-parser). 11 | 12 | In particular, that includes: 13 | 14 | - APIs using [the Hydra Core Vocabulary](https://www.hydra-cg.com/) 15 | - APIs exposing an [OpenAPI documentation](https://www.openapis.org/) 16 | 17 | Of course, API Platform Admin is the perfect companion of APIs created 18 | using [the API Platform framework](https://api-platform.com). But it also supports APIs written with any other programming language or framework as long as they expose a standard Hydra or OpenAPI documentation. 19 | 20 | ## Based On React Admin 21 | 22 | API Platform Admin is a Single Page Application (SPA), based on [React Admin](https://marmelab.com/react-admin/), a powerful frontend framework for building B2B applications on top of REST/GraphQL APIs, written in TypeScript and React. 23 | 24 | Thanks to its built-in **guessers**, API Platform Admin parses the API documentation then uses React Admin to expose a nice, responsive management interface (Create-Retrieve-Update-Delete, i.e. CRUD) for all documented resource types. 25 | 26 | Afterwards, you can **customize everything** by using the numerous components provided by [React Admin](https://marmelab.com/react-admin/documentation.html) and [MUI](https://mui.com/), or even writing your own [React](https://reactjs.org/) components. 27 | 28 | 29 | 30 |

React Admin Screencast
Watch the React Admin screencast

31 | 32 | ## Features 33 | 34 | Simply by reading your API documentation, API Platform Admin provides the following features: 35 | 36 | - Generate 'list', 'create', 'show', and 'edit' views for all resources 37 | - Automatically detect the type for inputs and fields 38 | - Client-side [validation](./validation.md) on required inputs 39 | - Pagination 40 | - Filtering and ordering 41 | - Easily view and edit [related records](./handling-relations.md) 42 | - Display the related resource’s name instead of its IRI ([using the Schema.org vocabulary](./schema.md#displaying-related-resources-name-instead-of-its-iri)) 43 | - Nicely displays server-side errors (e.g. advanced validation) 44 | - Real-time updates with [Mercure](https://mercure.rocks) 45 | 46 | By [leveraging React Admin components](./advanced-customization.md), you can further customize the generated interface and get access to many more features: 47 | 48 | - Powerful Datagrid components 49 | - Search and filtering 50 | - Advanced form validation 51 | - Undoable mutations 52 | - Authentication 53 | - Access Control 54 | - Internationalization 55 | - [And many more](https://marmelab.com/react-admin/Features.html) 56 | 57 | ## Next Step 58 | 59 | Get your Admin up and running by following the [Getting Started guide](./getting-started.md). -------------------------------------------------------------------------------- /admin/performance.md: -------------------------------------------------------------------------------- 1 | # Performance Tips 2 | 3 | To make the admin faster and greener, you can make some changes to your API. 4 | 5 | ## Retrieve All Relations in One Request 6 | 7 | By default, if your relations are not embedded and if you decide to display some fields belonging to relations in your resource list, 8 | the admin will fetch the relations one by one. 9 | 10 | In this case, it can be improved by doing only one request for all the related resources instead. 11 | 12 | To do so, you need to make sure the [search filter](../core/doctrine-filters.md#search-filter) is enabled for the identifier of the related resource. 13 | 14 | For instance, if you have a `book` resource having a relation to `author` resources and you display the author names on your book list, 15 | you can make sure the authors are retrieved in one go by writing: 16 | 17 | ```php 18 | ` or `` component: 14 | 15 | ```javascript 16 | import { OpenApiAdmin } from '@api-platform/admin'; 17 | 18 | export default () => ( 19 | 24 | ); 25 | ``` 26 | 27 | Or in the data provider factory: 28 | 29 | ```javascript 30 | import { hydraDataProvider, fetchHydra } from '@api-platform/admin'; 31 | import { parseHydraDocumentation } from '@api-platform/api-doc-parser'; 32 | 33 | const dataProvider = baseHydraDataProvider({ 34 | entrypoint, 35 | httpClient: fetchHydra, 36 | apiDocumentationParser: parseHydraDocumentation, 37 | mercure: { hub: 'https://mercure.rocks/hub' }, 38 | }); 39 | ``` 40 | 41 | The `mercure` object can take the following properties: 42 | 43 | - `hub`: the URL to your Mercure hub (default value: null ; when null it will be discovered by using API responses) 44 | - `jwt`: a subscriber JWT to access your Mercure hub (default value: null) 45 | - `topicUrl`: the topic URL of your resources (default value: entrypoint) 46 | -------------------------------------------------------------------------------- /admin/schema.md: -------------------------------------------------------------------------------- 1 | # Customizing the Schema 2 | 3 | Both [`HydraAdmin`](./components.md#hydraadmin) and [`OpenApiAdmin`](./components.md#openapiadmin) leverage introspection of the API schema to discover its capabilities, like **filtering** and **sorting**. 4 | 5 | They also detect wether the API has real-time capabilities using [Mercure](./real-time-mercure.md), and automatically enable it if it does. 6 | 7 | Lastly, API Platform Admin has native support for the popular [Schema.org](./schema.md#about-schemaorg) vocabulary, which enables it to automatically use the field type matching your data, or display a related resource's name instead of its IRI. 8 | 9 | ## Adding Filtering Capabilities 10 | 11 | You can add the [`ApiFilter` attribute](../core/filters.md#apifilter-attribute) to an API Platform resource to configure a filter on a property. 12 | 13 | For instance, here is how configure filtering on the `id`, `title` and `author` properties of a `Book` resource: 14 | 15 | ```php 16 | 'exact', 29 | 'title' => 'ipartial', 30 | 'author' => 'ipartial' 31 | ])] 32 | class Book 33 | { 34 | // ... 35 | } 36 | ``` 37 | 38 | If you are using the guessers, the Admin will automatically update the Book list view to include a filter on the selected properties. 39 | 40 | ![Filtering on the title property](./images/admin-filter.png) 41 | 42 | **Tip:** Learn more about the [`ApiFilter` attribute](../core/filters.md#apifilter-attribute) in the core documentation. 43 | 44 | ## Adding Sorting Capabilities 45 | 46 | You can also use the [`ApiFilter` attribute](../core/filters.md#apifilter-attribute) on an API Plaform resource to configure sorting. 47 | 48 | For instance, here is how to configure sorting on the `id`, `isbn`, `title`, `author` and `publicationDate` properties of a `Book` resource: 49 | 50 | ```php 51 | 'ASC', 64 | 'isbn' => 'ASC', 65 | 'title' => 'ASC', 66 | 'author' => 'ASC', 67 | 'publicationDate' => 'DESC' 68 | ])] 69 | class Book 70 | { 71 | // ... 72 | } 73 | ``` 74 | 75 | If you are using the guessers, the Admin will automatically update the Book list view to make the selected columns sortable. 76 | 77 | ![Sorting by the title property](./images/admin-sort.png) 78 | 79 | **Tip:** Learn more about the [`ApiFilter` attribute](../core/filters.md#apifilter-attribute) in the core documentation. 80 | 81 | ## Enabling Real-Time Updates 82 | 83 | You can use the `mercure` attribute to hint API Platform that it must dispatch the updates regarding the given resources to the Mercure hub: 84 | 85 | ```php 86 | Schema.org is a collaborative, community activity with a mission to create, maintain, and promote schemas for structured data on the Internet, on web pages, in email messages, and beyond. 108 | 109 | To leverage this capability, your API must use the JSON-LD format and the appropriate Schema.org types. 110 | The following examples will use [API Platform Core](../core/) to create such API, but keep in mind that this feature will work with any JSON-LD API using the Schema.org vocabulary, regardless of the used web framework or programming language. 111 | 112 | ## Displaying Related Resource's Name Instead of its IRI 113 | 114 | By default, IRIs of related objects are displayed in lists and forms. 115 | However, it is often more user-friendly to display a string representation of the resource (such as its name) instead of its ID. 116 | 117 | To configure which property should be shown to represent your entity, map the property containing the name of the object with the `https://schema.org/name` type: 118 | 119 | ```php 120 | // api/src/Entity/Person.php 121 | ... 122 | 123 | #[ApiProperty(iris: ["https://schema.org/name"])] 124 | private $name; 125 | 126 | ... 127 | ``` 128 | 129 | | With IRI | With Resource Name | 130 | | ---------------------------------------------------------------- | ---------------------------------------------------------------------------- | 131 | | ![Related Record With IRI](./images/related-record-with-iri.png) | ![Related Record With Resource Name](./images/related-record-with-name.png) | 132 | 133 | ## Emails, URLs and Identifiers 134 | 135 | Besides, it is also possible to use the documentation to customize some fields automatically while configuring the semantics of your data. 136 | 137 | The following Schema.org types are currently supported by API Platform Admin: 138 | 139 | - `https://schema.org/email`: the field will be rendered using the [``](https://marmelab.com/react-admin/EmailField.html) React Admin component 140 | - `https://schema.org/url`: the field will be rendered using the [``](https://marmelab.com/react-admin/UrlField.html) React Admin component 141 | - `https://schema.org/identifier`: the field will be formatted properly in inputs 142 | 143 | Note: if you already use validation on your properties, the semantics are already configured correctly (see [the correspondence table](../core/validation.md#open-vocabulary-generated-from-validation-metadata))! 144 | 145 | ## Next Step 146 | 147 | Learn how to tweak the generated Admin by [Customizing the Guessers](./customizing.md). 148 | -------------------------------------------------------------------------------- /admin/validation.md: -------------------------------------------------------------------------------- 1 | # Validation 2 | 3 | API Platform Admin manages automatically two types of validation: client-side validation and server-side (or submission) validation. 4 | 5 | ## Client-side Validation 6 | 7 | If the API documentation indicates that a field is mandatory, 8 | API Platform Admin will automatically add a [required client-side validation](https://marmelab.com/react-admin/Validation.html#per-input-validation-built-in-field-validators). 9 | 10 | For instance, with API Platform as backend, if you write the following: 11 | 12 | ```php 13 | ` with a React Admin [input component](https://marmelab.com/react-admin/Inputs.html), such as [``](https://marmelab.com/react-admin/TextInput.html), [``](https://marmelab.com/react-admin/DateInput.html) or [``](https://marmelab.com/react-admin/ReferenceInput.html), you will need to **manually add the validation rules back**. 66 | 67 | Fortunately, this is very easy to do, thanks to the [`validate`](https://marmelab.com/react-admin/Inputs.html#validate) prop of the input components. 68 | 69 | For instance, here is how to replace the input for the required `title` field: 70 | 71 | ```diff 72 | import { EditGuesser, InputGuesser } from '@api-platform/admin'; 73 | +import { TextInput, required } from 'react-admin'; 74 | 75 | export const BookEdit = () => ( 76 | 77 | - 78 | + 79 | 80 | ); 81 | ``` 82 | 83 | React Admin already comes with several [built-in validators](https://marmelab.com/react-admin/Validation.html#per-input-validation-built-in-field-validators), such as: 84 | 85 | * `required(message)` if the field is mandatory, 86 | * `minValue(min, message)` to specify a minimum value for integers, 87 | * `maxValue(max, message)` to specify a maximum value for integers, 88 | * `minLength(min, message)` to specify a minimum length for strings, 89 | * `maxLength(max, message)` to specify a maximum length for strings, 90 | * `number(message)` to check that the input is a valid number, 91 | * `email(message)` to check that the input is a valid email address, 92 | * `regex(pattern, message)` to validate that the input matches a regular expression, 93 | * `choices(list, message)` to validate that the input is within a given list 94 | 95 | React Admin also supports [Global Validation](https://marmelab.com/react-admin/Validation.html#global-validation) (at the form level). 96 | 97 | Check out the [Form Validation](https://marmelab.com/react-admin/Validation.html) documentation to learn more. 98 | -------------------------------------------------------------------------------- /core/client-integration.md: -------------------------------------------------------------------------------- 1 | # Client Integrations 2 | 3 | ## Edge Side API (ESA) 4 | 5 | > [Edge Side APIs (ESA)](https://edge-side-api.rocks/) is an architectural pattern that allows the creation of more 6 | > reliable, efficient, and less resource-intensive APIs. It revives the core REST/HATEOAS principles while taking full 7 | > advantage of the new capabilities provided by the web platform. 8 | > 9 | > ESA promotes a mixed approach (synchronous and asynchronous), offering simplicity in development and use, exceptional 10 | > performance, and the ability for clients to receive real-time updates of the resources they fetched. ESA also leverages 11 | > existing standards to expose API documentation, enabling the creation of generic clients capable of discovering the 12 | > API’s capabilities at runtime. 13 | > 14 | > — *From [ESA White Paper](https://edge-side-api.rocks/white-paper)* 15 | 16 | ## JavaScript Client Integrations 17 | 18 | API Platform offers a suite of tools and libraries that streamline the integration of JavaScript clients with APIs. 19 | These tools simplify development by automating tasks such as data fetching, administration panel creation, 20 | and real-time updates. Below is a detailed overview of the available clients, libraries, and their usage. 21 | 22 | ### Clients and Tools Overview 23 | 24 | #### Admin 25 | 26 | API Platform Admin is a dynamic administration panel generator built with [React-Admin](https://marmelab.com/react-admin/). 27 | It automatically adapts to your API schema and provides extensive customization options. It can read an [OpenAPI](https://www.openapis.org/) 28 | specification or a [Hydra](https://www.hydra-cg.com/) specification. API Platform supports both [OpenAPI](openapi.md) and 29 | [Hydra](extending-jsonld-context.md#hydra) from scratch! 30 | 31 | [Learn more about API Platform Admin](../admin/index.md). 32 | 33 | #### Create Client 34 | 35 | The Client Generator creates JavaScript/TypeScript clients based on your API documentation. It generates code that 36 | integrates seamlessly with your API endpoints, reducing development time and errors. 37 | 38 | [Learn more about the Create Client](../create-client/index.md) 39 | 40 | ### JavaScript Libraries 41 | 42 | #### api-platform/ld 43 | 44 | The [api-platform/ld](https://edge-side-api.rocks/linked-data) JavaScript library simplifies working with Linked Data. 45 | It helps parse and serialize data in formats such as [JSON-LD](extending-jsonld-context.md#json-ld), making it easier to 46 | handle complex relationships in your applications. 47 | 48 | For example, let's load authors when required with a Linked Data approach. 49 | Given an API referencing books and their authors, where `GET /books/1` returns: 50 | 51 | ```json 52 | { 53 | "@id": "/books/1", 54 | "@type": ["https://schema.org/Book"], 55 | "title": "Hyperion", 56 | "author": "https://localhost/authors/1" 57 | } 58 | ``` 59 | 60 | Use an [URLPattern](https://urlpattern.spec.whatwg.org/) to load authors automatically when fetching an author property 61 | such as `books.author?.name`: 62 | 63 | ```javascript 64 | import ld from '@api-platform/ld' 65 | 66 | const pattern = new URLPattern("/authors/:id", "https://localhost"); 67 | const books = await ld('/books', { 68 | urlPattern: pattern, 69 | onUpdate: (newBooks) => { 70 | log() 71 | } 72 | }) 73 | 74 | function log() { 75 | console.log(books.author?.name) 76 | } 77 | 78 | log() 79 | ``` 80 | 81 | With [api-platform/ld](https://edge-side-api.rocks/linked-data), authors are automatically loaded when needed. 82 | 83 | [Read the full documentation](https://edge-side-api.rocks/linked-data). 84 | 85 | #### api-platform/mercure 86 | 87 | [Mercure](https://mercure.rocks/spec) is a real-time communication protocol. The [api-platform/mercure](https://edge-side-api.rocks/mercure) 88 | library enables you to subscribe to updates and deliver real-time data seamlessly. 89 | 90 | Our frontend library allows you to subscribe to updates with efficiency, re-using the hub connection and adding topics 91 | automatically as they get requested. API Platform [supports Mercure](mercure.md) and automatically sets the 92 | [Link header](https://mercure.rocks/spec#content-negotiation) making auto-discovery a breeze. For example: 93 | 94 | ```javascript 95 | import mercure, { close } from "@api-platform/mercure"; 96 | 97 | const res = await mercure('https://localhost/authors/1', { 98 | onUpdate: (author) => console.log(author) 99 | }) 100 | 101 | const author = res.then(res => res.json()) 102 | 103 | // Close if you need to 104 | history.onpushstate = function(e) { 105 | close('https://localhost/authors/1') 106 | } 107 | ``` 108 | 109 | Assuming `/authors/1` returned the following: 110 | 111 | ```http 112 | Link: ; rel="self" 113 | Link: ; rel="mercure" 114 | ``` 115 | 116 | An `EventSource` subscribes to the topic `https://localhost/authors/1` on the hub `https://localhost/.well-known/mercure`. 117 | 118 | [Read the full documentation](https://edge-side-api.rocks/mercure). 119 | 120 | #### api-platform/api-doc-parser 121 | 122 | The [api-platform/api-doc-parser](https://github.com/api-platform/api-doc-parser) that parses Hydra, Swagger, 123 | OpenAPI, and GraphQL documentation into an intermediate format for generating API clients and scaffolding code. 124 | It integrates well with API Platform and supports auto-detecting resource relationships. 125 | 126 | Key Features: 127 | 128 | - Multi-format support: Parses Hydra, Swagger (OpenAPI v2), OpenAPI v3, and GraphQL. 129 | - Intermediate representation: Converts API docs into a usable format for generating clients, scaffolding code, or building admin interfaces. 130 | - API Platform integration: Works seamlessly with API Platform. 131 | - Auto-detection of resource relationships: Automatically detects relationships between resources based on documentation. 132 | 133 | Example: Parsing [Hydra](http://hydra-cg.com/) API Documentation: 134 | 135 | ```javascript 136 | import { parseHydraDocumentation } from '@api-platform/api-doc-parser'; 137 | 138 | parseHydraDocumentation('https://demo.api-platform.com').then(({api}) => console.log(api)); 139 | ``` 140 | This example fetches Hydra documentation from `https://demo.api-platform.com`, parses it, and logs the resulting API 141 | structure. The `parseHydraDocumentation` method is particularly useful for building metadata-driven clients or handling advanced API interactions. 142 | 143 | [Read the full documentation](https://github.com/api-platform/api-doc-parser). 144 | -------------------------------------------------------------------------------- /core/default-order.md: -------------------------------------------------------------------------------- 1 | # Overriding Default Order 2 | 3 | API Platform provides an easy way to override the default order of items in your collection. 4 | 5 | By default, items in the collection are ordered in ascending (ASC) order by their resource identifier(s). If you want to 6 | customize this order, you must add an `order` attribute on your ApiResource annotation: 7 | 8 | 9 | 10 | ```php 11 | 'ASC'])] 18 | class Book 19 | { 20 | // ... 21 | 22 | /** 23 | * ... 24 | */ 25 | public $foo; 26 | 27 | // ... 28 | } 29 | ``` 30 | 31 | ```yaml 32 | # api/config/api_platform/resources/Book.yaml 33 | # The YAML syntax is only supported for Symfony 34 | App\ApiResource\Book: 35 | order: 36 | foo: ASC 37 | ``` 38 | 39 | 40 | 41 | This `order` attribute is used as an array: the key defines the order field, the values defines the direction. 42 | If you only specify the key, `ASC` direction will be used as default. For example, to order by `foo` & `bar`: 43 | 44 | 45 | 46 | ```php 47 | 80 | 81 | It's also possible to configure the default order on an association property: 82 | 83 | 84 | 85 | ```php 86 | 114 | 115 | Another possibility is to apply the default order for a specific collection operation, which will override the global default order configuration. 116 | 117 | 118 | 119 | ```php 120 | 'DESC'])], 130 | new GetCollection(name: 'get_asc_custom', uriTemplate: 'custom_collection_asc_foos', order: ['name' => 'ASC'])] 131 | ])] 132 | class Book 133 | { 134 | // ... 135 | 136 | /** 137 | * @var string 138 | */ 139 | public $name; 140 | 141 | // ... 142 | } 143 | ``` 144 | 145 | ```yaml 146 | # api/config/api_platform/resources/Book.yaml 147 | # The YAML syntax is only supported for Symfony 148 | App\ApiResource\Book: 149 | ApiPlatform\Metadata\GetCollection: ~ 150 | get_desc_custom: 151 | class: ApiPlatform\Metadata\GetCollection 152 | uriTemplate: custom_collection_desc_foos 153 | order: 154 | name: DESC 155 | get_asc_custom: 156 | class: ApiPlatform\Metadata\GetCollection 157 | uriTemplate: custom_collection_asc_foos 158 | order: 159 | name: ASC 160 | ``` 161 | 162 | 163 | -------------------------------------------------------------------------------- /core/design.md: -------------------------------------------------------------------------------- 1 | # General Design Considerations 2 | 3 | Since you only need to describe the structure of the data to expose, API Platform is both [a "design-first" and "code-first"](https://swagger.io/blog/api-design/design-first-or-code-first-api-development/) 4 | API framework. However, the "design-first" methodology is strongly recommended: first you design the **public shape** of 5 | API endpoints. 6 | 7 | To do so, you have to write a plain old PHP object (POPO) representing the input and output of your endpoint. This is the class 8 | that is [marked with the `#[ApiResource]` attribute](../symfony/index.md). 9 | This class **doesn't have** to be mapped with Doctrine ORM, or any other persistence system. It must be simple (it's usually 10 | just a data structure with no or minimal behaviors) and will be automatically converted to [Hydra](extending-jsonld-context.md), 11 | [OpenAPI](openapi.md) and [GraphQL](graphql.md) documentations or schemas by API Platform (there is a 1-1 mapping 12 | between this class and those docs). 13 | 14 | Then, it's up to the developer to feed API Platform with an hydrated instance of this API resource object by implementing 15 | the [`ProviderInterface`](state-providers.md). Basically, the state provider will query the persistence system (RDBMS, 16 | document or graph DB, external API...), and must hydrate and return the POPO that has been designed as mentioned above. 17 | 18 | When updating a state (`POST`, `PUT`, `PATCH`, `DELETE` HTTP methods), it's up to the developer to properly persist the 19 | data provided by API Platform's resource object [hydrated by the serializer](serialization.md). 20 | To do so, there is another interface to implement: [`ProcessorInterface`](state-processors.md). 21 | 22 | This class will read the API resource object (the one marked with `#[ApiResource]`) and: 23 | 24 | - persist it directly in the database; 25 | - or hydrate a DTO then trigger a command; 26 | - or populate an event store; 27 | - or persist the data in any other useful way. 28 | 29 | The logic of state processors is the responsibility of application developers, and is **out of the API Platform's scope**. 30 | 31 | For [Rapid Application Development](https://en.wikipedia.org/wiki/Rapid_application_development), convenience and prototyping, 32 | **if and only if the class marked with `#[ApiResource]` is also a Doctrine entity**, the developer can use the Doctrine 33 | ORM's state provider and processor implementations shipped with API Platform. 34 | 35 | In this case, the public (`#[ApiResource]`) and internal (Doctrine entity) data models are shared. Then, API Platform will 36 | be able to query, filter, paginate and persist data automatically. 37 | This approach is super-convenient and efficient, but is probably **not a good idea** for non-[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) 38 | and/or large systems. 39 | Again, it's up to the developers to use, or to not use these built-in state providers/processors depending on the business logic 40 | they are dealing with. 41 | API Platform makes it easy to create custom state providers and processors. 42 | It also makes it easy to implement patterns such as [CQS](https://www.martinfowler.com/bliki/CommandQuerySeparation.html) 43 | or [CQRS](https://martinfowler.com/bliki/CQRS.html) thanks to [the Messenger Component integration](../symfony/messenger.md) and the [DTO support](dto.md). 44 | 45 | Last but not least, to create [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html)-based systems, a convenient 46 | approach is: 47 | 48 | - to persist data in an event store using a Messenger handler or a custom [state processor](state-processors.md) 49 | - to create projections in standard RDBMS (PostgreSQL, MariaDB...) tables or views 50 | - to map those projections with read-only Doctrine entity classes **and** to mark those classes with `#[ApiResource]` 51 | 52 | You can then benefit from the built-in Doctrine filters, sorting, pagination, auto-joins and all of [the extension points](extending.md) provided by API Platform. 53 | -------------------------------------------------------------------------------- /core/extending-jsonld-context.md: -------------------------------------------------------------------------------- 1 | # Extending JSON-LD AND Hydra Contexts 2 | 3 | ## JSON-LD 4 | 5 |

JSON-LD screencast
Watch the JSON-LD screencast

6 | 7 | API Platform provides the possibility to extend the JSON-LD context of properties. This allows you to describe JSON-LD-typed 8 | values, inverse properties using the `@reverse` keyword, and you can even overwrite the `@id` property this way. 9 | Everything you define within the following annotation will be passed to the context. This provides a generic way to 10 | extend the context. 11 | 12 | ```php 13 | 'http://yourcustomid.com', 29 | '@type' => 'http://www.w3.org/2001/XMLSchema#string', 30 | 'someProperty' => [ 31 | 'a' => 'textA', 32 | 'b' => 'textB' 33 | ] 34 | ] 35 | )] 36 | public $name; 37 | 38 | // ... 39 | } 40 | ``` 41 | 42 | The generated context will now have your custom attributes set: 43 | 44 | `GET /contexts/Book` 45 | 46 | ```json 47 | { 48 | "@context": { 49 | "@vocab": "http://example.com/apidoc#", 50 | "hydra": "http://www.w3.org/ns/hydra/core#", 51 | "name": { 52 | "@id": "http://yourcustomid.com", 53 | "@type": "http://www.w3.org/2001/XMLSchema#string", 54 | "someProperty": { 55 | "a": "textA", 56 | "b": "textB" 57 | } 58 | } 59 | } 60 | } 61 | ``` 62 | 63 | Note that you do not have to provide the `@id` attribute. If you do not provide an `@id` attribute, the value from `iri` will be used. 64 | 65 | ## Hydra 66 | 67 |

Hydra screencast
Watch the Hydra screencast

68 | 69 | It's also possible to replace the Hydra context used by the documentation generator: 70 | 71 | 72 | 73 | ```php 74 | 'bar']) 83 | ])] 84 | class Book 85 | { 86 | //... 87 | } 88 | ``` 89 | 90 | ```yaml 91 | # api/config/api_platform/resources.yaml 92 | # The YAML syntax is only supported for Symfony 93 | resources: 94 | App\ApiResource\Book: 95 | operations: 96 | ApiPlatform\Metadata\Get: 97 | hydraContext: { foo: 'bar' } 98 | ``` 99 | 100 | ```xml 101 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 114 | bar 115 | 116 | 117 | 118 | 119 | 120 | 121 | ``` 122 | 123 | 124 | -------------------------------------------------------------------------------- /core/external-vocabularies.md: -------------------------------------------------------------------------------- 1 | # Using External Vocabularies 2 | 3 | JSON-LD allows to define classes and properties of your API with open vocabularies such as [Schema.org](https://schema.org) 4 | and [Good Relations](https://www.heppnetz.de/projects/goodrelations/). 5 | 6 | API Platform provides attributes usable on PHP classes and properties for specifying a related external [IRI](https://en.wikipedia.org/wiki/Internationalized_resource_identifier). 7 | 8 | ```php 9 | [!WARNING] 11 | > Adding support for `application/x-www-form-urlencoded` makes your API vulnerable to [CSRF (Cross-Site Request Forgery)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) attacks. 12 | > It's crucial to implement proper countermeasures to protect your application. 13 | > 14 | > If you're using Symfony, make sure you enable [Stateless CSRF protection](https://symfony.com/blog/new-in-symfony-7-2-stateless-csrf). 15 | > 16 | > If you're working with Laravel, refer to the [Laravel CSRF documentation](https://laravel.com/docs/csrf) to ensure 17 | > adequate protection against such attacks. 18 | 19 | In this tutorial, we will decorate the default `DeserializeListener` class to handle form data if applicable, and delegate to the built-in listener for other cases. 20 | 21 | ## Create your `FormRequestProcessorDecorator` processor 22 | 23 | This decorator is able to denormalize posted form data to the target object. In case of other format, it fallbacks to the original [DeserializeListener](https://github.com/api-platform/core/blob/91dc2a4d6eeb79ea8dec26b41e800827336beb1a/src/Bridge/Symfony/Bundle/Resources/config/api.xml#L85-L91). 24 | 25 | ```php 26 | getContentType()) { 49 | return $this->handleFormRequest($data); 50 | } 51 | 52 | // Delegate the processing to the original processor for other cases 53 | return $this->decorated->process($data, $operation, $uriVariables, $context); 54 | } 55 | 56 | /** 57 | * Handle form requests by deserializing the data into the correct entity 58 | */ 59 | private function handleFormRequest(Request $request) 60 | { 61 | $attributes = $request->attributes->get('_api_attributes'); 62 | if (!$attributes) { 63 | return null; 64 | } 65 | 66 | $context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes); 67 | 68 | // Deserialize the form data into an entity 69 | $data = $request->request->all(); 70 | 71 | return $this->denormalizer->denormalize($data, 'App\Entity\SomeEntity', null, $context); 72 | } 73 | } 74 | ``` 75 | 76 | Next, configure the `FormRequestProcessorDecorator` according to whether you're using Symfony or Laravel, as shown below: 77 | 78 | ### Creating the Service Definition using Symfony 79 | 80 | ```yaml 81 | # api/config/services.yaml 82 | services: 83 | # ... 84 | App\State\FormRequestProcessorDecorator: 85 | decorates: api_platform.state.processor 86 | arguments: 87 | $decorated: '@App\State\FormRequestProcessorDecorator.inner' 88 | $denormalizer: '@serializer' 89 | $serializerContextBuilder: '@api_platform.serializer.context_builder' 90 | tags: 91 | - { name: 'api_platform.state.processor' } 92 | ``` 93 | 94 | ### Registering a Decorated Processor using Laravel 95 | 96 | ```php 97 | app->bind(ProcessorInterface::class, function ($app) { 113 | $decoratedProcessor = $app->make(ProcessorInterface::class); 114 | 115 | return new FormRequestProcessorDecorator( 116 | $decoratedProcessor, 117 | $app->make(DenormalizerInterface::class), 118 | $app->make(SerializerContextBuilderInterface::class) 119 | ); 120 | }); 121 | } 122 | } 123 | ``` 124 | 125 | ## Using your `FormRequestProcessorDecorator` processor 126 | 127 | Finally, you can use the processor in your API Resource like this: 128 | 129 | ```php 130 | SymfonyCasts, API Platform screencasts

48 | 49 | The easiest and funniest way to learn how to use API Platform for Symfony is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform-3)! 50 | -------------------------------------------------------------------------------- /core/json-schema.md: -------------------------------------------------------------------------------- 1 | # JSON Schema Support 2 | 3 | [JSON Schema](https://json-schema.org/) is a popular vocabulary to describe the shape of JSON documents. A variant of JSON Schema is also used 4 | [in OpenAPI specifications](openapi.md). 5 | 6 | API Platform provides an infrastructure to generate JSON Schemas for any resource, represented in any format 7 | (including JSON-LD). 8 | The generated schema can be used with libraries such as [react-json-schema-form](https://github.com/rjsf-team/react-jsonschema-form) to build forms for the documented 9 | resources, or to [be used for validation](https://json-schema.org/implementations.html#validators). 10 | 11 | ## Generating a JSON Schema 12 | 13 | > [!WARNING] 14 | > These commands are not yet available with Laravel, you're welcome to contribute [on GitHub](https://github.com/api-platform/core) 15 | 16 | To export the schema corresponding to an API Resource, run the following command: 17 | 18 | ```console 19 | bin/console api:json-schema:generate 'App\ApiResource\Book' 20 | ``` 21 | 22 | To see all options available, try: 23 | 24 | ```console 25 | bin/console help api:json-schema:generate 26 | ``` 27 | 28 | ## Overriding the JSON Schema Specification 29 | 30 | In a unit testing context, API Platform does not use the same schema version as the schema used when generating the API 31 | documentation. The version used by the documentation is the OpenAPI Schema version and the version used by unit testing 32 | is the JSON Schema version. 33 | 34 | > [!NOTE] 35 | > For assertions about JSON schemas in Laravel, refer to the 36 | > [API Test Assertions in Laravel documentation](../laravel/testing.md#api-test-assertions-with-laravel). 37 | 38 | When [Testing the API](../core/testing.md), JSON Schemas are useful to generate and automate unit testing. API Platform provides specific 39 | unit testing functionalities like [`assertMatchesResourceCollectionJsonSchema()`](../symfony/testing.md#writing-functional-tests) or 40 | [`assertMatchesResourceItemJsonSchema()`](../symfony/testing.md#writing-functional-tests) methods. 41 | These methods generate a JSON Schema then do unit testing based on the generated schema automatically. 42 | 43 | Usually, the fact that API Platform uses a different schema version for unit testing is not a problem, but sometimes you 44 | may need to use the [`ApiProperty`](openapi.md#using-the-openapi-and-swagger-contexts) attribute to specify a [calculated field](serialization.md#calculated-field) type by overriding the OpenAPI Schema 45 | for the calculated field to be correctly documented. 46 | 47 | When you will use [`assertMatchesResourceCollectionJsonSchema()`](../symfony/testing.md#writing-functional-tests) or 48 | [`assertMatchesResourceItemJsonSchema()`](../symfony/testing.md#writing-functional-tests) functions the unit test will 49 | fail on this [calculated field](serialization.md#calculated-field) as the unit testing process doesn't use the `openapi_context`you specified because 50 | API Platform is using the JSON Schema version instead at this moment. 51 | 52 | So there is a way to override JSON Schema specification for a specific property in the JSON Schema used by the unit testing process. 53 | 54 | You will need to add the `json_schema_context` property in the [`ApiProperty`](openapi.md#using-the-openapi-and-swagger-contexts) 55 | attribute to do this, example: 56 | 57 | ```php 58 | 'integer', 71 | 'example' => 1 72 | ] 73 | )] 74 | private ?int $id = null; 75 | 76 | // [...] 77 | 78 | public function getId(): ?int 79 | { 80 | return $this->id; 81 | } 82 | 83 | #[ApiProperty( 84 | openapiContext: [ 85 | 'type' => 'array', 86 | 'items' => ['type' => 'integer'] 87 | ], 88 | jsonSchemaContext: [ 89 | 'type' => 'array', 90 | 'items' => ['type' => 'integer'] 91 | ] 92 | )] 93 | public function getSomeNumbers(): array { 94 | return [1, 2, 3, 4]; 95 | } 96 | } 97 | ``` 98 | 99 | You can obtain more information about the available [JSON Schema Types and format here](https://json-schema.org/understanding-json-schema/reference/type.html). 100 | 101 | ## Generating a JSON Schema Programmatically 102 | 103 | To generate JSON Schemas programmatically, use the `api_platform.json_schema.schema_factory`. 104 | 105 | For further information, please consult the following documentations: 106 | 107 | - [Symfony: Fetching and Using Services](https://symfony.com/doc/current/service_container.html#fetching-and-using-services) 108 | - [Laravel: Resolving Services](https://laravel.com/docs/container#resolving) 109 | 110 | ## Testing 111 | 112 | API Platform provides a PHPUnit assertion to test if a response is valid according to a given Schema: `assertMatchesJsonSchema()`. 113 | Refer to [the testing documentation](../core/testing.md) for more details. 114 | -------------------------------------------------------------------------------- /core/jwt.md: -------------------------------------------------------------------------------- 1 | # JWT Authentication 2 | 3 | > [JSON Web Token (JWT)](https://jwt.io/) is a JSON-based open standard ([RFC 7519](https://tools.ietf.org/html/rfc7519)) for creating access tokens that assert 4 | > some number of claims. For example, a server could generate a token that has the claim "logged in as admin" and 5 | > provide that to a client. The client could then use that token to prove that he/she is logged in as admin. 6 | > The tokens are signed by the server's key, so the server is able to verify that the token is legitimate. The tokens 7 | > are designed to be compact, URL-safe and usable especially in web browser single sign-on (SSO) context. 8 | > 9 | > ―[Wikipedia](https://en.wikipedia.org/wiki/JSON_Web_Token) 10 | 11 | - For Symfony users, check out the [JWT Authentication with Symfony documentation](/symfony/jwt.md). 12 | - For Laravel users, explore the [JWT Authentication with Laravel documentation](/laravel/jwt.md). 13 | -------------------------------------------------------------------------------- /core/operation-path-naming.md: -------------------------------------------------------------------------------- 1 | # Operation Path Naming 2 | 3 | With API Platform Core, you can configure the default resolver used to generate operation paths. 4 | Pre-registered resolvers are available and can easily be overridden. 5 | 6 | ## Configuration 7 | 8 | There are two pre-registered operation path naming services: 9 | 10 | | Service name | Entity name | Path result | 11 | |----------------------------------------------------------------|--------------|-----------------| 12 | | `api_platform.metadata.path_segment_name_generator.underscore` | `MyResource` | `/my_resources` | 13 | | `api_platform.metadata.path_segment_name_generator.dash` | `MyResource` | `/my-resources` | 14 | 15 | The default resolver is `api_platform.metadata.path_segment_name_generator.underscore`. 16 | 17 | ### Configuration using Symfony 18 | 19 | To change it to the dash resolver, add the following lines to `api/config/packages/api_platform.yaml`: 20 | 21 | ```yaml 22 | # api/config/packages/api_platform.yaml 23 | api_platform: 24 | path_segment_name_generator: api_platform.metadata.path_segment_name_generator.dash 25 | ``` 26 | 27 | ### Configuration using Laravel 28 | 29 | To change it to the dash resolver, add the following lines to `config/api-platform.php`: 30 | 31 | ```php 32 | 'api_platform.metadata.path_segment_name_generator.dash' 37 | ]; 38 | ``` 39 | 40 | ## Create a Custom Operation Path Resolver 41 | 42 | Let's assume we need URLs without separators (e.g. `api.tld/myresources`) 43 | 44 | ### Defining the Operation Segment Name Generator 45 | 46 | Make sure the custom segment generator implements [`ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface`](https://github.com/api-platform/core/blob/main/src/Metadata/Operation/PathSegmentNameGeneratorInterface.php): 47 | 48 | ```php 49 | dashize($name); 67 | 68 | return $name; 69 | } 70 | 71 | private function dashize(string $string): string 72 | { 73 | return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '-$1', $string)); 74 | } 75 | } 76 | ``` 77 | 78 | Note that `$name` contains a camelCase string, by default the resource class name (e.g. `MyResource`). 79 | 80 | ### Registering the Service (for Symfony only) 81 | 82 | If you haven't disabled the autowiring option, the service will be registered automatically and you have nothing more to 83 | do. 84 | Otherwise, you must register this class as a service like in the following example: 85 | 86 | ```yaml 87 | # api/config/services.yaml 88 | services: 89 | # ... 90 | 'App\Operation\SingularPathSegmentNameGenerator': ~ 91 | ``` 92 | 93 | ### Configuring the Service 94 | 95 | #### Configuring It using Symfony 96 | 97 | ```yaml 98 | # api/config/packages/api_platform.yaml 99 | api_platform: 100 | path_segment_name_generator: 'App\Operation\SingularPathSegmentNameGenerator' 101 | ``` 102 | 103 | #### Configuring It using Laravel 104 | 105 | ```php 106 | App\Operation\SingularPathSegmentNameGenerator::class 111 | ]; 112 | ``` 113 | -------------------------------------------------------------------------------- /core/push-relations.md: -------------------------------------------------------------------------------- 1 | # Pushing Related Resources Using HTTP/2 2 | 3 | > HTTP/2 allows a server to pre-emptively send (or "push") responses (along with corresponding "promised" requests) to 4 | > a client in association with a previous client-initiated request. This can be useful when the server knows the client 5 | > will need to have those responses available in order to fully process the response to the original request. 6 | > 7 | > —[RFC 7540](https://tools.ietf.org/html/rfc7540#section-8.2) 8 | 9 | API Platform leverages this capability by pushing relations of a resource to clients. 10 | 11 | > [!NOTE] 12 | > We strongly recommend using [Vulcain](https://vulcain.rocks) instead of this feature. 13 | > Vulcain is faster, cleaner, more flexible, and is supported out of the box in [the API Platform distribution](../symfony/index.md). 14 | 15 | ```php 16 | [ 45 | 'url_generation_strategy' => ApiPlatform\Metadata\UrlGeneratorInterface::ABS_URL 46 | ], 47 | ]; 48 | ``` 49 | 50 | ## Configure URL Generation for a Specific Resource 51 | 52 | It can also be configured only for a specific resource: 53 | 54 | 55 | 56 | ```php 57 | 82 | 83 | 84 | 85 | 90 | 91 | 92 | ``` 93 | 94 | 95 | 96 | For the above configuration, the collection will be like this: 97 | 98 | ```json 99 | { 100 | "@context": "http://example.com/contexts/Book", 101 | "@id": "http://example.com/books", 102 | "@type": "Collection", 103 | "member": [ 104 | { 105 | "@id": "http://example.com/books/1", 106 | "@type": "https://schema.org/Book", 107 | "name": "My awesome book" 108 | } 109 | ], 110 | "totalItems": 1 111 | } 112 | ``` 113 | -------------------------------------------------------------------------------- /core/validation.md: -------------------------------------------------------------------------------- 1 | # Validation 2 | 3 | API Platform takes care of validating the data sent to the API by the client (usually user data entered through forms). 4 | 5 | - For Symfony users, refer to the [Validation with Symfony documentation](/symfony/validation.md). 6 | - For Laravel users, refer to the [Validation with Laravel documentation](/laravel/validation.md). 7 | -------------------------------------------------------------------------------- /create-client/custom.md: -------------------------------------------------------------------------------- 1 | # Custom Generator 2 | 3 | Create Client provides support for many of the popular JS frameworks, but you may be using another framework or language and may need a solution adapted to your specific needs. For this scenario, you can write your own generator and pass it to the CLI using a path as the `-g` argument. 4 | 5 | You will probably want to extend or, at least, take a look at [BaseGenerator.js](https://github.com/api-platform/create-client/blob/main/src/generators/BaseGenerator.js), since the library expects some methods to be available, as well as one of the [included generators](https://github.com/api-platform/create-client/blob/main/src/generators/BaseGenerator.js) to make your own. 6 | 7 | ## Usage 8 | 9 | ```shell 10 | npm init @api-platform/client -- --generator "$(pwd)/path/to/custom/generator.js" -t "$(pwd)/path/to/templates" 11 | ``` 12 | 13 | The `-g` argument can point to any resolvable node module which means it can be a package dependency of the current project as well as any js file. 14 | 15 | ## Example 16 | 17 | Create Client makes use of the [Handlebars](https://handlebarsjs.com/) template engine. You can use any programming language or file type. Your generator can also pass data to your templates in any shape you want. 18 | 19 | In this example, we'll create a simple [Rust](https://www.rust-lang.org) file defining a new `struct` and creating some instances of this `struct`. 20 | 21 | ### Generator 22 | 23 | ```js 24 | // ./Generator.js 25 | import BaseGenerator from '@api-platform/create-client/lib/generators/BaseGenerator'; 26 | 27 | export default class extends BaseGenerator { 28 | constructor(params) { 29 | super(params); 30 | 31 | this.registerTemplates('', ['main.rs']); 32 | } 33 | 34 | help() {} 35 | 36 | generate(api, resource, dir) { 37 | const context = { 38 | type: 'Tilia', 39 | structure: [ 40 | { name: 'name', type: 'String' }, 41 | { name: 'min_size', type: 'u8' }, 42 | { name: 'max_size', type: 'u8' }, 43 | ], 44 | list: [ 45 | { 46 | name: 'Tilia cordata', 47 | minSize: 50, 48 | maxSize: 80, 49 | }, 50 | { 51 | name: 'Tilia platyphyllos', 52 | minSize: 50, 53 | maxSize: 70, 54 | }, 55 | { 56 | name: 'Tilia tomentosa', 57 | minSize: 50, 58 | maxSize: 70, 59 | }, 60 | { 61 | name: 'Tilia intermedia', 62 | minSize: 50, 63 | maxSize: 165, 64 | }, 65 | ], 66 | }; 67 | 68 | this.createDir(dir); 69 | 70 | this.createFile('main.rs', `${dir}/main.rs`, context, false); 71 | } 72 | } 73 | ``` 74 | 75 | ### Template 76 | 77 | ```rs 78 | // template/main.rs 79 | struct {{{type}}} { 80 | {{#each structure}} 81 | {{{name}}}: {{{type}}} 82 | {{/each}} 83 | } 84 | 85 | fn main() { 86 | let tilias = [ 87 | {{#each list}} 88 | Tilia { name: "{{{name}}}", min_size: {{{minSize}}}, max_size: {{{maxSize}}}, }, 89 | {{/each}} 90 | ]; 91 | } 92 | ``` 93 | 94 | Then we can use our generator: 95 | 96 | ```shell 97 | npm init @api-platform/client https://demo.api-platform.com out/ -g "$(pwd)/Generator.js" -t "$(pwd)/template" 98 | ``` 99 | 100 | which will produces: 101 | 102 | ```ts 103 | struct Tilia { 104 | name: String 105 | min_size: u8 106 | max_size: u8 107 | } 108 | 109 | fn main() { 110 | let tilias = [ 111 | Tilia { name: "Tilia cordata", min_size: 50, max_size: 80, }, 112 | Tilia { name: "Tilia platyphyllos", min_size: 50, max_size: 70, }, 113 | Tilia { name: "Tilia tomentosa", min_size: 50, max_size: 70, }, 114 | Tilia { name: "Tilia intermedia", min_size: 50, max_size: 165, }, 115 | ]; 116 | } 117 | ``` 118 | -------------------------------------------------------------------------------- /create-client/images/create-client-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/create-client-demo.gif -------------------------------------------------------------------------------- /create-client/images/nextjs/create-client-nextjs-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/nextjs/create-client-nextjs-list.png -------------------------------------------------------------------------------- /create-client/images/nextjs/create-client-nextjs-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/nextjs/create-client-nextjs-show.png -------------------------------------------------------------------------------- /create-client/images/nuxt/create-client-nuxt-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/nuxt/create-client-nuxt-edit.png -------------------------------------------------------------------------------- /create-client/images/nuxt/create-client-nuxt-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/nuxt/create-client-nuxt-list.png -------------------------------------------------------------------------------- /create-client/images/react-native/create-client-react-native-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react-native/create-client-react-native-add.png -------------------------------------------------------------------------------- /create-client/images/react-native/create-client-react-native-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react-native/create-client-react-native-delete.png -------------------------------------------------------------------------------- /create-client/images/react-native/create-client-react-native-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react-native/create-client-react-native-list.png -------------------------------------------------------------------------------- /create-client/images/react-native/create-client-react-native-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react-native/create-client-react-native-show.png -------------------------------------------------------------------------------- /create-client/images/react/create-client-react-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react/create-client-react-delete.png -------------------------------------------------------------------------------- /create-client/images/react/create-client-react-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react/create-client-react-edit.png -------------------------------------------------------------------------------- /create-client/images/react/create-client-react-list-pagination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react/create-client-react-list-pagination.png -------------------------------------------------------------------------------- /create-client/images/react/create-client-react-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react/create-client-react-list.png -------------------------------------------------------------------------------- /create-client/images/react/create-client-react-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/create-client/images/react/create-client-react-show.png -------------------------------------------------------------------------------- /create-client/index.md: -------------------------------------------------------------------------------- 1 | # API Platform Create Client 2 | 3 | Create Client is the fastest way to scaffold fully featured webapps 4 | and native mobile apps from APIs supporting the [Hydra](https://www.hydra-cg.com/) or [OpenAPI](https://www.openapis.org/) format. 5 | 6 | ![Screencast](images/create-client-demo.gif) 7 | 8 | ## Generated React and React Native Apps, Updated in Real Time 9 | 10 | It is able to generate apps using the following frontend stacks: 11 | 12 | - [Next.js](nextjs.md) 13 | - [Nuxt](nuxt.md) 14 | - [Quasar](quasar.md) 15 | - [Vuetify](vuetify.md) 16 | - [React](react.md) 17 | - [React Native](react-native.md) 18 | - [Vue.js](vuejs.md) 19 | - [Or bring your custom generator](custom.md) 20 | 21 | Create Client works especially well with APIs built with the [API Platform](https://api-platform.com) framework. 22 | 23 | ## Features 24 | 25 | - Generates high-quality TypeScript: 26 | - list view (with pagination) 27 | - detail view 28 | - creation form 29 | - update form 30 | - delete button 31 | - Supports to-one and to-many relations 32 | - Uses the appropriate input type (`number`, `date`...) 33 | - Client-side validation 34 | - Subscribes to data updates pushed by servers supporting [the Mercure protocol](https://mercure.rocks) 35 | - Displays server-side validation errors under the related input (if using API Platform Core) 36 | - Integration with [Tailwind CSS](https://tailwindcss.com) (Next.js) or [Bootstrap](https://getbootstrap.com/) and [Font Awesome](https://fontawesome.com/) (other generators) 37 | - Integration with [React Native Elements](https://react-native-training.github.io/react-native-elements/) 38 | - Accessible to people with disabilities ([ARIA](https://www.w3.org/WAI/intro/aria) support in webapps) 39 | -------------------------------------------------------------------------------- /create-client/nextjs.md: -------------------------------------------------------------------------------- 1 | # Next.js Generator 2 | 3 | ![List screenshot](images/nextjs/create-client-nextjs-list.png) 4 | 5 | The Next.js generator scaffolds components for server-side rendered (SSR) applications using [Next.js](https://nextjs.org/). 6 | 7 | ## Install 8 | 9 | The easiest way to get started is to install [the API Platform Symfony variant](../symfony/index.md). 10 | It contains a Next.js skeleton generated with Create Next App, 11 | a development Docker container to serve the webapp, and all the API Platform components you may need, including an API server 12 | supporting Hydra and OpenAPI. 13 | 14 | If you use API Platform, jump to the next section! 15 | 16 | Alternatively, create a Next.js application by executing: 17 | 18 | - Pnpm (recommended) 19 | ```console 20 | pnpm create next-app --typescript 21 | ``` 22 | - Npm 23 | ```console 24 | npm init next-app --typescript 25 | ``` 26 | - Yarn 27 | ```console 28 | yarn reate next-app --typescript 29 | ``` 30 | 31 | 32 | Install the required dependencies: 33 | 34 | - Pnpm (recommended) 35 | ```console 36 | pnpm install isomorphic-unfetch formik react-query 37 | ``` 38 | - Npm 39 | ```console 40 | npm install isomorphic-unfetch formik react-query 41 | ``` 42 | - Yarn 43 | ```console 44 | yarn add isomorphic-unfetch formik react-query 45 | ``` 46 | 47 | The generated HTML will contain [Tailwind CSS](https://tailwindcss.com) classes. 48 | Optionally, [follow the Tailwind installation guide for Next.js projects](https://tailwindcss.com/docs/guides/nextjs) 49 | (Tailwind is preinstalled in [the API Platform Symfony variant](../symfony/index.md)) 50 | 51 | ## Generating Routes 52 | 53 | If you are using the [API Platform Distribution with Symfony](../symfony/index.md) generating all the code you need for a given resource is as simple as running the following command: 54 | 55 | ```console 56 | docker compose exec pwa \ 57 | pnpm create @api-platform/client --resource book -g next 58 | ``` 59 | 60 | Omit the resource flag to generate files for all resource types exposed by the API. 61 | 62 | Or if you don't use the standalone installation, run the following command instead: 63 | 64 | - Pnpm (recommended) 65 | ```console 66 | pnpm create @api-platform/client https://demo.api-platform.com . --generator next --resource book 67 | ``` 68 | - Npm 69 | ```console 70 | npm init @api-platform/client https://demo.api-platform.com . -- --generator next --resource book 71 | ``` 72 | - Yarn 73 | ```console 74 | yarn create @api-platform/client https://demo.api-platform.com . --generator next --resource book 75 | ``` 76 | 77 | Replace the URL by the entrypoint of your Hydra-enabled API. 78 | You can also use an OpenAPI documentation with `-f openapi3`. 79 | 80 | The code has been generated, and is ready to be executed! 81 | 82 | Add the layout to the app: 83 | 84 | ```typescript 85 | import type { AppProps } from "next/app"; 86 | import type { DehydratedState } from "react-query"; 87 | 88 | import Layout from "../components/common/Layout"; 89 | 90 | const App = ({ Component, pageProps }: AppProps<{dehydratedState: DehydratedState}>) => ( 91 | 92 | 93 | 94 | ); 95 | 96 | export default App; 97 | ``` 98 | 99 | ## Starting the Project 100 | 101 | You can launch the server with: 102 | 103 | - Pnpm (recommended) 104 | ```console 105 | pnpm dev 106 | ``` 107 | - Npm 108 | ```console 109 | npm run dev 110 | ``` 111 | - Yarn 112 | ```console 113 | yarn dev 114 | ``` 115 | 116 | Go to `http://localhost:3000/books/` to start using your app. 117 | 118 | ## Generating a production build locally with docker compose 119 | 120 | If you want to generate a production build locally with docker compose, follow [these instructions](../deployment/docker-compose.md). 121 | 122 | ## Screenshots 123 | 124 | ![List](images/nextjs/create-client-nextjs-list.png) 125 | ![Show](images/nextjs/create-client-nextjs-show.png) 126 | -------------------------------------------------------------------------------- /create-client/nuxt.md: -------------------------------------------------------------------------------- 1 | # Nuxt Generator 2 | 3 | Bootstrap a [Nuxt 3](https://nuxt.com/) application: 4 | 5 | ```console 6 | npx nuxi init my-app 7 | cd my-app 8 | ``` 9 | 10 | Install the required dependencies: 11 | 12 | ```console 13 | yarn add dayjs @pinia/nuxt qs @types/qs 14 | ``` 15 | 16 | To generate the code you need for a given resource, run the following command: 17 | 18 | ```console 19 | yarn create @api-platform/client https://demo.api-platform.com . --generator nuxt --resource foo 20 | ``` 21 | 22 | Replace the URL with the entrypoint of your Hydra-enabled API. You can also use an OpenAPI documentation with `https://demo.api-platform.com/docs.jsonopenapi` and `-f openapi3`. 23 | 24 | Omit the resource flag to generate files for all resource types exposed by the API. 25 | 26 | Add Pinia module in `nuxt.config.ts`: 27 | 28 | ```typescript 29 | // https://nuxt.com/docs/api/configuration/nuxt-config 30 | export default defineNuxtConfig({ 31 | // ... 32 | modules: ['@pinia/nuxt'], 33 | // ... 34 | }); 35 | ``` 36 | 37 | Delete `app.vue` as it will prevent Nuxt router to work correctly. 38 | 39 | Optionally, install Tailwind to get an app that looks good: 40 | 41 | ```console 42 | yarn add -D tailwindcss postcss autoprefixer 43 | yarn tailwindcss init -p 44 | ``` 45 | 46 | Add this code in `nuxt.config.ts`: 47 | 48 | ```typescript 49 | // https://nuxt.com/docs/api/configuration/nuxt-config 50 | export default defineNuxtConfig({ 51 | // ... 52 | css: ['~/assets/css/main.css'], 53 | postcss: { 54 | plugins: { 55 | tailwindcss: {}, 56 | autoprefixer: {}, 57 | }, 58 | }, 59 | // ... 60 | }); 61 | ``` 62 | 63 | And this code in `tailwind.config.js`: 64 | 65 | ```javascript 66 | /** @type {import('tailwindcss').Config} */ 67 | module.exports = { 68 | content: [ 69 | './components/**/*.{js,vue,ts}', 70 | './layouts/**/*.vue', 71 | './pages/**/*.vue', 72 | './plugins/**/*.{js,ts}', 73 | './nuxt.config.{js,ts}', 74 | './app.vue', 75 | ], 76 | theme: { 77 | extend: {}, 78 | }, 79 | plugins: [], 80 | }; 81 | ``` 82 | 83 | Create the file `assets/css/main.css` and add this code in it: 84 | 85 | ```css 86 | @tailwind base; 87 | @tailwind components; 88 | @tailwind utilities; 89 | ``` 90 | 91 | You can launch the server with: 92 | 93 | ```console 94 | yarn dev -o 95 | ``` 96 | 97 | Go to `https://localhost:3000/books/` to start using your app. 98 | 99 | ## Screenshots 100 | 101 | ![List](images/nuxt/create-client-nuxt-list.png) 102 | ![Edit](images/nuxt/create-client-nuxt-edit.png) 103 | -------------------------------------------------------------------------------- /create-client/quasar.md: -------------------------------------------------------------------------------- 1 | # Quasar Framework Generator 2 | 3 | Create a Quasar Framework application using 4 | [Quasar CLI](https://quasar.dev/start/quasar-cli): 5 | 6 | ```console 7 | npm i -g @quasar/cli 8 | npm init quasar 9 | cd my-app 10 | ``` 11 | 12 | It will ask you some questions, you can use these answers: 13 | 14 | ```console 15 | What would you like to build ? App with Quasar CLI, let's go! 16 | Project folder: my-app 17 | Pick Quasar version: Quasar v2 (Vue 3 | latest and greatest) 18 | Pick script types: Typescript 19 | Pick Quasar App CLI variant: Quasar App CLI with Vite 20 | Package name: my-app 21 | Pick a Vue component style: Composition API with 40 | ``` 41 | 42 | Optionally, install Tailwind to get an app that looks good: 43 | 44 | ```console 45 | npm install -D tailwindcss postcss autoprefixer 46 | npx tailwindcss init -p 47 | ``` 48 | 49 | Replace the content of `tailwind.config.js` by: 50 | 51 | ```js 52 | // tailwind.config.js 53 | /** @type {import('tailwindcss').Config} */ 54 | module.exports = { 55 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 56 | theme: { 57 | extend: {}, 58 | }, 59 | plugins: [], 60 | }; 61 | ``` 62 | 63 | Replace the content of `src/assets/main.css` by: 64 | 65 | ```css 66 | @tailwind base; 67 | @tailwind components; 68 | @tailwind utilities; 69 | ``` 70 | 71 | You can launch the server with: 72 | 73 | ```console 74 | npm run dev 75 | ``` 76 | 77 | Go to `http://localhost:5173/books/` to start using your app. 78 | 79 | **Note:** In order to Mercure to work with the demo, you have to use the port 3000. 80 | -------------------------------------------------------------------------------- /create-client/vuetify.md: -------------------------------------------------------------------------------- 1 | # Vuetify Generator 2 | 3 | Bootstrap a Vuetify 3 application using `create-vuetify`: 4 | 5 | ```console 6 | npm init vuetify -- --typescript --preset essentials 7 | cd my-app 8 | ``` 9 | 10 | Install the required dependencies: 11 | 12 | ```console 13 | npm install dayjs qs @types/qs vue-i18n 14 | ``` 15 | 16 | To generate all the code you need for a given resource run the following command: 17 | 18 | ```console 19 | npm init @api-platform/client https://demo.api-platform.com src/ -- --generator vuetify --resource book 20 | ``` 21 | 22 | Replace the URL with the entrypoint of your Hydra-enabled API. 23 | You can also use an OpenAPI documentation with `https://demo.api-platform.com/docs.jsonopenapi` and `-f openapi3`. 24 | 25 | Omit the resource flag to generate files for all resource types exposed by the API. 26 | 27 | **Note:** Make sure to follow the result indications of the command to register the routes and the translations. 28 | 29 | Then add this import in `src/plugins/vuetify.ts`: 30 | 31 | ```typescript 32 | // src/plugins/vuetify.ts 33 | import { VDataTableServer } from 'vuetify/labs/VDataTable'; 34 | ``` 35 | 36 | In the same file replace the export with: 37 | 38 | ```typescript 39 | // src/plugins/vuetify.ts 40 | export default createVuetify({ 41 | components: { 42 | VDataTableServer, 43 | }, 44 | }); 45 | ``` 46 | 47 | In `src/plugins/index.ts` add this import: 48 | 49 | ```typescript 50 | // src/plugins/index.ts 51 | import i18n from '@/plugins/i18n'; 52 | ``` 53 | 54 | In the same file add `.use(i18n)` chained with the other `use()` functions. 55 | 56 | You can launch the server with: 57 | 58 | ```console 59 | npm run dev 60 | ``` 61 | 62 | Go to `http://localhost:3000/books/` to start using your app. 63 | 64 | **Note:** In order to Mercure to work with the demo, you have to use the port 3000. 65 | -------------------------------------------------------------------------------- /deployment/heroku.md: -------------------------------------------------------------------------------- 1 | # Deploying an API Platform App on Heroku 2 | 3 | [Heroku](https://www.heroku.com) is a popular, fast, scalable and reliable _Platform As A Service_ (PaaS). As Heroku offers a 4 | free plan including database support through [Heroku Postgres](https://www.heroku.com/postgres), it's a convenient way 5 | to experiment with API Platform. 6 | 7 | The API Platform Heroku integration also supports MySQL databases provided by [the ClearDB add-on](https://addons.heroku.com/cleardb). 8 | 9 | Deploying API Platform applications on Heroku is straightforward and you will learn how to do it in this tutorial. 10 | 11 | _Note: this tutorial works perfectly well with API Platform but also with any Symfony application based on the Symfony Standard 12 | Edition._ 13 | 14 | If you don't already have one, [create an account on Heroku](https://signup.heroku.com/signup/dc). Then install [the Heroku 15 | toolbelt](https://devcenter.heroku.com/articles/getting-started-with-php#set-up). We're guessing you already 16 | have a working install of [Composer](https://getcomposer.org/). Perfect, we will need it. 17 | 18 | Create a new [API Platform Symfony project](symfony/index.md) which will be used in the rest of this example. 19 | 20 | Heroku relies on [environment variables](https://devcenter.heroku.com/articles/config-vars) for its configuration. Regardless 21 | of what provider you choose for hosting your application, using environment variables to configure your production environment 22 | is a best practice promoted by API Platform. 23 | 24 | Create a Heroku `app.json` file at the root of the `api/` directory to configure the deployment: 25 | 26 | ```json 27 | { 28 | "success_url": "/", 29 | "env": { 30 | "APP_ENV": "prod", 31 | "APP_SECRET": { "generator": "secret" }, 32 | "CORS_ALLOW_ORIGIN": "https://your-client-url.com" 33 | }, 34 | "addons": ["heroku-postgresql"], 35 | "buildpacks": [ 36 | { 37 | "url": "https://github.com/heroku/heroku-buildpack-php" 38 | } 39 | ], 40 | "scripts": { 41 | "postdeploy": "php bin/console doctrine:schema:create" 42 | } 43 | } 44 | ``` 45 | 46 | The file also tells the Heroku deployment system to build a PHP container and to add the Postgres add-on. 47 | 48 | We are almost done, but API Platform (and Symfony) has a particular directory structure which requires further configuration. 49 | We must tell Heroku that the document root is `public/`, and that all other directories must be private. 50 | 51 | Create a new file named `Procfile` in the `api/` directory with the following content: 52 | 53 | ```yaml 54 | web: vendor/bin/heroku-php-apache2 public/ 55 | ``` 56 | 57 | Be sure to add the Apache Pack to your dependencies: 58 | 59 | ```console 60 | composer require symfony/apache-pack 61 | ``` 62 | 63 | As Heroku doesn't support Varnish out of the box, let's disable its integration: 64 | 65 | ```diff 66 | # api/config/packages/api_platform.yaml 67 | - http_cache: 68 | - invalidation: 69 | - enabled: true 70 | - varnish_urls: ['%env(VARNISH_URL)%'] 71 | - max_age: 0 72 | - shared_max_age: 3600 73 | - vary: ['Content-Type', 'Authorization', 'Origin'] 74 | - public: true 75 | ``` 76 | 77 | Heroku provides another free service, [Logplex](https://devcenter.heroku.com/articles/logplex), which allows us to centralize 78 | and persist application logs. Because API Platform writes logs on `STDERR`, it will work seamlessly. 79 | 80 | However, if you use Monolog instead of the default logger, you'll need to configure it to output to `STDERR` instead of 81 | in a file. 82 | 83 | Open `api/config/packages/prod/monolog.yaml` and apply the following patch: 84 | 85 | ```diff 86 | handlers: 87 | nested: 88 | type: stream 89 | - path: "%kernel.logs_dir%/%kernel.environment%.log" 90 | + path: php://stderr 91 | level: debug 92 | ``` 93 | 94 | We are now ready to deploy our app! 95 | 96 | Go to the `api/` directory, then 97 | 98 | 1. Initialize a Git repository: 99 | 100 | ```console 101 | git init 102 | ``` 103 | 104 | 2. Add all existing files: 105 | 106 | ```console 107 | git add --all 108 | ``` 109 | 110 | 3. Commit: 111 | 112 | ```console 113 | git commit -a -m "My first API Platform app running on Heroku!" 114 | ``` 115 | 116 | 4. Create the Heroku application: 117 | 118 | ```console 119 | heroku create 120 | ``` 121 | 122 | 5. And deploy for the first time: 123 | 124 | ```console 125 | git push heroku master 126 | ``` 127 | 128 | **We're done.** You can play with the demo API provided with API Platform. It is ready for production and you 129 | can scale it in one click from the Heroku interface. 130 | 131 | To see your logs, run `heroku logs --tail`. 132 | -------------------------------------------------------------------------------- /deployment/images/deploy-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/deployment/images/deploy-result.png -------------------------------------------------------------------------------- /deployment/images/digitalocean-dns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/deployment/images/digitalocean-dns.png -------------------------------------------------------------------------------- /deployment/images/digitalocean-droplet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/deployment/images/digitalocean-droplet.png -------------------------------------------------------------------------------- /deployment/images/google-image-caddy-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/deployment/images/google-image-caddy-details.png -------------------------------------------------------------------------------- /deployment/images/google-image-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/deployment/images/google-image-overview.png -------------------------------------------------------------------------------- /deployment/index.md: -------------------------------------------------------------------------------- 1 | # Deploying API Platform Applications 2 | 3 | API Platform apps are super easy to deploy in production thanks to the [Docker Compose definition](docker-compose.md) and to the [Kubernetes chart](kubernetes.md) we provide. 4 | 5 | We strongly recommend using Kubernetes or Docker Compose to deploy your apps. 6 | 7 | If you want to play with a local Kubernetes cluster, read [how to deploy an API Platform project on Minikube](minikube.md). 8 | 9 | If you don't want to use Docker, keep in mind that the server application of API Platform is a standard Symfony project, 10 | while the Progressive Web Application is a standard Next.js project: 11 | 12 |

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

13 | 14 | - [Deploying the Symfony application](https://symfony.com/doc/current/deployment.html) 15 | - [Deploying the Next.js application](https://nextjs.org/docs/deployment) 16 | 17 | Alternatively, you may want to deploy API Platform on a PaaS (Platform as a Service): 18 | 19 | - [Deploying the server application of API Platform on Heroku](heroku.md) 20 | - [Deploying API Platform on Platform.sh (outdated)](https://platform.sh/blog/deploy-api-platform-on-platformsh) 21 | -------------------------------------------------------------------------------- /deployment/minikube.md: -------------------------------------------------------------------------------- 1 | # Deploying to minikube 2 | 3 | ## Install minikube 4 | 5 | If you have no existing installation of minikube on your computer, [follow the official tutorial](https://minikube.sigs.k8s.io/docs/start/). 6 | 7 | When Minikube is installed, start the cluster: 8 | 9 | ```console 10 | minikube start --addons registry --addons dashboard 11 | ``` 12 | 13 | The previous command starts minikube with a Docker registry (we'll use it in the next step) and with the Kubernetes dashboard. 14 | 15 | Finally, [install Helm](https://helm.sh/docs/intro/install/). We'll use it to deploy the application in the cluster thanks to the chart provided in the API Platform distribution. 16 | 17 | ## Building and Pushing Docker Images 18 | 19 | On GNU/Linux and macOS, run the following command to point your terminal's docker-cli to the Docker Engine inside minikube: 20 | 21 | ```console 22 | eval $(minikube docker-env) 23 | ``` 24 | 25 | Now any `docker` command you run in this current terminal will run against the Docker Engine inside the minikube cluster. For detailed explanation and instructions for Windows [visit official minikube documentation](https://minikube.sigs.k8s.io/docs/handbook/pushing/#1-pushing-directly-to-the-in-cluster-docker-daemon-docker-env). 26 | 27 | Build the images in minikube: 28 | 29 | ```console 30 | docker build -t localhost:5000/php api --target frankenphp_prod 31 | docker build -t localhost:5000/pwa pwa --target prod 32 | ``` 33 | 34 | Then push the images in the registry available in minikube: 35 | 36 | ```console 37 | docker push localhost:5000/php 38 | docker push localhost:5000/pwa 39 | ``` 40 | 41 | ## Deploying 42 | 43 | Fetch Helm chart dependencies: 44 | 45 | ```console 46 | helm repo add bitnami https://charts.bitnami.com/bitnami/ 47 | helm dependency build helm/api-platform 48 | ``` 49 | 50 | Finally, deploy the project using the Helm chart: 51 | 52 | ```console 53 | helm upgrade --install my-project helm/api-platform \ 54 | --set php.image.repository=localhost:5000/php \ 55 | --set php.image.tag=latest \ 56 | --set pwa.image.repository=localhost:5000/pwa \ 57 | --set pwa.image.tag=latest 58 | ``` 59 | 60 | Copy and paste the commands displayed in the terminal to enable the port forwarding then go to `http://localhost:8080` to access your application! 61 | 62 | Run `minikube dashboard` at any moment to see the state of your deployments. 63 | 64 | ## Using Skaffold 65 | 66 | Skaffold is a tool for Kubernetes development: [https://skaffold.dev/](https://skaffold.dev/). 67 | 68 | It will build and deploy automatically your app in Kubernetes and apply every changes. The default configuration use minikube and helm. More configurations are available in Skaffold documentation. 69 | 70 | First, install the [skaffold CLI](https://skaffold.dev/docs/install/#standalone-binary). 71 | 72 | Then, run minikube: 73 | 74 | ```console 75 | minikube start 76 | ``` 77 | 78 | Add Skaffold configuration in the file `./helm/skaffold.yaml`. You can find a [complete configuration file for minikube](https://github.com/api-platform/api-platform/blob/main/helm/skaffold.yaml) with its [Helm values override](https://github.com/api-platform/api-platform/blob/main/helm/skaffold-values.yaml). 79 | 80 | Finally, go to the helm folder, and run skaffold in dev mode: 81 | 82 | ```console 83 | cd ./helm 84 | skaffold dev 85 | ``` 86 | -------------------------------------------------------------------------------- /extra/conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, ethnic group, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | - The use of sexualized language or imagery 16 | - Personal attacks 17 | - Trolling or insulting/derogatory comments 18 | - Public or private harassment 19 | - Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | - Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at kevin+api-platform-coc [at] dunglas.fr. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality regarding the reporter of an 42 | incident. 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 45 | version 1.3.0, available at 46 | [http://contributor-covenant.org/version/1/3/0/][version] 47 | 48 | [homepage]: http://contributor-covenant.org 49 | [version]: http://contributor-covenant.org/version/1/3/0/ 50 | -------------------------------------------------------------------------------- /extra/contribution-guides.md: -------------------------------------------------------------------------------- 1 | # Contribution Guides 2 | 3 | ## API Platform Core 4 | - [General Contribution Guide](https://github.com/api-platform/core/blob/main/CONTRIBUTING.md) 5 | - [Laravel-Specific Contribution Guide](https://github.com/api-platform/core/blob/main/src/Laravel/CONTRIBUTING.md) 6 | 7 | ## API Platform Documentation 8 | - [General Contribution Guide](https://github.com/api-platform/docs/blob/main/CONTRIBUTING.md) 9 | 10 | ## API Platform Tools 11 | - [Schema Generator Contribution Guide](https://github.com/api-platform/schema-generator/blob/main/CONTRIBUTING.md) 12 | - [Admin Contribution Guide](https://github.com/api-platform/admin/blob/master/CONTRIBUTING.md) 13 | - [CRUD Generator Contribution Guide](https://github.com/api-platform/create-client/blob/master/CONTRIBUTING.md) 14 | 15 | **To report a security issue, please take a look at [the dedicated document](security.md).** 16 | 17 |

JWT screencast
Watch the Contributing back to Symfony screencast (free)

18 | -------------------------------------------------------------------------------- /extra/enterprise.md: -------------------------------------------------------------------------------- 1 | # API Platform for Enterprise 2 | 3 | API Platform is available as part of [the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise). 4 | 5 | [Tidelift](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) is working with the maintainers of API Platform and thousands of other 6 | open source projects to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. 7 | 8 | - [Learn more](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 9 | - [Request a demo](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 10 | 11 | ## Enterprise-ready open source software—managed for you 12 | 13 | [The Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) is a managed open source subscription for application dependencies covering millions of open source projects across JavaScript, Python, Java, PHP, Ruby, .NET, and more. 14 | 15 | Your subscription includes: 16 | 17 | - **Security updates**: Tidelift’s security response team coordinates patches for new breaking security vulnerabilities and alerts immediately through a private channel, so your software supply chain is always secure. 18 | - **Licensing verification and indemnification**: Tidelift verifies license information to enable easy policy enforcement and adds intellectual property indemnification to cover creators and users in case something goes wrong. You always have a 100% up-to-date bill of materials for your dependencies to share with your legal team, customers, or partners. 19 | - **Maintenance and code improvement**: Tidelift ensures the software you rely on keeps working as long as you need it to work. Your managed dependencies are actively maintained and we recruit additional maintainers where required. 20 | - **Package selection and version guidance**: We help you choose the best open source packages from the start—and then guide you through updates to stay on the best releases as new issues arise. 21 | - **Roadmap input**: Take a seat at the table with the creators behind the software you use. Tidelift’s participating maintainers earn more income as their software is used by more subscribers, so they’re interested in knowing what you need. 22 | - **Tooling and cloud integration**: Tidelift works with GitHub, GitLab, BitBucket, and more. We support every cloud platform (and other deployment targets, too). 23 | 24 | The end result? All of the capabilities you expect from commercial-grade software, for the full breadth of open source you use. That means less time grappling with esoteric open source trivia, and more time building your own applications—and your business. 25 | 26 | - [Learn more](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 27 | - [Request a demo](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 28 | -------------------------------------------------------------------------------- /extra/philosophy.md: -------------------------------------------------------------------------------- 1 | # API Platform's Philosophy 2 | 3 | In 25 years of PHP, the web changed dramatically and is now evolving faster than ever: 4 | 5 | - Thanks to awesome frontend technologies such as [React](https://reactjs.org/) or [Vue.js](https://vuejs.org/), 6 | [full-JavaScript Progressive Web Apps](https://en.wikipedia.org/wiki/Progressive_web_application) **are becoming the standard**. 7 | - [Internet users spend more time on their mobile devices than on desktops](https://www.broadbandsearch.net/blog/mobile-desktop-internet-usage-statistics): having a mobile-first website is mandatory and **native mobile apps are a must have**. 8 | - [The semantic web](https://en.wikipedia.org/wiki/Semantic_Web) and **especially [Linked Data](https://en.wikipedia.org/wiki/Linked_data) 9 | is a reality**: with the [Schema.org](https://schema.org/) initiative and new open web standards such as [JSON-LD](https://json-ld.org/), 10 | search engines (among a bunch of other services and software) consume structured and machine-readable data at web scale. 11 | Not exposing such data decrease interoperability and search engine ranking/efficiency (think rich snippets). 12 | - HTTP/2 and HTTP/3 [dramatically improve the performance of web applications](https://vulcain.rocks) thanks to multiplexing, Server Push and their other new capabilities. 13 | 14 | [PHP.net](https://www.php.net), [Symfony](https://symfony.com), [Facebook](https://hhvm.com/) and many others have worked hard 15 | to improve and professionalize the PHP ecosystem. The PHP world has closed the gap with most backend solutions and is often 16 | [more innovative](https://wiki.php.net/rfc) and [faster](https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/php-python3.html) than them. 17 | 18 | However in critical areas I've described previously, many things can be improved. Almost all existing solutions are still [designed 19 | and documented](https://symfony.com/doc/current/book/page_creation.html) to create websites the old way: a server generates 20 | then sends plain-old HTML documents to browsers. 21 | 22 | [API Platform](https://api-platform.com) is a set of tools for building modern web projects. It is a framework 23 | for API-first projects built on top of [Symfony components](https://symfony.com/projects/apiplatform). 24 | Like other modern frameworks such as Laravel and Symfony, it's both a full-stack all-in-one framework and a set of independent PHP components and bundles that can be used separately. 25 | 26 | API Platform makes modern development easy and fun again: 27 | 28 | - [Start by **creating a web API**](../symfony/index.md) exposing structured data that can 29 | be understood by any compliant client such as your apps but also search engines (JSON-LD with Schema.org vocabulary). 30 | This API is the central and unique entry point to access and modify data. It also encapsulates the whole business logic. 31 | - [Then **create as many clients as you want using frontend technologies you love**](../create-client/index.md): a JavaScript 32 | webapp built with React or with Vue querying the API but also a native iOS or Android app, or even a desktop application. Clients 33 | only display data and forms. 34 | 35 | See also [the general design](../core/design.md) of the framework. 36 | -------------------------------------------------------------------------------- /extra/releases.md: -------------------------------------------------------------------------------- 1 | # The Release Process 2 | 3 | API Platform follows the [Semantic Versioning](https://semver.org) strategy. 4 | A new minor version is released every six months, and a new major version is released every two years, along with a last minor version on the previous major one with the same features and an upgrade path. 5 | 6 | For example: 7 | 8 | - version 3.0 has been released on 15 September 2022; 9 | - version 3.1 has been released on 23 January 2023; 10 | - version 3.2 has been released on 12 October 2023; 11 | - version 3.3 has been released on 9 April 2024 (we were a little late, it should have been published in March); 12 | - versions 3.4 has been released on 18 September 2024; 13 | - versions 4.0 has been released on 27 September 2024; 14 | - versions 4.1 has been released on 28 February 2025; 15 | 16 | ## Maintenance 17 | 18 | 3 versions are maintained at the same time: 19 | 20 | - **stable** (currently the **4.1** branch): regular bugfixes are integrated in this version 21 | - **old-stable** (are the last branch: **4.0**): [security fixes](security.md) are integrated in this version, regular bugfixes are **not** backported in it 22 | - **development** (**main** branch): new features target this branch 23 | 24 | Older versions (1.x, 2.6..., 3.0...) **are not maintained**. If you still use them, you must upgrade as soon as possible. 25 | 26 | The **old-stable** branch is merged in the **stable** branch on a regular basis to propagate [security fixes](security.md). 27 | The **stable** branch is merged in the **development** branch on a regular basis to propagate [security](security.md) and regular bugfixes. 28 | 29 | New major versions of API Platform are released every 2 years. 30 | New minor versions of API Platform are released every 6 months. 31 | 32 | The latest minor version of a major branch contains all the new features introduced in the first version of the next major, but also contains deprecated features which are removed in the next major branch. 33 | -------------------------------------------------------------------------------- /extra/security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | This document explains how API Platform security issues are handled by the API Platform core team (API Platform being the code hosted in [the `api-platform` GitHub organization](https://github.com/api-platform)). 4 | 5 | ## Reporting a Security Issue 6 | 7 | If you think that you have found a security issue in API Platform, don't use the bug tracker and don't publish it publicly. Instead, all security issues must be sent to kevin+api-platform-security [at] dunglas.fr. 8 | 9 | ## Resolving Process 10 | 11 | For each report, we first try to confirm the vulnerability. When it is confirmed, the core team works on a solution following these steps: 12 | 13 | 1. Send an acknowledgment to the reporter; 14 | 2. Work on a patch; 15 | 3. Get a CVE identifier from [mitre.org](https://cveform.mitre.org); 16 | 4. Send the patch to the reporter for review; 17 | 5. Apply the patch to all [maintained versions](releases.md) of API Platform; 18 | 6. Package new versions for all affected versions; 19 | 7. If the affected package is written in PHP, update the public [security advisories database](https://github.com/FriendsOfPHP/security-advisories) maintained by the FriendsOfPHP organization and which is used by the `check:security` command. 20 | 21 | While we are working on a patch, please do not reveal the issue publicly. 22 | 23 | The resolution takes anywhere between a couple of days to some months depending on its complexity and the coordination with the downstream projects (see next paragraph). 24 | 25 | ## Security Updates With Tidelift 26 | 27 | API Platform Core is part of [the Tidelift subscription](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise): verified updates for zero-day vulnerabilities, coordinated security responses, and immediate notifications of which of your applications are impacted, with the fix prepared for you! 28 | 29 | - [Learn more](https://tidelift.com/subscription/pkg/packagist-api-platform-core?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 30 | - [Request a demo](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-api-platform-core&utm_medium=referral&utm_campaign=enterprise) 31 | 32 | ## Issue Severity 33 | 34 | In order to determine the severity of a security issue we take into account the complexity of any potential attack, the impact of the vulnerability and also how many projects it is likely to affect. This score out of 15 is then converted into a level of: Low, Medium, High, Critical, or Exceptional. 35 | 36 | ### Attack Complexity 37 | 38 | Score of between 1 and 5 depending on how complex it is to exploit the vulnerability 39 | 40 | - 4 - 5 Basic: attacker must follow a set of simple steps 41 | - 2 - 3 Complex: attacker must follow non-intuitive steps with a high level of dependencies 42 | - 1 - 2 High: A successful attack depends on conditions beyond the attacker's control. That is, a successful attack cannot be accomplished at will, but requires the attacker to invest in some measurable amount of effort in preparation or execution against the vulnerable component before a successful attack can be expected. 43 | 44 | ### Impact 45 | 46 | Scores from the following areas are added together to produce a score. The score for Impact is capped at 6. Each area is scored between 0 and 4. 47 | 48 | - Integrity: Does this vulnerability cause non-public data to be accessible? If so, does the attacker have control over the data disclosed? (0-4) 49 | - Disclosure: Can this exploit allow system data (or data handled by the system) to be compromised? If so, does the attacker have control over modification? (0-4) 50 | - Code Execution: Does the vulnerability allow arbitrary code to be executed on an end users system, or the server that it runs on? (0-4) 51 | - Availability: Is the availability of a service or application affected? Is it reduced availability or total loss of availability of a service / application? Availability includes networked services (e.g., databases) or resources such as consumption of network bandwidth, processor cycles, or disk space. (0-4) 52 | 53 | ### Affected Projects 54 | 55 | Scores from the following areas are added together to produce a score. The score for Affected Projects is capped at 4. 56 | 57 | - Will it affect some or all projects using a component? (1-2) 58 | - Is the usage of the component that would cause such a thing already considered bad practice? (0-1) 59 | - How common/popular is the component (e.g. Core vs Distribution vs Schema Generator)? (0-2) 60 | - Are a number of well-known FOSS projects using API Platform affected that requires coordinated releases? (0-1) 61 | 62 | ### Score Totals 63 | 64 | - Attack Complexity: 1 - 5 65 | - Impact: 1 - 6 66 | - Affected Projects: 1 - 4 67 | 68 | ### Severity levels 69 | 70 | - Low: 1 - 5 71 | - Medium: 6 - 10 72 | - High: 11 - 12 73 | - Critical: 13 - 14 74 | - Exceptional: 15 75 | 76 | ## Credits 77 | 78 | This document has been adapted from the [Symfony's security policy](https://symfony.com/doc/current/contributing/code/security.html). 79 | -------------------------------------------------------------------------------- /extra/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | This is a list of common pitfalls while using API Platform, and how to avoid them. 4 | 5 | ## Using Docker 6 | 7 | ### With Docker Toolbox on Windows 8 | 9 | Docker Toolbox is not supported anymore by API Platform. Please upgrade to [Docker for Windows](https://www.docker.com/docker-windows). 10 | 11 | ### Error Starting The Web Server 12 | 13 | If the `php` container cannot start and display this `Error starting userland proxy: Bind for 0.0.0.0:80`, it means that port 80 is already in use. You can check to see which processes are currently listening on certain ports. 14 | 15 | Find out if any service listens on port 80. You can use this command on UNIX-based OSes like macOS and Linux: 16 | 17 | ```console 18 | sudo lsof -n -i :80 | grep LISTEN 19 | ``` 20 | 21 | On Windows, you can use `netstat`. This will give you all TCP/IP network connections and not just processes listening to port 80. 22 | 23 | ```console 24 | netstat -a -b 25 | ``` 26 | 27 | The same problem may occur for port 443. In this case, follow the same steps but replace 80 by 443. 28 | 29 | You can change the port to be used in the `compose.yaml` file (default ports are 443 and 80). 30 | 31 | ## Using API Platform and JMS Serializer in the same project 32 | 33 | For the latest versions of [JMSSerializerBundle](https://jmsyst.com/bundles/JMSSerializerBundle), there is no conflict so everything should work out of the box. 34 | 35 | If you are still using the old, unmaintained v1 of JMSSerializerBundle, the best way would be to [upgrade to v2](https://github.com/schmittjoh/JMSSerializerBundle/blob/2.4.2/UPGRADING.md#upgrading-from-1x-to-20) of JMSSerializerBundle. 36 | 37 | In v1 of JMSSerializerBundle, the `serializer` alias is registered for the JMS Serializer service by default. However, API Platform requires the Symfony Serializer (and not the JMS one) to work properly. If you cannot upgrade for some reason, this behavior can be deactivated using the following configuration: 38 | 39 | ```yaml 40 | # api/config/packages/jms_serializer.yaml 41 | jms_serializer: 42 | enable_short_alias: false 43 | ``` 44 | 45 | The JMS Serializer service is available as `jms_serializer`. 46 | 47 | **Note:** if you are using JMSSerializerBundle along with FOSRestBundle and considering migrating to API Platform, you might want to take a look at [this guide](migrate-from-fosrestbundle.md) too. 48 | 49 | ## "upstream sent too big header while reading response header from upstream" NGINX 502 Error 50 | 51 | Some of your API calls fail with a 502 error and the logs for the API container shows the following error message `upstream sent too big header while reading response header from upstream`. 52 | 53 | This can be due to the cache invalidation headers that are too big for NGINX. When you query the API, API Platform adds the IDs of all returned entities and their dependencies in the headers like so : `Cache-Tags: /entity/1,/dependent_entity/1,/entity/2`. This can overflow the default header size (4k) when your API gets larger and more complex. 54 | 55 | You can modify the PHP FPM configuration file and set values to `fastcgi_buffer_size` and `fastcgi_buffers` that suit your needs, like so: 56 | 57 | ```nginx 58 | server { 59 | root /app/public; 60 | 61 | location / { 62 | # try to serve file directly, fallback to index.php 63 | try_files $uri /index.php$is_args$args; 64 | } 65 | 66 | location ~ ^/index\.php(/|$) { 67 | # Comment the next line and uncomment the next to enable dynamic resolution (incompatible with Kubernetes) 68 | fastcgi_pass php:9000; 69 | #resolver 127.0.0.11; 70 | #set $upstream_host php; 71 | #fastcgi_pass $upstream_host:9000; 72 | 73 | # Bigger buffer size to handle cache invalidation headers expansion 74 | fastcgi_buffer_size 32k; 75 | fastcgi_buffers 8 16k; 76 | 77 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 78 | include fastcgi_params; 79 | # When you are using symlinks to link the document root to the 80 | # current version of your application, you should pass the real 81 | # application path instead of the path to the symlink to PHP 82 | # FPM. 83 | # Otherwise, PHP's OPcache may not properly detect changes to 84 | # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 85 | # for more information). 86 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; 87 | fastcgi_param DOCUMENT_ROOT $realpath_root; 88 | # Prevents URIs that include the front controller. This will 404: 89 | # http://domain.tld/index.php/some-path 90 | # Remove the internal directive to allow URIs like this 91 | internal; 92 | } 93 | 94 | # return 404 for all other php files not matching the front controller 95 | # this prevents access to other php files you don't want to be accessible. 96 | location ~ \.php$ { 97 | return 404; 98 | } 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /laravel/images/basic-rest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/basic-rest.png -------------------------------------------------------------------------------- /laravel/images/books-collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/books-collection.png -------------------------------------------------------------------------------- /laravel/images/empty-docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/empty-docs.png -------------------------------------------------------------------------------- /laravel/images/filters-documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/filters-documentation.png -------------------------------------------------------------------------------- /laravel/images/form-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/form-request.png -------------------------------------------------------------------------------- /laravel/images/graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/graphql.png -------------------------------------------------------------------------------- /laravel/images/property-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/property-placeholder.png -------------------------------------------------------------------------------- /laravel/images/read-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/read-only.png -------------------------------------------------------------------------------- /laravel/images/title-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/laravel/images/title-filter.png -------------------------------------------------------------------------------- /laravel/jwt.md: -------------------------------------------------------------------------------- 1 | # JWT Authentication with Laravel 2 | 3 | > [!NOTE] 4 | > While solutions like `tymondesigns/jwt-auth` (Laravel) or `LexikJWTAuthenticationBundle` (Symfony) are popular, 5 | > **we recommend adopting open standards such as [OpenID Connect (OIDC)](https://openid.net/connect/)** for robust, scalable, 6 | > and interoperable authentication. 7 | 8 | For comprehensive details on authentication, refer to our [Laravel Authentication documentation](../laravel/index.md#authentication). 9 | 10 | ## Setup Instructions 11 | 12 | 1. **Install** 13 | Follow the official installation guide of [Laravel Passport](https://laravel.com/docs/passport#installation) to implement 14 | OpenID Connect (OIDC) standards in your Laravel application. 15 | Alternatively, if you prefer an ad-hoc solution, you can use [tymondesigns/jwt-auth](https://github.com/tymondesigns/jwt-auth) 16 | to set up JWT authentication in your Laravel project. 17 | 18 | 2. **Configure Authentication** 19 | Refer to the [Authentication section](../laravel/index.md#authentication) of our documentation to properly configure 20 | and secure your API with JWT tokens. 21 | 22 | > [!TIP] 23 | > Use [Laravel middlewares with API Platform](../laravel/index.md#middlewares) such as `auth:api` to 24 | > restrict access to certain endpoints, ensuring only authenticated users can access them. 25 | 26 | By following these steps, you can set up a secure and scalable JWT-based authentication system in your Laravel application. 27 | 28 | ## Testing 29 | 30 | To verify your authentication setup using `ApiTestCase`, you can write a test method tailored to your preferred testing 31 | framework. Here's how you can approach it for both **Pest** and **PHPUnit**: 32 | 33 | > [!NOTE] 34 | > Ensure your routes (/api/auth) and authentication mechanisms are configured to match your application's implementation. 35 | 36 | ### Test with Pest 37 | 38 | ```php 39 | create([ 49 | 'email' => 'test@example.com', 50 | 'password' => bcrypt('$3CR3T'), // Hash the password 51 | ]); 52 | 53 | // Retrieve a token 54 | $response = $this->postJson('/api/auth', [ 55 | 'email' => 'test@example.com', 56 | 'password' => '$3CR3T', 57 | ]); 58 | 59 | $response->assertStatus(200) 60 | ->assertJsonStructure(['token']); 61 | 62 | $token = $response->json('token'); 63 | 64 | // Test not authorized 65 | $this->getJson('/api/greetings') 66 | ->assertStatus(401); 67 | 68 | // Test authorized 69 | $this->withHeader('Authorization', "Bearer $token") 70 | ->getJson('/api/greetings') 71 | ->assertStatus(200); 72 | }); 73 | ``` 74 | 75 | ### Test with PHPUnit 76 | 77 | ```php 78 | create([ 93 | 'email' => 'test@example.com', 94 | 'password' => bcrypt('$3CR3T'), // Hash the password 95 | ]); 96 | 97 | // Retrieve a token 98 | $response = $this->postJson('/api/auth', [ 99 | 'email' => 'test@example.com', 100 | 'password' => '$3CR3T', 101 | ]); 102 | 103 | $response->assertStatus(200) 104 | ->assertJsonStructure(['token']); 105 | 106 | $token = $response->json('token'); 107 | 108 | // Test not authorized 109 | $this->getJson('/api/greetings') 110 | ->assertStatus(401); 111 | 112 | // Test authorized 113 | $this->withHeader('Authorization', "Bearer $token") 114 | ->getJson('/api/greetings') 115 | ->assertStatus(200); 116 | } 117 | } 118 | ``` 119 | 120 | 121 | -------------------------------------------------------------------------------- /laravel/security.md: -------------------------------------------------------------------------------- 1 | # Security with Laravel 2 | 3 | ## Policies 4 | 5 | API Platform is compatible with Laravel's [authorization](https://laravel.com/docs/authorization) mechanism. 6 | 7 | To utilize policies in API Platform, it is essential to have Laravel's authentication system initialized. 8 | See the [Authentication section](#authentication) for more information. 9 | 10 | Once a gate is defined, API Platform will automatically detect your policy. 11 | 12 | ```php 13 | // app/Models/Book.php 14 | 15 | use ApiPlatform\Metadata\Patch; 16 | 17 | #[Patch] 18 | class Book extends Model 19 | { 20 | } 21 | ``` 22 | 23 | API Platform will detect the operation and map it to a specific method in your policy according to the rules defined in 24 | this table: 25 | 26 | | Operation | Policy | 27 | | -------------- | ---------------------------------------------------------- | 28 | | GET collection | `viewAny` | 29 | | GET | `view` | 30 | | POST | `create` | 31 | | PATCH | `update` | 32 | | DELETE | `delete` | 33 | | PUT | `update` or `create` if the resource doesn't already exist | 34 | 35 | If your policy methods do not match Laravel's conventions, you can always use the `policy` property on an operation 36 | attribute to enforce this policy: 37 | 38 | ```php 39 | // app/Models/Book.php 40 | namespace App\Models; 41 | 42 | use ApiPlatform\Metadata\ApiResource; 43 | +use ApiPlatform\Metadata\Patch; 44 | use Illuminate\Database\Eloquent\Model; 45 | 46 | -#[ApiResource] 47 | #[ApiResource( 48 | paginationItemsPerPage: 10, 49 | + operations: [ 50 | + new Patch( 51 | + policy: 'myCustomPolicy', 52 | + ), 53 | + ], 54 | )] 55 | class Book extends Model 56 | { 57 | } 58 | ``` 59 | 60 | You also can link a model to a policy: 61 | 62 | ```php 63 | use App\Models\Book; 64 | use App\Tests\Book\BookPolicy; 65 | use Illuminate\Support\Facades\Gate; 66 | 67 | Gate::guessPolicyNamesUsing(function (string $modelClass): ?string { 68 | return Book::class === $modelClass ? 69 | BookPolicy::class : 70 | null; 71 | }); 72 | ``` 73 | 74 | ## Authentication 75 | 76 | Usually, you will use [Sanctum](https://laravel.com/docs/sanctum) and add a middleware on secured routes: 77 | 78 | ```php 79 | // app/Models/Book.php 80 | 81 | use ApiPlatform\Metadata\Patch; 82 | 83 | #[Patch(middleware: 'auth:sanctum')] 84 | class Book extends Model 85 | { 86 | } 87 | ``` 88 | 89 | Or you can define it globally in the configuration by adding the following code: 90 | 91 | ```php 92 | [ 97 | // .... 98 | 'middleware' => 'auth:sanctum', 99 | ], 100 | ]; 101 | ``` 102 | -------------------------------------------------------------------------------- /laravel/validation.md: -------------------------------------------------------------------------------- 1 | # Validation with Laravel 2 | 3 | API Platform simplifies the validation of data sent by clients to the API, typically user inputs submitted through forms. 4 | 5 | You can add [validation rules](https://laravel.com/docs/validation) within the `rules` option: 6 | 7 | ```php 8 | // app/Models/Book.php 9 | 10 | use ApiPlatform\Metadata\ApiResource; 11 | 12 | #[ApiResource( 13 | rules: [ 14 | 'title' => 'required', 15 | ] 16 | )] 17 | class Book extends Model 18 | { 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /outline.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | chapters: 3 | - title: "API Platform for Symfony" 4 | path: symfony 5 | items: 6 | - index 7 | - validation 8 | - security 9 | - testing 10 | - debugging 11 | - caddy 12 | - jwt 13 | - messenger 14 | - user 15 | - file-upload 16 | - controllers 17 | - nelmio-api-doc 18 | - migrate-from-fosrestbundle 19 | - fosuser-bundle 20 | - title: "API Platform for Laravel" 21 | path: laravel 22 | items: 23 | - index 24 | - testing 25 | - filters 26 | - security 27 | - validation 28 | - jwt 29 | - title: Core 30 | path: core 31 | items: 32 | - index 33 | - getting-started 34 | - upgrade-guide 35 | - design 36 | - extending 37 | - testing 38 | - operations 39 | - graphql 40 | - state-providers 41 | - state-processors 42 | - filters 43 | - elasticsearch-filters 44 | - doctrine-filters 45 | - subresources 46 | - serialization 47 | - validation 48 | - security 49 | - content-negotiation 50 | - pagination 51 | - deprecations 52 | - default-order 53 | - performance 54 | - extensions 55 | - dto 56 | - openapi 57 | - json-schema 58 | - mercure 59 | - push-relations 60 | - errors 61 | - external-vocabularies 62 | - operation-path-naming 63 | - url-generation-strategy 64 | - extending-jsonld-context 65 | - identifiers 66 | - mongodb 67 | - elasticsearch 68 | - events 69 | - jwt 70 | - form-data 71 | - bootstrap 72 | - configuration 73 | - client-integration 74 | - title: Schema Generator 75 | path: schema-generator 76 | items: 77 | - index 78 | - getting-started 79 | - configuration 80 | - title: Admin 81 | path: admin 82 | items: 83 | - index 84 | - getting-started 85 | - schema 86 | - customizing 87 | - advanced-customization 88 | - handling-relations 89 | - validation 90 | - real-time-mercure 91 | - authentication-support 92 | - file-upload 93 | - performance 94 | - components 95 | - title: Create Client 96 | path: create-client 97 | items: 98 | - index 99 | - nextjs 100 | - nuxt 101 | - vuetify 102 | - quasar 103 | - react 104 | - react-native 105 | - vuejs 106 | - typescript 107 | - custom 108 | - troubleshooting 109 | - title: Deployment 110 | path: deployment 111 | items: 112 | - index 113 | - docker-compose 114 | - kubernetes 115 | - minikube 116 | - heroku 117 | - traefik 118 | - title: General Information 119 | path: extra 120 | items: 121 | - philosophy 122 | - releases 123 | - enterprise 124 | - security 125 | - troubleshooting 126 | - contribution-guides 127 | - conduct 128 | -------------------------------------------------------------------------------- /schema-generator/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | If you use [the API Platform Distribution with Symfony](../symfony/index.md), the Schema Generator is already installed 6 | as a development dependency of your project and can be invoked with: 7 | 8 | ```console 9 | vendor/bin/schema 10 | ``` 11 | 12 | The Schema Generator can also [be downloaded independently as a PHAR](https://github.com/api-platform/schema-generator/releases) 13 | or installed in an existing project using [Composer](https://getcomposer.org): 14 | 15 | ```console 16 | composer require --dev api-platform/schema-generator 17 | ``` 18 | 19 | ## Configuration 20 | 21 | The Schema Generator can either be used with Schema.org types (see [model scaffolding](#model-scaffolding)) or with an OpenAPI documentation (see [OpenAPI generation](#openapi-generation)). 22 | 23 | Choose your preferred way of designing your API, and [run the generator](#usage)! 24 | 25 | ### Model Scaffolding 26 | 27 | Start by browsing [Schema.org](https://schema.org) (or any other RDF vocabulary) and pick types applicable to your application. 28 | Schema.org provides tons of schemas including (but not limited to) representations of people, organizations, events, postal addresses, 29 | creative work and e-commerce structures. 30 | Many other open vocabularies can be found on [the LOV website](https://lov.linkeddata.es/). 31 | 32 | Then, write a simple YAML config file similar to the following. 33 | 34 | Here we will generate a data model for an address book with the following data: 35 | 36 | - a [`Person`](https://schema.org/Person) which inherits from [`Thing`](https://schema.org/Thing); 37 | - a [`PostalAddress`](https://schema.org/PostalAddress) (without its class hierarchy). 38 | 39 | ```yaml 40 | # api/config/schema.yaml 41 | # The list of types and properties we want to use 42 | types: 43 | # Parent class of Person 44 | Thing: 45 | properties: 46 | name: ~ 47 | Person: 48 | # Enable the generation of the class hierarchy (not enabled by default) 49 | parent: ~ 50 | properties: 51 | familyName: ~ 52 | givenName: ~ 53 | additionalName: ~ 54 | address: ~ 55 | PostalAddress: 56 | properties: 57 | # Force the type of the addressCountry property to text 58 | addressCountry: { range: 'Text' } 59 | addressLocality: ~ 60 | addressRegion: ~ 61 | postOfficeBoxNumber: ~ 62 | postalCode: ~ 63 | streetAddress: ~ 64 | ``` 65 | 66 | **Note:** If no properties are specified for a given type, all its properties will be generated. 67 | 68 | The generator also supports enumeration generation. For subclasses of [`Enumeration`](https://schema.org/Enumeration), the 69 | generator will automatically create a class extending the Enum type provided by [myclabs/php-enum](https://github.com/myclabs/php-enum). 70 | Don't forget to install this library in your project. Refer you to PHP Enum documentation to see how to use it. 71 | The Symfony validation annotation generator automatically takes care of enumerations to validate choices values. 72 | 73 | A config file generating an enum class: 74 | 75 | ```yaml 76 | types: 77 | OfferItemCondition: # The generator will automatically guess that OfferItemCondition is subclass of Enum 78 | properties: {} # Remove all properties of the parent class 79 | ``` 80 | 81 | ### OpenAPI Generation 82 | 83 | Design your API with tools like [Stoplight](https://stoplight.io/). 84 | 85 | Export your OpenAPI documentation to a JSON or to a YAML file and place it somewhere in your project 86 | (for instance in `api/openapi.yaml`). 87 | 88 | Write the following config file: 89 | 90 | ```yaml 91 | # api/config/schema.yaml 92 | openApi: 93 | file: '../openapi.yaml' 94 | ``` 95 | 96 | ## Usage 97 | 98 | Run the generator with the config file as parameter: 99 | 100 | ```console 101 | vendor/bin/schema generate api/src/ api/config/schema.yaml -vv 102 | ``` 103 | 104 | Using [the API Platform Symfony variant](../symfony/index.md): 105 | 106 | ```console 107 | vendor/bin/schema generate src/ config/schema.yaml -vv 108 | ``` 109 | 110 | The corresponding PHP classes will be automatically generated in the `src/` directory! 111 | Note that the generator takes care of creating directories corresponding to the namespace structure. 112 | 113 | Without configuration file, the tool will build the entire Schema.org vocabulary. 114 | 115 | ## Load Previously Generated Files 116 | 117 | If you launch the schema generator again, the previously generated files will be loaded. 118 | 119 | It will try to keep as much user-added changes as possible while adding the new changes from the configuration file. 120 | 121 | You can also choose to overwrite the file instead. 122 | 123 | ## Going Further 124 | 125 | Browse [the configuration documentation](configuration.md). 126 | 127 | ### Cardinality Extraction 128 | 129 | The Cardinality Extractor is a standalone tool (also used internally by the generator) extracting a property's cardinality. 130 | It extracts cardinality described with the [Web Ontology Language (OWL)](https://en.wikipedia.org/wiki/Web_Ontology_Language) vocabulary 131 | or in [GoodRelations](https://www.heppnetz.de/projects/goodrelations/). 132 | When cardinality cannot be automatically extracted, its value is set to `unknown`. 133 | 134 | Usage: 135 | 136 | ```console 137 | vendor/bin/schema extract-cardinalities 138 | ``` 139 | -------------------------------------------------------------------------------- /schema-generator/images/stoplight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/schema-generator/images/stoplight.png -------------------------------------------------------------------------------- /schema-generator/index.md: -------------------------------------------------------------------------------- 1 | # The Schema Generator 2 | 3 | `schema` is a command-line tool part of [the API Platform framework](https://api-platform.com) that instantly generates a set 4 | of PHP classes from [RDF](https://en.wikipedia.org/wiki/Resource_Description_Framework) vocabularies such as (but not limited to) 5 | [Schema.org](https://schema.org) or [ActivityStreams](https://www.w3.org/TR/activitystreams-core/). 6 | Alternatively, it can generate PHP classes from an [OpenAPI](https://www.openapis.org/) documentation. 7 | 8 | [Find and browse](https://lov.linkeddata.es/) (or create) a vocabulary that fits your needs, choose the types and properties you need, run our code generator and you're done! 9 | Alternatively, design your API with tools like [Stoplight](https://stoplight.io/), export the OpenAPI documentation, run our code generator and your API is ready! 10 | 11 | ![Stoplight](images/stoplight.png) 12 | 13 | You get a fully featured PHP data model including: 14 | 15 | - A set of PHP entities with properties, constants (enum values), getters, setters, adders and removers. The class 16 | hierarchy provided by the vocabulary will be translated to a PHP class hierarchy with parents as `abstract` classes. 17 | The generated code complies with [PSR](https://www.php-fig.org/) coding standards; 18 | - Full, high-quality PHPDoc and type declarations for classes, properties, constants and methods extracted from the vocabulary; 19 | - Doctrine ORM or MongoDB ODM attributes mapping including database columns / fields with type guessing, relations with cardinality guessing, 20 | smart class inheritance (through the `#[MappedSuperclass]` or `#[InheritanceType]` attributes depending on if the resource is used in a relation); 21 | - Data validation through [Symfony Validator](https://symfony.com/doc/current/book/validation.html) attributes including enum support (choices) and check for required properties; 22 | - API Platform attributes; 23 | - Interfaces and [Doctrine `ResolveTargetEntityListener`](https://www.doctrine-project.org/projects/doctrine-orm/en/current/cookbook/resolve-target-entity-listener.html) 24 | support; 25 | - Custom PHP namespace support; 26 | - List of values provided the vocabulary with [PHP Enum](https://github.com/myclabs/php-enum) classes. 27 | 28 | Bonus: 29 | 30 | - The code generator is fully configurable and extendable. All features can be deactivated (e.g., the Doctrine mapping generator) 31 | and a custom generator can be added; 32 | - The code generator can load previously generated files and add new changes while keeping the user-added ones; 33 | - The generated code can be used as is in a [Symfony](https://symfony.com) app (but it will work too in a raw PHP project 34 | or any other framework including [Laravel](https://laravel.com) and [Zend Framework](https://framework.zend.com/)). 35 | 36 | ## What Is Schema.org? 37 | 38 | Schema.org is a vocabulary representing common data structures and their relations. Schema.org can be exposed as [JSON-LD](https://en.wikipedia.org/wiki/JSON-LD), 39 | [microdata]() and [RDF](https://en.wikipedia.org/wiki/Resource_Description_Framework). 40 | Extracting semantical data exposed in the Schema.org vocabulary is supported by a growing number of companies including 41 | Google (Search, Gmail), Yahoo!, Bing and Yandex. 42 | 43 | ## Why Use Schema.org Data to Generate a PHP Model? 44 | 45 | ### Don't Reinvent the Wheel 46 | 47 | Data models provided by Schema.org are popular and were proven efficient. They cover a broad spectrum of topics including 48 | creative works, e-commerce, events, medicine, social networking, people, postal addresses, organization data, places or reviews. 49 | Schema.org has its root in a ton of preexisting well-designed vocabularies and is 50 | successfully used by more and more websites and applications. 51 | 52 | Pick schemas applicable to your application, generate your PHP model, then customize and specialize it to fit your needs. 53 | 54 | ### Improve SEO and User Experience 55 | 56 | Adding Schema.org markup to websites and apps increases their ranking in search engines results and enables awesome features 57 | such as [Google Rich Snippets](https://support.google.com/webmasters/answer/99170?hl=en) and [Gmail markup](https://developers.google.com/gmail/markup/overview). 58 | 59 | Mapping your app data model to Schema.org structures can be tedious. When using the generator, your data model will be 60 | derived from Schema.org. Adding microdata markup to your templates or serializing your data as JSON-LD will not require 61 | specific mapping nor adaptation. It's a matter of minutes. 62 | 63 | ### Be Ready for The Future 64 | 65 | Schema.org improves the interoperability of your applications. Used with hypermedia technologies such as [Hydra](https://www.hydra-cg.com/) 66 | it's a big step towards the semantic and machine-readable web. 67 | It opens the way to generic web API clients able to extract and process data from any website or app using such technologies. 68 | 69 | ## Documentation 70 | 71 | - [Getting Started](getting-started.md) 72 | - [Configuration](configuration.md) 73 | -------------------------------------------------------------------------------- /symfony/caddy.md: -------------------------------------------------------------------------------- 1 | # Configuring the Caddy Web Server with Symfony 2 | 3 | [The API Platform distribution](index.md) is shipped with [the Caddy web server](https://caddyserver.com). 4 | The build contains the [Mercure](../core/mercure.md) and the [Vulcain](https://vulcain.rocks) Caddy modules. 5 | 6 | Caddy is positioned in front of the web API and of the Progressive Web App. 7 | It routes requests to either service depending on the value of the `Accept` HTTP header or the extension 8 | of the requested file. 9 | 10 | Using the same domain to serve the API and the PWA [improves performance by preventing unnecessary CORS preflight requests 11 | and encourages embracing the REST principles](https://dunglas.fr/2022/01/preventing-cors-preflight-requests-using-content-negotiation/). 12 | 13 | By default, requests having an `Accept` request header containing the `text/html` media type are routed to the Next.js application, 14 | except for some paths known to be resources served by the API (e.g. the Swagger UI documentation, static files provided by bundles...). 15 | Other requests are routed to the API. 16 | 17 | Sometimes, you may want to let the PHP application generate HTML responses. 18 | For instance, when you create your own Symfony controllers serving HTML pages, 19 | or when using bundles such as EasyAdmin or SonataAdmin. 20 | 21 | To do so, you have to tweak the rules used to route the requests. 22 | Open `api-platform/api/frankenphp/Caddyfile` and modify the expression. 23 | You can use [any CEL (Common Expression Language) expression](https://caddyserver.com/docs/caddyfile/matchers#expression) supported by Caddy. 24 | 25 | For instance, if you want to route all requests to a path starting with `/admin` to the API, modify the existing expression like this: 26 | 27 | ```patch 28 | # Matches requests for HTML documents, for static files and for Next.js files, 29 | # except for known API paths and paths with extensions handled by API Platform 30 | @pwa expression `( 31 | {header.Accept}.matches("\\btext/html\\b") 32 | - && !{path}.matches("(?i)(?:^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") 33 | + && !{path}.matches("(?i)(?:^/admin|^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") 34 | )` 35 | ``` 36 | -------------------------------------------------------------------------------- /symfony/debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging with Symfony 2 | 3 |

API Platform debugging screencast
Watch the Debugging API Platform screencast

4 | 5 | ## Xdebug 6 | 7 | For development purposes such as debugging tests or remote API requests, 8 | [Xdebug](https://xdebug.org/) is shipped by default with the API Platform distribution. 9 | 10 | To enable it, run: 11 | 12 | ```console 13 | XDEBUG_MODE=debug XDEBUG_SESSION=1 docker compose up --wait 14 | ``` 15 | 16 | ## Using Xdebug with PhpStorm 17 | 18 | First, [create a PHP debug remote server configuration](https://www.jetbrains.com/help/phpstorm/creating-a-php-debug-server-configuration.html): 19 | 20 | 1. In the `Settings/Preferences` dialog, go to `PHP | Servers` 21 | 2. Create a new server: 22 | - Name: `api` (or whatever you want to use for the variable `PHP_IDE_CONFIG`) 23 | - Host: `localhost` (or the one defined using the `SERVER_NAME` environment variable) 24 | - Port: `443` 25 | - Debugger: `Xdebug` 26 | - Check `Use path mappings` 27 | - Map the local `api/` directory to the `/app` absolute path on the server 28 | 29 | You can now use the debugger! 30 | 31 | 1. In PhpStorm, open the `Run` menu and click on `Start Listening for PHP Debug Connections` 32 | 2. Add the `XDEBUG_SESSION=PHPSTORM` query parameter to the URL of the page you want to debug or use [other available triggers](https://xdebug.org/docs/step_debug#activate_debugger). 33 | Alternatively, you can use [the Xdebug extension](https://xdebug.org/docs/step_debug#browser-extensions) for your preferred web browser. 34 | 35 | 3. On the command-line, we might need to tell PhpStorm which [path mapping configuration](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging-cli.html#configure-path-mappings) should be used, set the value of the PHP_IDE_CONFIG environment variable to `serverName=api`, where `api` is the name of the debug server configured higher. 36 | 37 | Example: 38 | 39 | ```console 40 | XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=api" php bin/console ... 41 | ``` 42 | 43 | ## Using Xdebug With Visual Studio Code 44 | 45 | If you are using Visual Studio Code, use the following `launch.json` to debug. 46 | Note that this configuration includes the path mappings for the Docker image. 47 | 48 | ```json 49 | { 50 | "version": "0.2.0", 51 | "configurations": [ 52 | { 53 | "name": "Listen for Xdebug", 54 | "type": "php", 55 | "request": "launch", 56 | "port": 9003, 57 | "log": true, 58 | "pathMappings": { 59 | "/app": "${workspaceFolder}/api" 60 | } 61 | } 62 | ] 63 | } 64 | ``` 65 | 66 | > [!NOTE] 67 | > 68 | > On Linux, the `client_host` setting of `host.docker.internal` may not work. 69 | > In this case you will need the actual local IP address of your computer. 70 | 71 | ## Troubleshooting 72 | 73 | Inspect the installation with the following command. The requested Xdebug 74 | version should be displayed in the output. 75 | 76 | ```console 77 | $ docker compose exec php \ 78 | php --version 79 | 80 | PHP … 81 | with Xdebug v…, Copyright (c) 2002-2021, by Derick Rethans 82 | … 83 | ``` 84 | -------------------------------------------------------------------------------- /symfony/fosuser-bundle.md: -------------------------------------------------------------------------------- 1 | # FOSUserBundle Integration with Symfony 2 | 3 | > [!WARNING] 4 | > The use of FOSUserBundle is no longer recommended for better flexibility and security. It is advised to switch to the 5 | > [Doctrine entity user provider](https://symfony.com/doc/current/security/user_provider.html#entity-user-provider) (recommended) 6 | > or consider [creating a custom user provider](https://symfony.com/doc/current/security/user_provider.html#creating-a-custom-user-provider). 7 | 8 | ## Installing the Bundle 9 | 10 | The installation procedure of the FOSUserBundle is described [in the FOSUserBundle documentation](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/docs/index.rst). 11 | 12 | You can: 13 | 14 | - Skip [step 3 (Create your User class)](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/docs/index.rst#step-3-create-your-user-class) 15 | and use the class provided in the next paragraph to set up serialization groups the correct way 16 | - Skip [step 4 (Configure your application's security.yml)](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/docs/index.rst#step-4-configure-your-applications-securityyml) 17 | if you are planning to [use a JWT-based authentication using `LexikJWTAuthenticationBundle`](../core/jwt.md) 18 | 19 | If you are using the API Platform Standard Edition, you will need to enable the form services in the symfony framework 20 | configuration options: 21 | 22 | ```yaml 23 | # api/config/packages/framework.yaml 24 | framework: 25 | form: { enabled: true } 26 | ``` 27 | 28 | ## Creating a `User` Entity with Serialization Groups 29 | 30 | Here's an example of declaration of a [Doctrine ORM User class](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/docs/index.rst#a-doctrine-orm-user-class). 31 | There's also an example for a [Doctrine MongoDB ODM](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/docs/index.rst#b-mongodb-user-class). 32 | You need to use serialization groups to hide some properties like `plainPassword` (only in read) and `password`. The properties 33 | shown are handled with [`normalizationContext`](../core/serialization.md#normalization), while the properties 34 | you can modify are handled with [`denormalizationContext`](../core/serialization.md#denormalization). 35 | 36 | Create your User entity with serialization groups: 37 | 38 | ```php 39 | ['user']], 53 | denormalizationContext: ['groups' => ['user', 'user:write']], 54 | )] 55 | class User extends BaseUser 56 | { 57 | #[ORM\Id, ORM\Column, ORM\GeneratedValue] 58 | protected ?int $id = null; 59 | 60 | #[Groups("user")] 61 | protected string $email; 62 | 63 | #[ORM\Column(nullable: true)] 64 | #[Groups("user")] 65 | protected string $fullname; 66 | 67 | #[Groups("user:write")] 68 | protected string $plainPassword; 69 | 70 | #[Groups("user")] 71 | protected string $username; 72 | 73 | public function setFullname(?string $fullname): void 74 | { 75 | $this->fullname = $fullname; 76 | } 77 | 78 | public function getFullname(): ?string 79 | { 80 | return $this->fullname; 81 | } 82 | 83 | public function isUser(?UserInterface $user = null): bool 84 | { 85 | return $user instanceof self && $user->id === $this->id; 86 | } 87 | } 88 | ``` 89 | -------------------------------------------------------------------------------- /symfony/images/NelmioApiDocBundle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/NelmioApiDocBundle.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-admin.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-api.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-bookshop-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-bookshop-api.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-graphql.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-pwa-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-pwa-react.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.5-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.5-welcome.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-admin.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-api.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-bookshop-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-bookshop-api.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-bookshop-json-schemas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-bookshop-json-schemas.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-graphql.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-pwa-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-pwa-react.png -------------------------------------------------------------------------------- /symfony/images/api-platform-2.6-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-2.6-welcome.png -------------------------------------------------------------------------------- /symfony/images/api-platform-3.0-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/api-platform-3.0-welcome.png -------------------------------------------------------------------------------- /symfony/images/swagger-ui-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/swagger-ui-1.png -------------------------------------------------------------------------------- /symfony/images/swagger-ui-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/swagger-ui-2.png -------------------------------------------------------------------------------- /symfony/images/symfonycasts-player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/api-platform/docs/22340ba1a28490caa3795569103a7ec162549263/symfony/images/symfonycasts-player.png -------------------------------------------------------------------------------- /symfony/migrate-from-fosrestbundle.md: -------------------------------------------------------------------------------- 1 | # Migrate From FOSRestBundle with Symfony 2 | 3 | [FOSRestBundle](https://github.com/FriendsOfSymfony/FOSRestBundle) is a popular bundle to rapidly develop RESTful APIs with Symfony. 4 | This page provides a guide to help developers migrate from FOSRestBundle to API Platform. 5 | 6 | > [!IMPORTANT] 7 | > Since [2021](https://x.com/lsmith/status/1440216817876627459), the creators of FOSRestBundle have recommended 8 | > transitioning to **API Platform** as the preferred solution **for building modern APIs**. 9 | 10 | ## Features Comparison 11 | 12 | The table below provides a list of the main features you can find in FOSRestBundle 3.1, and their equivalents in API Platform. 13 | 14 | ### Make CRUD endpoints 15 | 16 | **In FOSRestBundle** 17 | 18 | Create a controller extending the `AbstractFOSRestController` abstract class, make your magic manually in your methods, and return responses through the `handleView()` provided by FOSRest's `ControllerTrait`. 19 | 20 | See [The view layer](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/2-the-view-layer.rst). 21 | 22 | **In API Platform** 23 | 24 | Add the `ApiResource` attribute to your entities, and enable the operations you desire inside. By default, every operation is activated. 25 | 26 | See [Operations](../core/operations.md). 27 | 28 | ### Make custom controllers 29 | 30 | **In FOSRestBundle** 31 | 32 | Same as above. 33 | 34 | **In API Platform** 35 | 36 | Even though this is not recommended, API Platform allows you to [create custom controllers](controllers.md) and declare them in your entity's `ApiResource` attribute. 37 | 38 | You can use them as you migrate from FOSRestBundle, but you should consider [switching to Symfony Messenger](messenger.md) as it will give you more benefits, such as compatibility with both REST and GraphQL and better performances of your API on big tasks. 39 | 40 | See [General Design Considerations](../core/design.md). 41 | 42 | ### Routing system (with native documentation support) 43 | 44 | **In FOSRestBundle** 45 | 46 | Annotate your controllers with FOSRest's route annotations that are the most suitable to your needs. 47 | 48 | See [Full default annotations](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/annotations-reference.rst). 49 | 50 | **In API Platform** 51 | 52 | Use the `ApiResource` attribute to activate the HTTP methods you need for your entity. By default, all the methods are enabled. 53 | 54 | See [Operations](../core/operations.md). 55 | 56 | ### Hook into the handling of the requests 57 | 58 | **In FOSRestBundle** 59 | 60 | Listen to FOSRest's events to modify the requests before they come into your controllers and the responses after they come out of them. 61 | 62 | See [Listener support](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/3-listener-support.rst). 63 | 64 | **In API Platform** 65 | 66 | API Platform provides a lot of ways to customize the behavior of your API, depending on what you exactly want to do. 67 | 68 | See [Extending API Platform](../core/extending.md) for more details. 69 | 70 | ### Customize the formats of the requests and the responses 71 | 72 | **In FOSRestBundle** 73 | 74 | Only the request body's format can be customized. 75 | 76 | Use body listeners to use either FOSRest's own decoders or your own ones. FOSRestBundle provides native support for JSON and XML. 77 | 78 | See [Body Listener](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/body_listener.rst). 79 | 80 | **In API Platform** 81 | 82 | Both the request and the response body's format can be customized. 83 | 84 | You can configure the formats of the API either globally or in specific resources or operations. API Platform provides native support for multiple formats including JSON, XML, CSV, YAML, etc. 85 | 86 | See [Content negotiation](../core/content-negotiation.md). 87 | 88 | ### Name conversion 89 | 90 | **In FOSRestBundle** 91 | 92 | Only request bodies can be converted before entering into your controller. 93 | 94 | FOSRest provides two native normalizers for converting the names of your JSON keys to camelCase. You can create your own ones by implementing the `ArrayNormalizerInterface`. 95 | 96 | See [Body Listeners](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/body_listener.rst). 97 | 98 | **In API Platform** 99 | 100 | Both request and response bodies can be converted. 101 | 102 | API Platform uses [name converters](https://symfony.com/doc/current/components/serializer.html#component-serializer-converting-property-names-when-serializing-and-deserializing) included in the Serializer component of Symfony. You can create your own by implementing the `NameConverterInterface` provided by Symfony. 103 | 104 | See [_Name Conversion_ in The Serialization Process](../core/serialization.md#name-conversion-for-symfony). 105 | 106 | ### Handle errors 107 | 108 | **In FOSRestBundle** 109 | 110 | Map the exceptions to HTTP statuses in the `fos_rest.exception` parameter. 111 | 112 | See [ExceptionController support](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/4-exception-controller-support.rst). 113 | 114 | **In API Platform** 115 | 116 | Map the exceptions to HTTP statuses in the `api_platform.exception_to_status` parameter. 117 | 118 | See [Errors Handling](../core/errors.md). 119 | 120 | ### Security 121 | 122 | **In FOSRestBundle** 123 | 124 | Use [Symfony's Security component](https://symfony.com/doc/current/security) to control your API access. 125 | 126 | **In API Platform** 127 | 128 | Use the `security` attribute in the `ApiResource` and `ApiProperty` attributes. It is an [Expression language](https://symfony.com/doc/current/components/expression_language.md) string describing who can access your resources or who can see the properties of your resources. By default, everything is accessible without authentication. 129 | 130 | Note you can also use the `security.yml` file if you only need to limit access to specific roles. 131 | 132 | See [Security](../core/security.md). 133 | 134 | ### API versioning 135 | 136 | **In FOSRestBundle** 137 | 138 | FOSRestBundle provides a way to provide versions to your APIs in a way users have to specify which one they want to use. 139 | 140 | See [API versioning](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/3.x/Resources/doc/versioning.rst). 141 | 142 | **In API Platform** 143 | 144 | API Platform has no native support for API versioning, but instead provides an approach consisting of deprecating resources when needed. It allows a smoother upgrade for clients, as they need to change their code only when it is necessary. 145 | 146 | See [Deprecating Resources and Properties](../core/deprecations.md). 147 | -------------------------------------------------------------------------------- /symfony/nelmio-api-doc.md: -------------------------------------------------------------------------------- 1 | # NelmioApiDocBundle Integration with Symfony 2 | 3 | > [!WARNING] 4 | > For new projects, prefer using the built-in Swagger support and/or NelmioApiDoc 3. 5 | 6 | NelmioApiDoc provides an alternative to [the native Swagger/Open API support](../core/openapi.md) provided by API Platform. 7 | 8 | As NelmioApiDocBundle 3+ has built-in support for API Platform, this documentation is only relevant for people using 9 | NelmioApiDocBundle between version 2.9 and 3.0. 10 | 11 | ![Screenshot of API Platform integrated with NelmioApiDocBundle](images/NelmioApiDocBundle.png) 12 | 13 | [NelmioApiDocBundle](https://github.com/nelmio/NelmioApiDocBundle) is supported by API Platform since version 2.9. 14 | 15 | To enable the NelmioApiDoc integration, copy the following configuration: 16 | 17 | ```yaml 18 | # api/config/packages/api_platform.yaml 19 | api_platform: 20 | # ... 21 | 22 | enable_nelmio_api_doc: true 23 | 24 | nelmio_api_doc: 25 | sandbox: 26 | accept_type: 'application/json' 27 | body_format: 28 | formats: ['json'] 29 | default_format: 'json' 30 | request_format: 31 | formats: 32 | json: 'application/json' 33 | ``` 34 | 35 | Please note that NelmioApiDocBundle has a sandbox limitation where you cannot pass a JSON array as parameter, so you cannot 36 | use it to deserialize nested objects. 37 | --------------------------------------------------------------------------------