Salut la famille, bienvenue dans mon premier tutoriel sur ce blog je remercie d’abord @alioukahere pour cette opportunité.

Dans ce tutoriel je vais vous parlez de comment documenter une API laravel avec OpenApi/Swagger.

Écrire de la documentation est contraignante. D’autant plus que cette dernière doit être régulièrement mise à jour au fur et à mesure que le projet évolue, ne faisant qu’accroître le côté fastidieux de la chose.

UN PEU D’HISTOIRE

La lumière de laravel

Documenter une API n’est pas plus aisé, toutes les requêtes et réponses différentes de chaque endPoint doivent être renseignées. De plus, une API n’est pas forcément à destination des développeurs, elle doit donc être facile à comprendre.

Dans cet article nous allons voir comment documenter une API développée en laravel . Pour ceux pour qui c'est la première fois de voir le mot LARAVEL faites un tour rapide sur ce site https://www.apprendre-laravel.fr/laraguide.

Cet article évidemment ne peut pas traiter toutes les notions liées à la documentation via OpenApi/Swagger d'un projet laravel.

Il existe heureusement plusieurs services pour documenter une api. Les plus populaires sont RAML, Apiary et Swagger.

  • RAML : un language basé sur le YAML ;
  • Swagger : du JSON ou du YAML ;
  • Apiary : markdown (API Blueprint) ;

Je vais vous expliquer un peu la particularité de chacun de ces services.

RAML

RAML (RESTful API Modeling Language) est un langage vous permettant de désigner une API très rapidement en respectant les principes architecturaux de REST. RAML permet de respecter les contraintes tout en étant très facile à lire (il repose sur le langage YAML, format de présentation de données très facile à lire développé par Clark Evans en 2001).

Sa facilité de lecture lui permet d’être compréhensible par l’ensemble de la communauté des développeurs. En fait une API documenter grâce à RAML est définit dans un simple fichier. Dans ce dernier on peut voir immédiatement ce que cette dernière fait. Procédé ainsi permet d’avoir un système maintenable sur le long terme.

SWAGGER                       

Swagger en une phrase c’est un ensemble d’outils permettant d'aider les développeurs dans la conception, le build, la documentation et la consommation d’API.

En 2010, Swagger n’était qu’une spécification open source pour construire des API REST. A cela est venu se greffer divers outils, également open source, pour aider à implémenter et visualiser les API; on parle là de Swagger UI, Swagger Editor et Swagger Codegen.

En 2015, le projet Swagger est récupéré par Smartbear Software et la spécification swagger est renommée OpenAPI.

APIARY 

Apiary est un langage orienté documentation créé pour décrire une API sous forme de texte brut (markdown). Étant simple à apprendre et à lire, cela facilite la collaboration avec tous les membres de l’équipe aussi bien les développeurs front-end que le product owner. Ainsi tout le monde peut modifier la documentation.

Mon choix s’est porté sur Open Api (SWAGGER) pour plusieurs raisons, premièrement je l’utilise au quotidien et la dernière raison la documentation est automatiquement générée à partir du code.

ON CODE QUAND ?

Commençons molo molo (délicatement) …..

Quand tu l'annonce la bonne nouvelle

Comme exemple allons consommer et documenter une api public , rien de mieux que de prendre cet Api https://api.covid19api.com 

INSTALLER LARAVEL

$ composer create-project --prefer-dist laravel/laravel ApiLaravelWithOpenApi

Composer va nous installer la dernière version de laravel :

$ php artisan --version
Laravel Framework 8.x.x

INSTALLER SWAGGER

$ composer require "darkaonline/l5-swagger"

PUBLIER SWAGGER:

$ php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

Une fois que la publication est succès, un fichier l5-swagger.php est automatiquement crée dans le dossier config/

Tu viens de faire le plus dur 

