Parliamo del progetto
PHP symfony Sonata

Symfony 4 / Sonata : Creare un'API REST

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énecessariofriendsofsymfony/rest-bundle : Fornisci una s...

Symfony 4 / Sonata : Creare un'API REST

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"
     * )
Sélection_207

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ì :

image

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.

Condividi questo articolo