Besoin d'aide ?

Application avec une API en back office

  • Avatar de loicconan
    Membre depuis :
    12/04/2019
    Messages :
    1

    Bonjour,

    Projet

    Je dois commencer un tout nouveau projet sur Laravel (5) avec la contrainte d'architecture suivante :
    Front (laravel) -> Back-office (API REST Java) -> BDD

    Mon application Laravel ne gérera donc pas directement la base de donnée et devra passer par une API REST déjà développé en interne.
    Cela est mon tout premier projet en Laravel, de plus je ne trouve pas beaucoup d'exemples avec une tel architecture.
    Pouvez-vous donc me dire si je fait bonne route et m'aiguiller svp ?

    Mon but et dans un premier temps est :

    • pouvoir récupérer via le BO (back-office) une entité représentant un objet modèle de mon application (ex : [GET] /transaction/{id})
    • envoyer au BO une requête représentant un objet modèle de mon application (ex : [POST] /transaction)

    Afin de parer à toute éventualité il pourra y avoir une différence :

    • entre le nom des paramètres JSON reçuent (GET) et le nom des paramètres de mon modèle
    • les paramètres de mon modèle et les paramètres JSON attenduent (POST)

    Ce que je fais

    J'ai installé Guzzle (guzzlehttp/guzzle) et JMS Serializer (jms/serializer) dans mon projet (composer).

    J'ai créé un provider pour Guzzle

    <?php

    namespace App\Providers;

    use Illuminate\Support\ServiceProvider;
    use GuzzleHttp\ClientInterface;
    use GuzzleHttp\Client;
    use Illuminate\Contracts\Support\DeferrableProvider;

    class GuzzleProvider extends ServiceProvider implements DeferrableProvider
    {
    /
    Register services.

    @return void
    /
    public function register()
    {
    $this->app->singleton(ClientInterface::class, function ($app) {
    return new Client();
    });
    }

    /

    Get the services provided by the provider.

    @return array
    /
    public function provides()
    {
    return [ClientInterface::class];
    }
    }

    J'ai créé un provider pour JMS Serializer

    <?php

    namespace App\Providers;

    use Illuminate\Support\ServiceProvider;
    use Doctrine\Common\Annotations\AnnotationRegistry;
    use JMS\Serializer\SerializerInterface;
    use \JMS\Serializer\SerializerBuilder;
    use Illuminate\Contracts\Support\DeferrableProvider;

    class JMSSerializerProvider extends ServiceProvider implements DeferrableProvider
    {
    /
    Register services.

    @return void
    /
    public function register()
    {
    AnnotationRegistry::registerLoader('class_exists');

    $this->app->singleton(SerializerInterface::class, function ($app) {
    $builder = new SerializerBuilder();
    return $builder::create()->build();
    });
    }

    /

    Get the services provided by the provider.

    @return array
    /
    public function provides()
    {
    return [SerializerInterface::class];
    }
    }

    Un modèle symple pour commencer

    <?php

    namespace App\Models;

    use JMS\Serializer\Annotation\Type;

    class Transaction
    {
    /
    @Type("integer")
    /
    private $id;

    /

    @Type("string")
    /
    private $name;

    /
    Get the value of id
    /
    public function getId()
    {
    return $this->id;
    }

    /

    Set the value of id

    @return self
    /
    public function setId($id)
    {
    $this->id = $id;

    return $this;
    }

    /
    Get the value of name
    /
    public function getName()
    {
    return $this->name;
    }

    /

    Set the value of name

    @return self
    /
    public function setName($name)
    {
    $this->name = $name;

    return $this;
    }
    }

    Une classe abstraite repository (j'ai l'habitude de travailler avec symfony, cette architecture m'est donc venue naturellement mais peut être qu'avec Laravel les normes ne sont pas les mêmes)

    <?php

    namespace App\Repositories;

    use GuzzleHttp\ClientInterface;
    use JMS\Serializer\SerializerInterface;

    abstract class Repository {
    protected $clientHttp;
    protected $serializer;

    public function __construct(ClientInterface $clientHttp, SerializerInterface $serializer)
    {
    $this->clientHttp = $clientHttp;
    $this->serializer = $serializer;
    }

    abstract public function get($id);
    abstract public function add($entity);
    abstract public function edit($entity);
    abstract public function delete($entity);
    abstract public function search(array $params);
    }

    Un repository pour mon modèle Transaction

    <?php

    namespace App\Repositories;

    use App\Models\Transaction;
    use App\Http\Resources\TransactionResource;

    class TransactionRepository extends Repository {
    public function get($id)
    {
    // Exemple d'appel REST. Fonctionne mais API encore non prête.
    //$response = $this->clientHttp->request('GET', 'https://httpbin.org/ip');
    //$response = $response->getBody()->getContents();

    // API non prête, on simule donc un retour en attendant
    $response = json_encode([
    'id' => 1,
    'name_changed' => 'test'
    ]);

    $jsonData = json_decode($response, true);
    $jsonDataConverted = json_encode(TransactionResource::make($jsonData)->resolve());

    $object = $this->serializer->deserialize($jsonDataConverted, Transaction::class, 'json');

    return $object;
    }

    public function add($entity)
    {
    $entityJson = $this->serializer->serialize($entity, 'json');
    $entityArray = json_decode($entityJson, true);

    $test = new TransactionResource($entity);
    dd($test->getResponse());
    //dd(TransactionResource::make($entityArray)->resolve());
    }

    public function edit($entity)
    {

    }

    public function delete($entity)
    {

    }

    public function search(array $params)
    {

    }
    }

    Ma ressource Transaction

    <?php

    namespace App\Http\Resources;

    use Illuminate\Http\Resources\Json\JsonResource;

    class TransactionResource extends JsonResource
    {
    /*
    Transform the resource into an array.

    @param \Illuminate\Http\Request $request
    @return array
    /
    public function toArray($request)
    {
    return [
    'id' => $this->resource['id'],
    'name' => $this->resource['name_changed']
    ];
    }
    }

    Enfin, mon contrôleur

    <?php

    use App\Repositories\TransactionRepository;

    Route::get('/', function () {
    $transactionRepository = App::make('App\Repositories\TransactionRepository');

    $transaction = new App\Models\Transaction();
    $transaction->setId(1);
    $transaction->setName('test');

    $transactionRepository->get(1);
    $transactionRepository->add($transaction);

    return view('welcome');
    });

    Conclusion

    Comme vous pouvez le voir j'ai tout d'abord essayer de mettre certains fondamentaux en place (provider/singleton, repository...).
    Suis-je dans les bonnes pratiques de Laravel ?

    Dans un deuxième temps j'essaye de gérer cette différence qu'il peut y avoir entre mon objet Modèle et les échanges avec le BO. Pour le moment, comme on peut le voir j'ai fait un test avec le principe de Ressource de Laravel. Cela fonctionne bien, mais cela m'obligera d'avoir deux Ressources par Modèles (modele vers json et json vers modèle).
    J'ai vu que je pourrai aussi gérer cela via JMS Serializer via les Handlers/Event Listener/Subscriber/Annotations...
    Que me conseillez-vous ?

    Merci d'avance pour votre retour d'expérience sur le sujet.

    Loïc

Vous ne pouvez pas répondre à ce sujet.