Ce l5-swagger.php est le fichier qui va nous permettre de configurer notre documentation en personnalisant par exemple la route, le nom de notre api, l’interface web de la documentation… dans cet exemple nous allons juste utiliser l’interface par défaut.

Tu veux déjà voir ta doc, soit patient....

Activons la doc, pour ce faire ajoutons ces lignes de code dans le contrôleur principal (Controller.php) comme suit :

class Controller extends BaseController
{   /**
 * @OA\Info(
 *      version="1.0.0",
 *      title="Api covid19 Documentation",
 *      description="Implementation of Swagger with in Laravel",
 *      @OA\Contact(
 *          email="admin@admin.com"
 *      ),
 *      @OA\License(
 *          name="Apache 2.0",
 *          url="http://www.apache.org/licenses/LICENSE-2.0.html"
 *      )
 * )
 *
 * @OA\Server(
 *      url=L5_SWAGGER_CONST_HOST,
 *      description="Demo API Server"
 * )

 *
 *
 */
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

Dans le fichier l5-swagger.php désactiver les lignes de 194 à 196 comme suit :

'constants' => [

'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'),

],

Ajouter cette ligne dans le fichier .env qui représentera notre Base Url :

L5_SWAGGER_CONST_HOST='http://127.0.0.1:8000/api'

Créons notre propre Controller et ajoutons ces lignes

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ApiController extends Controller
{
    /**
     * @OA\Get(
     *      path="/v1/countries",
     *      operationId="getAllCountrie",
     *      tags={"Tests"},

     *      summary="Get List Of Countries",
     *      description="Returns all countries and associated provinces. The country_slug variable is used for country specific data",
     *      @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\MediaType(
     *           mediaType="application/json",
     *      )
     *      ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      ),
     * @OA\Response(
     *      response=400,
     *      description="Bad Request"
     *   ),
     * @OA\Response(
     *      response=404,
     *      description="not found"
     *   ),
     *  )
     */
    public function getAllCountries(){
        //voir plus bas
    }
}

Enfin nous allons régénérer notre doc :

php artisan l5-swagger:generate

Si tout passe avec succès lançons le projet:

php artisan serve

Et partons sur le lien http://127.0.0.1:8000/api/documentation vous devriez voir ceci:

Pour avoir plus d’information sur toute les annotations déjà utiliser jusqu’ici consulter le site officiel de swagger  https://swagger.io/specification/

Comme mentionné plus haut nous allons consommer cette api https://api.covid19api.com qui a plusieurs endpoint, mais dans notre cas nous allons consommer et documenter trois(3) endpoint pour faire plus court.

Pour consommer notre api, créons d’abord une méthode pour se connecter a l’api.

Pour cela créons un Helper dans le dossier App pour la connexion à l’api.

Pour consommer une api en php/laravel plusieurs possibilité s’offrent a nous, mais pour faire plus court nous allons utiliser la méthode CURL.

