Laravel - api-platform: Full Api-platform usage example with larvel model and database
ApiPlatform is a full-featured, open-source, and easy-to-use RESTful API framework for PHP. It is designed to work seamlessly with Symfony and Laravel. In this example, we will discuss how to use ApiPlatform with Laravel, including creating a model, database, and defining the API routes and resources.
First, let's assume we have a simple Laravel project with a model called Product
and a database table named products
. The Product
model has the following fields: id
, name
, price
, and description
.
To use ApiPlatform with Laravel, follow these steps:
- Install ApiPlatform:
Add the following line to your composer.json
file:
{
"require": {
"api-platform/api-platform": "^2.7",
"api-platform/doctrine-orm-bundle": "^2.7",
"api-platform/symfony-bundle": "^2.7"
}
}
Run composer install
to install the packages.
- Configure the services:
Add the following lines to your config/services.yaml
file:
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
tags: ['controller.service_arguments']
ApiPlatform:
resource: '@api-platform/symfony-bundle/src'
tags: ['api_platform.core']
App\ProductController:
arguments: ['%router%']
tags: ['controller.service_arguments']
App\ProductResource:
arguments: ['%doctrine.orm.entity_manager%']
tags: ['api_platform.resource']
- Define the Product model:
Make sure your Product
model has the ApiPlatform\Core\Annotation\ApiResource
annotation:
namespace App;
use ApiPlatform\Core\Annotation\ApiResource;
use Illuminate\Database\Eloquent\Model;
/**
* @ApiResource()
*/
class Product extends Model
{
// ...
}
- Define the Product resource:
Create a new file src/Resources/App/ProductResource.php
with the following content:
namespace App\Resources;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Entity\Product;
/**
* @ApiResource(
* normalizationContext={"groups"={"product:read"}},
* denormalizationContext={"groups"={"product:write"}}
* )
*/
class ProductResource
{
/**
* @var Product
*
* @ApiProperty(
* name="id",
* readable=false,
* normalizationContext={"groups"={"product:read"}}
* )
*/
public $product;
public function __construct(Product $product)
{
$this->product = $product;
}
public function toArray($request = null)
{
return [
'id' => $this->product->getId(),
'name' => $this->product->getName(),
'price' => $this->product->getPrice(),
'description' => $this->product->getDescription(),
];
}
public function getId()
{
return $this->product->getId();
}
}
- Define the Product controller:
Create a new file src/Controller/ProductController.php
with the following content:
namespace App\Controller;
use App\Entity\Product;
use ApiPlatform\Core\Api\IAnnotations as ApiDoc;
use ApiPlatform\Core\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* @ApiDoc(
* swaggerYml="controllers.yml",
* section="Products",
* tags={"Products"}
* )
*/
class ProductController extends AbstractController
{
public function __construct()
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
}
/**
* @ApiDoc(
* swaggerYml="get_product.yml",
* method="GET",
* path="/api/products/{id}",
* name="get_product",
* description="Get a single product",
* security={{"Bearer": {}}},
* requirements={{"id"="\d+"}},
* output={"class"="App\Resources\ProductResource", "groups"={"product:read"}},
* statusCodes={200="Returned when successful", 404="Returned when the product is not found"}
* )
*
* @param Request $request
* @param Product $product
*
* @return Response
*/
public function getAction(Request $request, Product $product)
{
return $this->view($product, Response::HTTP_OK, ['_format' => $request->getRequestFormat()]);
}
/**
* @ApiDoc(
* swaggerYml="post_product.yml",
* method="POST",
* path="/api/products",
* name="create_product",
* description="Create a new product",
* security={{"Bearer": {}}},
* input={"class"="App\Resources\ProductResource", "groups"={"product:write"}},
* output={"class"="App\Resources\ProductResource", "groups"={"product:read"}},
* statusCodes={201="Returned when the product is created", 400="Returned when the product creation fails"}
* )
*
* @param Request $request
*
* @return Response
*/
public function postAction(Request $request)
{
$product = $this->getDoctrine()->getRepository(Product::class)->createNew();
$productResource = new ProductResource($product);
$data = json_decode($request->getContent(), true);
$productResource->applyToEntity($data, 'PATCH');
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
return $this->view($productResource, Response::HTTP_CREATED, ['_format' => $request->getRequestFormat()]);
}
}
- Configure the routing:
Add the following lines to your routes/api.yaml
file:
api_platform:
resources:
App\Entity\Product:
class: App\Controller\ProductController
methods: [GET, POST]
path: /api/products/{id}
name: product
controller: App\Controller\ProductController::getAction
defaults: { _controller: App\Controller\ProductController::getAction }
requirements:
id: '\d+'
api_platform:
resources:
App\Entity\Product:
class: App\Controller\ProductController
methods: [POST]
path: /api/products
name: create_product
controller: App\Controller\ProductController::postAction
defaults: {}
requirements: {}
- Create the Swagger documentation:
Create a new file controllers.yml
in the public/swagger
directory with the following content:
---
openapi: 3.0.0
info:
title: API Platform Example
version: 1.0.0
servers:
- url: http://localhost:8000/api
components:
schemas:
Product:
type: object
properties:
id:
type: integer
description: The id of the product
name:
type: string
description: The name of the product
price:
type: number
description: The price of the product
description