In questo articolo vedremo come crécreare un'API REST con FOS/rest-bundle, con un'autenticazione, e un génégeneratore di documentazione di tipo swagger.
Elenco dei bundle nénecessario
friendsofsymfony/rest-bundle : Fornisci una série d’strumenti di’aiuto al déviluppo
d’un'API RESTful
https://github.com/FriendsOfSymfony/FOSRestBundle
jms/serializer-bundle
: Permette la sérealizzazione d’oggetti.
https://packagist.org/packages/jms/serializer-bundle
lexik/jwt-authentication-bundle
: Consente la gestione dei token web in JSON.
https://github.com/lexik/LexikJWTAuthenticationBundle
nelmio/NelmioApiDocBundle
: Permette di génécreare una documentazione HTML à lo swagger
https://github.com/nelmio/NelmioApiDocBundle
Installazione in composer
Si parte dal presupposto che l’usiamo il nostro scheletro come base diéparte.
composer require "nelmio/cors-bundle"
composer require "lexik/jwt-authentication-bundle"
composer require "jms/serializer-bundle"
composer require "friendsofsymfony/rest-bundle"
composer require "nelmio/api-doc-bundle"
composer require "annotations"
Sarà poi necessario registrare i nostri bundle in bundles.php
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
FOS\RestBundle\FOSRestBundle::class => ['all' => true],
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
Per la documentazione, sarà necessario aggiungere il percorso:
# config/routes.yaml
app.swagger_ui:
path: /api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
app.swagger:
path: /api/doc.json
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger }
Créper la configurazione per la documentazione :
# config/packages/nelmio_api_doc.yaml
nelmio_api_doc:
areas:
path_patterns: # an array of regexps
- ^/api(?!/doc$)
host_patterns:
- ^api\.
Sarà quindi necessario attivare i converter di framework extra:
#/config/packages/sensio_framework_extra.yaml
sensio_framework_extra:
router:
annotations: false
request: { converters: true }
Créazione del nostro primière méthode de l’API
Si va d’approcci créessere il nostro controllore
bin/console make:controller api
Nel nostro controller, dovremo includere la nostra libreria d’annotazione di fosRestBundle per utilizzare le giuste annotazioni così come le librerie NelmioApiDoc
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use FOS\RestBundle\Controller\Annotations\Get;
use JMS\Serializer\SerializationContext;
use Symfony\Component\HttpFoundation\Response;
use Swagger\Annotations as SWG;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
class ApiController extends AbstractController
{
/**
* @Get(
* path = "/api/test/{id}",
* name = "api_test_id",
* requirements = {"id"="\d+"}
* )
*/
public function index()
{
$detail=['test'=>'value'];
$serializer = $this->get('serializer');
$response = new Response(
$serializer->serialize(['detail' => $detail], 'json'),
Response::HTTP_OK
);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
Per gérer il codice di rérisposte, dovremo utilizzare le seguenti annotazioni:
* @SWG\Response(
* response=200,
* @SWG\Schema(type="object",
* example={"foo": "bar", "hello": "world"}
* ),
* description="Response ok"
* )
* @SWG\Response(
* response=401,
* description="Access Denied"
* )
* @SWG\Response(
* response=403,
* description="Forbidden"
* )
* @SWG\Response(
* response=404,
* description="Not Found"
* )
Autenticazione della nostra API
Per l’autenticazione, abbiamo scelto di fare semplice. Non un'autenticazione tramite l’entêdi tipo Bearer, ma solo una chiave nel l’url.
C’è molto più semplice à testare, soprattutto quando andrete a lavorare con terzi, e non volete fare supporto in ogni senso e formare i loro stagisti. Mêmi si aggiungere una chiave
in l’entête, c’è francamente non molto complicatoé. breve.
Quindi andiamo déchiarire la nostra chiave nelle annotazioni del nostro méthode.
* @SWG\Parameter(
* name="key",
* in="query",
* type="string",
* description="The authorization key"
* )
Coppiaé alla définitura della nostra API questo dà:
/**
* @Get(
* path = "/api/test/{id}",
* name = "api_test_id",
* requirements = {"id"="\d+"}
* )
*
*
* @SWG\Parameter(
* name="key",
* in="query",
* type="string",
* description="The authorization key provided by HMF"
* )
E nello swagger questo si notaérealizza così :
Personalizzazione della documentazione
La documentazione présente qualche problemaèmesi d’visualizzazione dello stile, e in particolare mostra un logo del bundle, mentre l’vogliamo mostrare il logo del cliente.
Di conseguenza, basta sovraccaricare il template in crémettere un file twig qui
:
/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig
{# templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig #}
{#
To avoid a "reached nested level" error an exclamation mark `!` has to be added
See https://symfony.com/blog/new-in-symfony-3-4-improved-the-overriding-of-templates
#}
{% extends '@!NelmioApiDoc/SwaggerUi/index.html.twig' %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/custom-swagger-styles.css') }}">
<style>
header #logo img{
height: unset;
}
header::before{
background-color: #FFFFFF;
}
.swagger-ui table tbody tr td, .response-col_description__inner{
padding: 0;
vertical-align: top;
}
.swagger-ui .markdown p{
margin: 10px auto;
}
</style>
{% endblock stylesheets %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript" src="{{ asset('js/custom-request-signer.js') }}"></script>
{% endblock javascripts %}
{% block header %}
<a id="logo" href="#"><img src="{{ asset('images/logo.png') }}" alt="Hyundai"></a>
{% endblock header %}
Vogliamo inoltre consentire solo il json e il testo in https, perché il nostro dominio è in https, e se il’utente (il tirocinante), testa in http mentre la documentazione è in https, il browser bloccherà la richiestaête. C’è stupido, ma c’sei del véculo 😉
Gli metteremo un titolo, eliminare l’autenticazione Bearer, e rimuovere la véVerifica tramite host.
# config/packages/nelmio_api_doc.yaml
nelmio_api_doc:
areas:
path_patterns: # an array of regexps
- ^/api(?!/doc$)
# host_patterns:
# - ^api\.
#
documentation:
host: api.hyundai.test
#schemes: [http, https]
schemes: [https]
info:
title: Hyundai API
description: hyundai backend webservice
version: 1.0.0
#securityDefinitions:
# Bearer:
# type: apiKey
# description: 'Value: Bearer {jwt}'
# name: Authorization
# in: header
#security:
# - Bearer: []
Ed ecco! Siamo prontiêt à désviluppare la nostra API.
Ci resterà à créper un CRUD per le chiavi, e applicare la nostra logica dei datiéè à
fornire per ogni méthodes.
Adattare l’esempio alla versione installata
Gli esempi Symfony e Sonata rimangono legati alle versioni indicate nell’articolo. Symfony 4.x e Symfony 6.2 non sono più supportati: per un progetto attuale, utilizzate un ramo mantenuto e la documentazione corrispondente esattamente alle vostre dipendenze.
php bin/console about
composer show symfony/framework-bundle sonata-project/admin-bundle
Prima di riprendere il codice, controllate le firme, i servizi, le rotte e i template interessati. Aggiungete poi un test funzionale che copra le autorizzazioni, il codice HTTP e il risultato visibile.
Riferimento : versioni di Symfony supportate.