<?php
function serviceApi($endpoint){
    $url="https://api.covid19api.com/$endpoint";
    $crl = curl_init();

    curl_setopt($crl, CURLOPT_URL, $url);
    curl_setopt($crl, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($crl, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($crl);

    if(!$response){
        die('Error: "' . curl_error($ch) . '" - Code: ' . curl_errno($ch));
    }
    return $response;
    curl_close($crl);
}

Activation du helper

Ajouter cette ligne dans le fichier composer.json

"autoload": {
     ....
        "files": [
            "app/Helper.php"
        ]
    },

Activer le helper a travers la commande

composer dump-autoload

Modifions notre Controller  en appelant la méthode serviceApi qui est déjà déclarer dans notre Helper.php

/**
     * @OA\Get(
     *      path="/v1/countries",
     *      operationId="getAllCountrie",
     *      tags={"Tests"},

     *      summary="Get List Of Countries",
     *      description="Returns all countries and associated provinces. The country_slug variable is used for country specific data",
     *      @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\MediaType(
     *           mediaType="application/json",
     *      )
     *      ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      ),
     * @OA\Response(
     *      response=400,
     *      description="Bad Request"
     *   ),
     * @OA\Response(
     *      response=404,
     *      description="not found"
     *   ),
     *  )
     */
    public function getAllCountries(){
        return serviceApi("countries");
    }

Ensuite régénérons la documentation : 

php artisan l5-swagger:generate

Vous devriez voir quelque choses comme ci:

Cet EndPoint renvoie la liste des pays touché par la Covid19

Consommons et documentons les deux(2) autres endPoints que reçoivent des paths variables.

Notre Controller devrait ressembler a ceci:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ApiController extends Controller
{
    /**
     * @OA\Get(
     *      path="/v1/countries",
     *      operationId="getAllCountrie",
     *      tags={"Tests"},

     *      summary="Get List Of Countries",
     *      description="Returns all countries and associated provinces. The country_slug variable is used for country specific data",
     *      @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\MediaType(
     *           mediaType="application/json",
     *      )
     *      ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      ),
     * @OA\Response(
     *      response=400,
     *      description="Bad Request"
     *   ),
     * @OA\Response(
     *      response=404,
     *      description="not found"
     *   ),
     *  )
     */
    public function getAllCountries(){
        return serviceApi("countries");
        //return "Hello Swagger";
    }
    /**
     * @OA\Get(
     *      path="/v1/countries/{country}",
     *      operationId="getCountryConvidInfos",
     *      tags={"Tests"},
     *      summary="Get List Of Cases Per Country Per Province By Case Type From The First Recorded Case",
     *      description="Returns all cases by case type for a country from the first recorded case. Country must be the country_slug from /countries. Cases must be one of: confirmed, recovered, deaths",
     *@OA\Parameter(
     *      name="country",
     *      in="path",
     *      required=true,
     *      @OA\Schema(
     *           type="string"
     *      )
     *   ),
     *     @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\MediaType(
     *           mediaType="application/json",
     *      )
     *      ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      ),
     * @OA\Response(
     *      response=400,
     *      description="Bad Request"
     *   ),
     * @OA\Response(
     *      response=404,
     *      description="not found"
     *   ),
     *  )
     */
    public function getCovid19InfosByCountries($country){
        $endPoint="dayone/country/$country";
       return serviceApi($endPoint);
    }
    /**
     * @OA\Get(
     *      path="/v1/amount/{country}",
     *      operationId="getCountryConvidInfos",
     *      tags={"Tests"},
     *      summary="Get List Of Cases Per Country Per Province By Case Type From The First Recorded Case",
     *      description="Returns all cases by case type for a country from the first recorded case. Country must be the country_slug from /countries. Cases must be one of: confirmed, recovered, deaths",
     *@OA\Parameter(
     *      name="country",
     *      in="path",
     *      required=true,
     *      @OA\Schema(
     *           type="string"
     *      )
     *   ),
     *     @OA\Response(
     *          response=200,
     *          description="Successful operation",
     *          @OA\MediaType(
     *           mediaType="application/json",
     *      )
     *      ),
     *      @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *      ),
     *      @OA\Response(
     *          response=403,
     *          description="Forbidden"
     *      ),
     * @OA\Response(
     *      response=400,
     *      description="Bad Request"
     *   ),
     * @OA\Response(
     *      response=404,
     *      description="not found"
     *   ),
     *  )
     */
    public function getTotalByCountries($country){
        $endPoint="total/dayone/country/$country";
        return serviceApi($endPoint);
    }
}

Taper cette commande pour regénérer la doc:

php artisan l5-swagger:generate

Tu peux ensuite consulter ta doc et tu connais déjà le lien...

C'EST LA FIN

Merci a toi qui a lue cet article et a très bien bientôt


Partager cet article

moh90tourebeyla

Mohamed

@moh90tourebeyla

Developer fullstack