v2.1 Getting started

# Installing API Platform Core

If you are starting a new project, the easiest way to get API Platform up is to install the API Platform Distribution. It ships with the API Platform Core library integrated with the Symfony framework, the schema generator, Doctrine ORM, NelmioCorsBundle and Behat. Basically, it is a Symfony edition packaged with the best tools to develop a REST API and sensible default settings.

Alternatively, you can use Composer to install the standalone bundle in an existing Symfony project:

composer require api-platform/core

Then, update your app/AppKernel.php file:

<?php
// app/AppKernel.php

public function registerBundles()
{
    $bundles = [
        // ...
        new ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle(),
    ];

    // ...
}

Register the routes of our API by adding the following lines to app/config/routing.yml:

# app/config/routing.yml
api:
    resource: '.'
    type: 'api_platform'
    prefix: '/api' # Optional

There is no mandatory configuration options although many settings are available.

# Before Reading this Documentation

If you haven’t read it already, take a look at the “Creating your first API with API Platform, in a few minutes” guide. This tutorial covers basic concepts required to understand how API Platform works including how it implements the REST pattern and what JSON-LD and Hydra formats are.

# Mapping the Entities

API Platform Core is able to automatically expose entities mapped as “API resources” through a REST API supporting CRUD operations. To expose your entities, you can use Docblock annotations, XML and YAML configuration files.

Here is an example of entities mapped using annotations which will be exposed through a REST API:

<?php
// src/AppBundle/Entity/Product.php

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource
 * @ORM\Entity
 */
class Product // The class name will be used to name exposed resources
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @param string $name A name property - this description will be available in the API documentation too.
     *
     * @ORM\Column
     * @Assert\NotBlank
     */
    public $name;

    // Notice the "cascade" option below, this is mandatory if you want Doctrine to automatically persist the related entity
    /**
     * @ORM\OneToMany(targetEntity="Offer", mappedBy="product", cascade={"persist"})
     */
    public $offers;

    public function __construct()
    {
        $this->offers = new ArrayCollection(); // Initialize $offers as an Doctrine collection
    }

    // Adding both an adder and a remover as well as updating the reverse relation are mandatory
    // if you want Doctrine to automatically update and persist (thanks to the "cascade" option) the related entity
    public function addOffer(Offer $offer): void
    {
        $offer->product = $this;
        $this->offers->add($offer);
    }

    public function removeOffer(Offer $offer): void
    {
        $offer->product = null;
        $this->offers->removeElement($offer);
    }
}
<?php
// src/AppBundle/Entity/Offer.php

namespace AppBundle\Entity;

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

/**
 * An offer from my shop - this description will be automatically extracted form the PHPDoc to document the API.
 *
 * @ApiResource(iri="http://schema.org/Offer")
 * @ORM\Entity
 */
class Offer
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @ORM\Column(type="text")
     */
    public $description;

    /**
     * @ORM\Column(type="float")
     * @Assert\NotBlank
     * @Assert\Range(min=0, minMessage="The price must be superior to 0.")
     * @Assert\Type(type="float")
     */
    public $price;

    /**
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="offers")
     */
    public $product;
}

It is the minimal configuration required to expose Product and Offer entities as JSON-LD documents through an hypermedia web API.

If you are familiar with the Symfony ecosystem, you noticed that entity classes are also mapped with Doctrine ORM annotations and validation constraints from the Symfony Validator Component. This isn’t mandatory. You can use your preferred persistence and validation systems. However, API Platform Core has built-in support for those library and is able to use them without requiring any specific code or configuration to automatically persist and validate your data. They are good default and we encourage you to use them unless you know what you are doing.

Thanks to the mapping done previously, API Platform Core will automatically register the following REST operations for resources of the product type:

Product

MethodURLDescription
GET/productsRetrieve the (paged) collection
POST/productsCreate a new product
GET/products/{id}Retrieve a product
PUT/products/{id}Update a product
DELETE/products/{id}Delete a product

The same operations are available for the offer method (routes will start with the /offers pattern). Route prefixes are built by pluralizing the name of the mapped entity class. It is also possible to override the naming convention using operation path namings.

As an alternative to annotations, you can map entity classes using XML or YAML:

XML:

<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<resources xmlns="https://api-platform.com/schema/metadata"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata
           https://api-platform.com/schema/metadata/metadata-2.0.xsd">
    <resource class="AppBundle\Entity\Product" />
    <resource
        class="AppBundle\Entity\Offer"
        shortName="Offer" <!-- optional -->
        description="An offer form my shop" <!-- optional -->
        iri="http://schema.org/Offer" <!-- optional -->
    />
</resources>

YAML:

# src/AppBundle/Resources/config/api_resources/resources.yml
resources:
    AppBundle\Entity\Product: ~
    AppBundle\Entity\Offer:
        shortName: 'Offer'                   # optional
        description: 'An offer from my shop' # optional
        iri: 'http://schema.org/Offer'       # optional
        attributes:                          # optional
            pagination_items_per_page: 25    # optional

You’re done!

You now have a fully featured API exposing your entities. Run the Symfony app (bin/console server:run) and browse the API entrypoint at http://localhost:8000/api.

Interact with the API using a REST client (we recommend Postman) or an Hydra aware application (you should give Hydra Console a try). Take a look at the usage examples in the features directory.

You can also help us improve the documentation of this page.

Made with love by

Les-Tilleuls.coop can help you design and develop your APIs and web projects, and train your teams in API Platform, Symfony, Next.js, Kubernetes and a wide range of other technologies.

Learn more

Copyright © 2023 Kévin Dunglas

Sponsored by Les-Tilleuls.coop