Construire un serveur GraphQL avec Laravel

Publié: 2022-03-11

Au cas où vous ne le connaîtriez pas encore, GraphQL est un langage de requête utilisé pour interagir avec votre API qui offre certains avantages par rapport aux architectures alternatives telles que REST. GraphQL est extrêmement pratique lorsqu'il est utilisé pour servir de point de terminaison pour les applications mobiles et d'une seule page. GraphQL vous permet d'interroger des données imbriquées et associées dans une requête avec une relative facilité, permettant aux développeurs d'obtenir les données exactes dont ils ont besoin en un seul aller-retour vers le serveur.

Laravel est un framework Web PHP populaire et opiniâtre. Il fournit de nombreux outils intégrés pour rendre les applications opérationnelles rapidement, mais il permet également aux développeurs d'échanger leurs propres implémentations contre les interfaces intégrées de Laravel lorsqu'ils le souhaitent.

Bien que les communautés entourant à la fois GraphQL et Laravel se soient considérablement développées depuis qu'elles sont open source, la documentation expliquant comment utiliser ces deux technologies ensemble est encore assez rare.

Donc, dans ce tutoriel, je vais vous montrer comment créer votre propre serveur GraphQL en utilisant Laravel.

Aperçu du projet

Illustration de la présentation du serveur GraphQL

Avant de commencer, nous devrons nous familiariser avec le projet que nous essayons de construire. Pour ce faire, nous allons définir nos ressources et créer notre schéma GraphQL, que nous utiliserons plus tard pour servir notre API.

Ressources du projet

Notre application sera composée de deux ressources : Articles et Utilisateurs . Ces ressources seront définies en tant que types d'objets dans notre schéma GraphQL :

 type User { id: ID! name: String! email: String! articles: [Article!]! } type Article { id: ID! title: String! content: String! author: User! }

En regardant le schéma, nous pouvons voir que nous avons une relation un-à-plusieurs entre nos deux objets. Les utilisateurs peuvent écrire de nombreux articles, et un article a un auteur (utilisateur) qui lui est assigné.

Maintenant que nos types d'objets sont définis, nous aurons besoin d'un moyen de créer et d'interroger nos données. Définissons donc nos objets de requête et de mutation :

 type Query { user(id: ID!): User users: [User!]! article(id: ID!): Article articles: [Article!]! } type Mutation { createUser(name: String!, email: String!, password: String!): User createArticle(title: String!, content: String!): Article }

Mise en place de notre projet Laravel

Maintenant que nous avons défini notre schéma GraphQL, lançons notre projet Laravel opérationnel. Commençons par créer un nouveau projet Laravel via Composer :

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

Juste pour nous assurer que tout fonctionne, démarrons notre serveur et assurons-nous de voir la page par défaut de Laravel :

 $ cd laravel-graphql $ php artisan serve Laravel development server started: <http://127.0.0.1:8000>

Modèles de base de données et migrations

Pour les besoins de cet article, nous utiliserons SQLite. Apportons donc les modifications suivantes au fichier .env par défaut :

 DB_CONNECTION=sqlite # DB_HOST= # DB_PORT= # DB_DATABASE=database.sqlite # DB_USERNAME= # DB_PASSWORD=

Ensuite, créons notre fichier de base de données :

 $ touch ./database/database.sqlite

Laravel est livré avec un modèle utilisateur et quelques fichiers de migration de base. Ajoutons rapidement une colonne api_token à notre fichier de migration CreateUsersTable fourni par Laravel :

 /database/migrations/XXXX_XX_XX_000000_create_users_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { /** * Run the migrations. */ public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->string('api_token', 80)->unique()->nullable()->default(null); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down() { Schema::dropIfExists('users'); } }

Nous reviendrons à cette colonne supplémentaire plus loin dans l'article lorsque nous arriverons à l'autorisation. Continuons maintenant et créons notre modèle d'article et un fichier de migration pour créer la table associée :

 $ php artisan make:model Article -m

Remarque : L'option -m crée un fichier de migration pour notre modèle d'article nouvellement créé.

Apportons quelques ajustements au fichier de migration généré :

 use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateArticlesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('articles', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id'); $table->string('title'); $table->text('content'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('articles'); } }

Nous avons ajouté une clé étrangère pointant vers l' id de notre table d' users ainsi que les colonnes de title et content que nous avons définies dans notre schéma GraphQL.

Maintenant que nos fichiers de migration sont définis, allons-y et exécutons-les sur notre base de données :

 $ php artisan migrate

Ensuite, mettons à jour nos modèles en définissant les relations nécessaires :

 app/User.php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; // ... /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function articles() { return $this->hasMany(Article::class); } }
 app/Article.php namespace App; use Illuminate\Database\Eloquent\Model; class Article extends Model { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'title', 'content', ]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function user() { return $this->belongsTo(User::class); } }

Amorçage de la base de données

Maintenant que nos modèles et nos migrations sont configurés, ensemençons notre base de données. Nous allons commencer par créer des classes de départ pour nos articles et nos tables d' users :

 $ php artisan make:seeder UsersTableSeeder $ php artisan make:seeder ArticlesTableSeeder

Ensuite, configurons-les pour insérer des données factices dans notre base de données SQLite :

 database/seeds/UsersTableSeeder.php use App\User; use Illuminate\Database\Seeder; class UsersTableSeeder extends Seeder { /** * Run the database seeds. */ public function run() { \App\User::truncate(); $faker = \Faker\Factory::create(); $password = bcrypt('secret'); \App\User::create([ 'name' => $faker->name, 'email' => '[email protected]', 'password' => $password, ]); for ($i = 0; $i < 10; ++$i) { \App\User::create([ 'name' => $faker->name, 'email' => $faker->email, 'password' => $password, ]); } } }
 database/seeds/ArticlesTableSeeder.php use App\Article; use Illuminate\Database\Seeder; class ArticlesTableSeeder extends Seeder { /** * Run the database seeds. */ public function run() { \App\Article::truncate(); \App\Article::unguard(); $faker = \Faker\Factory::create(); \App\User::all()->each(function ($user) use ($faker) { foreach (range(1, 5) as $i) { \App\Article::create([ 'user_id' => $user->id, 'title' => $faker->sentence, 'content' => $faker->paragraphs(3, true), ]); } }); } }
 /database/seeds/DatabaseSeeder.php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(UsersTableSeeder::class); $this->call(ArticlesTableSeeder::class); } }

Enfin, allons-y et exécutons nos semoirs de base de données pour obtenir des données dans notre base de données :

 $ php artisan db:seed

Phare de Laravel et serveur GraphQL

Maintenant que notre base de données et nos modèles sont configurés, il est temps de commencer à développer notre serveur GraphQL. Actuellement, plusieurs solutions sont disponibles pour Laravel, mais pour cet article, nous allons utiliser Lighthouse.

Lighthouse est un package que j'ai créé il y a quelques années et qui a récemment bénéficié d'un soutien incroyable de la part de la communauté grandissante qui l'entoure. Il permet aux développeurs de configurer rapidement un serveur GraphQL à l'aide de Laravel avec peu de passe-partout tout en étant suffisamment flexible pour permettre aux développeurs de le personnaliser pour répondre aux besoins de presque tous les projets.

Illustration du phare de Laravel et du serveur GraphQL

Commençons par insérer le package dans notre projet :

 $ composer require nuwave/lighthouse:"3.1.*"

Ensuite, publions le fichier de configuration de Lighthouse :

 $ php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config

Remarque : Vous pouvez également choisir de publier le fichier de schéma par défaut de Lighthouse en supprimant simplement l'option --tag=config . Mais pour les besoins de cet article, nous allons créer notre fichier de schéma à partir de zéro.

Si nous jetons un coup d'œil au fichier config/lighthouse.php , vous remarquerez un paramètre utilisé pour enregistrer notre fichier de schéma auprès de Lighthouse :

 'schema' => [ 'register' => base_path('graphql/schema.graphql'), ],

Alors allons-y et créons notre fichier de schéma et configurons notre type d'objet utilisateur et notre requête :

 $ mkdir graphql $ touch ./graphql/schema.graphql /graphql/schema.graphql type User { id: ID! name: String! email: String! } type Query { user(id: ID! @eq): User @find users: [User!]! @all }

Vous remarquerez que notre schéma ressemble à celui que nous avons défini précédemment, sauf que nous avons ajouté des identifiants appelés directives de schéma.

Prenons un moment pour décomposer notre schéma défini. Notre première définition est un type d'objet appelé User qui a une relation avec notre modèle éloquent App\User . Nous avons défini l' id , le name et l'e- email comme des champs pouvant être interrogés sur nos modèles User . Autrement, cela signifie que les colonnes password , created_at et updated_at sont des champs qui ne peuvent pas être interrogés à partir de notre API.

Ensuite, nous avons notre type de Query qui est un point d'entrée dans notre API et peut être utilisé pour interroger des données. Notre premier champ est le champ users qui renvoie un tableau de types d'objets User . La directive @all indique à Lighthouse d'exécuter une requête Eloquent, en utilisant notre modèle User et d'obtenir tous les résultats. Ce serait la même chose que d'exécuter ce qui suit :

 $users = \App\User::all();

Remarque : Lighthouse sait rechercher un modèle dans l'espace de noms \App\User en raison de l'option d' namespaces de noms définie dans son fichier de configuration.

Notre deuxième champ défini sur notre type de requête est l'appel user , qui prend un id comme argument et renvoie un seul type d'objet User . Nous avons également ajouté deux directives pour aider Lighthouse à créer automatiquement une requête pour nous et à renvoyer un seul modèle User . La directive @eq indique à Lighthouse d'ajouter un where sur notre colonne id , et la directive @find indique à Lighthouse de renvoyer un seul résultat. Pour écrire cette requête à l'aide du générateur de requêtes de Laravel, cela ressemblerait à ceci :

 $user = \App\User::where('id', $args['id'])->first();

Interroger notre API GraphQL

Maintenant que nous avons un aperçu de la façon dont Lighthouse utilise notre schéma pour créer des requêtes, exécutons notre serveur et commençons à interroger les données. Nous allons commencer par exécuter notre serveur :

 $ php artisan serve Laravel development server started: <http://127.0.0.1:8000>

Pour interroger un point de terminaison GraphQL, vous pouvez exécuter la commande cURL dans le terminal ou un client standard tel que Postman. Cependant, pour bénéficier de tous les avantages de GraphQL (tels que la saisie semi-automatique, la mise en évidence des erreurs, la documentation, etc., nous utiliserons GraphQL Playground (versions téléchargeables ici).

Lors du démarrage de Playground, cliquez sur l'onglet "URL Endpoint" et saisissez http://localhost:8000/graphql pour pointer GraphQL Playground vers notre serveur. Sur le côté gauche de l'éditeur, nous pouvons interroger nos données, alors commençons par demander tous les utilisateurs avec lesquels nous avons ensemencé la base de données :

 { users { id email name } }

Lorsque vous appuyez sur le bouton de lecture au milieu de l'IDE (ou cliquez sur Ctrl+Entrée ), vous verrez la sortie JSON de notre serveur sur le côté droit, qui ressemblera à ceci :

 { "data": { "users": [ { "id": "1", "email": "[email protected]", "name": "Carolyn Powlowski" }, { "id": "2", "email": "[email protected]", "name": "Elouise Raynor" }, { "id": "3", "email": "[email protected]", "name": "Mrs. Dejah Wiza" }, ... ] } }

Remarque : Parce que nous avons utilisé Faker pour ensemencer notre base de données, les données dans les champs de l'e- email et du name seront différentes.

Essayons maintenant d'interroger un seul utilisateur :

 { user(id: 1) { email name } }

Et nous obtiendrons la sortie suivante pour un seul utilisateur :

 { "data": { "user": { "email": "[email protected]", "name": "Carolyn Powlowski" } } }

Interroger des données comme celle-ci est agréable pour commencer, mais il est très peu probable que vous soyez dans un projet où vous voudriez interroger toutes vos données, alors essayons d'ajouter une pagination. Lorsque nous parcourons la large gamme de directives intégrées de Lighthouse, nous avons une directive @paginate à notre disposition, alors mettons à jour l'objet de requête de notre schéma comme suit :

 type Query { user(id: ID! @eq): User @find users: [User!]! @paginate }

Si nous rechargeons GraphQL Playground ( Ctrl/Cmd + R ) et essayons à nouveau la requête de nos users , vous remarquerez que nous recevons un message d'erreur indiquant Cannot query field "id" on type "UserPaginator" , alors que s'est-il passé ? Dans les coulisses, Lighthouse manipule notre schéma pour que nous obtenions un ensemble paginé de résultats et le fait en modifiant le type de retour de notre champ users .

Examinons de plus près en inspectant notre schéma dans l'onglet "Docs" de GraphQL Playground. Si vous regardez le champ users , il renvoie un UserPaginator qui renvoie un tableau d'utilisateurs et un type PaginatorInfo défini par Lighthouse :

 type UserPaginator { paginatorInfo: PaginatorInfo! data: [User!]! } type PaginatorInfo { count: Int! currentPage: Int! firstItem: Int hasMorePages: Boolean! lastItem: Int lastPage: Int! perPage: Int! total: Int! }

Si vous connaissez la pagination intégrée de Laravel, les champs disponibles dans le type PaginatorInfo probablement très familiers. Ainsi, pour interroger deux utilisateurs, obtenir le nombre total d'utilisateurs dans le système et vérifier que nous avons plus de pages à parcourir, nous enverrions la requête suivante :

 { users(count:2) { paginatorInfo { total hasMorePages } data { id name email } } }

Ce qui nous fournira la réponse suivante :

 { "data": { "users": { "paginatorInfo": { "total": 11, "hasMorePages": true }, "data": [ { "id": "1", "name": "Carolyn Powlowski", "email": "[email protected]" }, { "id": "2", "name": "Elouise Raynor", "email": "[email protected]" }, ] } } }

Des relations

Généralement, lors du développement d'une application, une grande partie de vos données est liée. Dans notre cas, un User peut écrire de nombreux Articles , ajoutons donc cette relation à notre type d'utilisateur et définissons notre type d' Article :

 type User { id: ID! name: String! email: String! articles: [Article!]! @hasMany } type Article { id: ID! title: String! content: String! }

Ici, nous utilisons une autre directive de schéma fournie par Lighthouse @hasMany , qui indique à Lighthouse que notre modèle User a une \Illuminate\Database\Eloquent\Relations\HasMany avec le modèle Article .

Interrogeons maintenant notre relation nouvellement définie :

 { user(id:1) { articles { id title } } }

Cela nous fournira la réponse suivante :

 { "data": { "user": { "articles": [ { "id": "1", "title": "Aut velit et temporibus ut et tempora sint." }, { "id": "2", "title": "Voluptatem sed labore ea voluptas." }, { "id": "3", "title": "Beatae sit et maxime consequatur et natus totam." }, { "id": "4", "title": "Corrupti beatae cumque accusamus." }, { "id": "5", "title": "Aperiam quidem sit esse rem sed cupiditate." } ] } } }

Enfin, inversons notre relation et ajoutons notre relation d' author à notre type d'objet Article en utilisant la directive de schéma @belongsTo de Lighthouse ainsi que la mise à jour de notre Query :

 type Article { id: ID! title: String! content: String! author: User! @belongsTo(relation: "user") } type Query { user(id: ID! @eq): User @find users: [User!]! @paginate article(id: ID! @eq): Article @find articles: [Article!]! @paginate }

Vous verrez que nous avons ajouté un argument de relation facultatif à la directive @belongsTo . Cela indique à Lighthouse d'utiliser la relation user du modèle Articles et de l'affecter au champ author .

Maintenant, recherchons une liste d'articles et récupérons leur auteur associé :

 { articles(count:2) { paginatorInfo { total hasMorePages } data { id title author { name email } } } }

Et nous devrions obtenir ce qui suit de notre serveur :

 { "data": { "articles": { "paginatorInfo": { "total": 55, "hasMorePages": true }, "data": [ { "id": "1", "title": "Aut velit et temporibus ut et tempora sint.", "author": { "name": "Carolyn Powlowski", "email": "[email protected]" } }, { "id": "2", "title": "Voluptatem sed labore ea voluptas.", "author": { "name": "Carolyn Powlowski", "email": "[email protected]" } } ] } } }

Mutation GraphQL

Maintenant que nous pouvons interroger nos données, créons quelques mutations pour créer de nouveaux utilisateurs et articles. Commençons par notre modèle utilisateur :

 type Mutation { createUser( name: String! email: String! @rules(apply: ["email", "unique:users"]) password: String! @bcrypt @rules(apply: ["min:6"]) ): User @create }

Décomposons maintenant cette définition de schéma. Nous avons créé une mutation appelée createUser qui prend trois arguments ( name , email et password ). Nous avons appliqué la directive @rules à nos arguments d'e- email et de password de passe. Cela peut sembler un peu familier car il est similaire à la logique de validation que Laravel fournit pour ses contrôleurs.

Ensuite, nous avons attaché la directive @bcrypt à notre champ de password de passe. Cela chiffrera le mot de passe avant qu'il ne soit transmis au modèle nouvellement créé.

Enfin, pour nous aider à créer de nouveaux modèles, Lighthouse fournit une directive de schéma @create qui prendra les arguments que nous avons définis et créera un nouveau modèle. L'exécution de la même logique dans un contrôleur ressemblerait à ceci :

 namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { /** * Create a new user. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $data = $this->validate($request, [ 'email' => ['email', 'unique:users'], 'password' => ['min:6'] ]); $user = \App\User::create($data); return response()->json(['user' => $user]); } }

Maintenant que notre champ de mutation createUser est configuré, allons-y et exécutons-le dans GraphQL Playground avec ce qui suit :

 mutation { createUser( name:"John Doe" email:"[email protected]" password: "secret" ) { id name email } }

Nous devrions obtenir la sortie suivante :

 { "data": { "createUser": { "id": "12", "name": "John Doe", "email": "[email protected]" } } }

Authentification et autorisation GraphQL

Puisque nous devons ajouter un user_id à nos modèles d' Article , ce serait le moment idéal pour passer en revue l'authentification et l'autorisation dans GraphQL/Lighthouse.

texte alternatif de l'image

Pour authentifier un utilisateur, nous devons lui fournir un api_token , créons donc une mutation pour gérer cela et nous ajouterons la directive @field pour pointer Lighthouse vers un résolveur personnalisé qui gérera la logique. Nous définissons le résolveur de la même manière que la définition d'un contrôleur dans Laravel à l'aide de l'argument du resolver .

Avec la directive @field définie ci-dessous, nous disons à Lighthouse lorsque la mutation de login est exécutée, utilisez la méthode createToken sur notre classe App\GraphQL\Mutations\AuthMutator :

 type Mutation { # ... login( email: String! password: String! ): String @field(resolver: "AuthMutator@resolve") }

Remarque : Vous n'avez pas besoin d'inclure l'intégralité de l'espace de noms ici. Dans le fichier de configuration lighthouse.php , vous verrez que nous avons déjà défini l'espace de noms pour nos mutations sur App\\GraphQL\\Mutations . Cependant, vous pouvez utiliser l'espace de noms complet si vous préférez.

Utilisons le générateur de Lighthouse pour créer la nouvelle classe mutator :

 $ php artisan lighthouse:mutation AuthMutator

Ensuite, mettons à jour notre fonction de résolution comme suit :

 namespace App\GraphQL\Mutations; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Facades\Auth; use GraphQL\Type\Definition\ResolveInfo; use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; class AuthMutator { /** * Return a value for the field. * * @param null $rootValue Usually contains the result returned from the parent field. In this case, it is always `null`. * @param mixed[] $args The arguments that were passed into the field. * @param \Nuwave\Lighthouse\Support\Contracts\GraphQLContext $context Arbitrary data that is shared between all fields of a single query. * @param \GraphQL\Type\Definition\ResolveInfo $resolveInfo Information about the query itself, such as the execution state, the field name, path to the field from the root, and more. * @return mixed */ public function resolve($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) { $credentials = Arr::only($args, ['email', 'password']); if (Auth::once($credentials)) { $token = Str::random(60); $user = auth()->user(); $user->api_token = $token; $user->save(); return $token; } return null; } }

Maintenant que notre résolveur est configuré, testons-le et essayons d'obtenir un jeton API en utilisant la mutation suivante dans GraphQL Playground :

 mutation { login(email:"[email protected]", password:"secret") }

Nous devrions nous faire renvoyer un jeton comme ceci :

 { "data": { "login": "VJCz1DCpmdvB9WatqvWbXBP2RN8geZQlrQatUnWIBJCdbAyTl3UsdOuio3VE" } }

Remarque : Assurez-vous de copier le jeton renvoyé par la mutation de connexion afin que nous puissions l'utiliser plus tard.

Ensuite, ajoutons un champ de requête qui renverra l'utilisateur authentifié pour nous assurer que notre logique fonctionne. Nous allons ajouter un champ appelé me ​​et utiliser la directive @auth de Lighthouse pour renvoyer l'utilisateur actuellement authentifié. Nous définirons également l'argument guard égal à api puisque c'est ainsi que nous authentifierons l'utilisateur.

 type Query { # ... me: User @auth(guard: "api") }

Exécutons maintenant la requête. Dans GraphQL Playground, vous pouvez définir vos en-têtes de requête en double-cliquant sur l'onglet "En-têtes HTTP" en bas. Nous ajoutons des en-têtes avec un objet JSON, donc pour ajouter un jeton de support à chaque requête, vous devez ajouter ce qui suit :

 { "Authorization": "Bearer VJCz1DCpmdvB9WatqvWbXBP2RN8geZQlrQatUnWIBJCdbAyTl3UsdOuio3VE" }

Remarque : Remplacez le jeton du porteur par le jeton que vous avez reçu lors de l'exécution de la requête de connexion .

Exécutons maintenant la requête me :

 { me { email articles { id title } } }

Nous devrions obtenir une sortie qui ressemble à ceci :

 { "data": { "me": { "email": "[email protected]", "articles": [ { "id": "1", "title": "Rerum perspiciatis et quos occaecati exercitationem." }, { "id": "2", "title": "Placeat quia cumque laudantium optio voluptatem sed qui." }, { "id": "3", "title": "Optio voluptatem et itaque sit animi." }, { "id": "4", "title": "Excepturi in ad qui dolor ad perspiciatis adipisci." }, { "id": "5", "title": "Qui nemo blanditiis sed fugit consequatur." } ] } } }

Intergiciel

Maintenant que nous savons que notre authentification fonctionne correctement, créons notre dernière mutation pour créer un article en utilisant l'utilisateur actuellement authentifié. Nous utiliserons la directive @field pour pointer Lighthouse vers notre résolveur et nous inclurons également une directive @middleware pour nous assurer qu'un utilisateur est connecté.

 type Mutation { # ... createArticle(title: String!, content: String!): Article @field(resolver: "ArticleMutator@create") @middleware(checks: ["auth:api"]) }

Tout d'abord, générons une classe de mutation :

 $ php artisan lighthouse:mutation ArticleMutator

Ensuite, mettons à jour le mutateur avec la logique suivante :

 namespace App\GraphQL\Mutations; use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; class ArticleMutator { /** * Return a value for the field. * * @param null $rootValue * @param mixed[] $args * @param \Nuwave\Lighthouse\Support\Contracts\GraphQLContext $context * @return mixed */ public function create($rootValue, array $args, GraphQLContext $context) { $article = new \App\Article($args); $context->user()->articles()->save($article); return $article; } }

Remarque : nous avons renommé la fonction de resolve par défaut en create . Vous n'avez pas besoin de créer une nouvelle classe pour chaque résolveur. Au lieu de cela, vous pouvez regrouper la logique si cela a plus de sens.

Enfin, exécutons notre nouvelle mutation et vérifions la sortie. Assurez-vous de conserver l'en-tête d' Authorization de notre requête précédente dans l'onglet "En-têtes HTTP" :

 mutation { createArticle( title:"Building a GraphQL Server with Laravel" content:"In case you're not currently familiar with it, GraphQL is a query language used to interact with your API..." ) { id author { id email } } }

Nous devrions obtenir la sortie suivante :

 { "data": { "createArticle": { "id": "56", "author": { "id": "1", "email": "[email protected]" } } } }

Emballer

Pour récapituler, nous avons utilisé Lighthouse pour créer un serveur GraphQL pour notre projet Laravel. Nous avons utilisé certaines directives de schéma intégrées, créé des requêtes et des mutations, et géré l'autorisation et l'authentification.

Lighthouse vous permet de faire beaucoup plus (comme vous permettre de créer vos propres directives de schéma personnalisées), mais pour les besoins de cet article, nous nous sommes tenus aux bases et nous avons pu mettre en place un serveur GraphQL avec assez peu de passe-partout.

La prochaine fois que vous devrez configurer une API pour une application mobile ou d'une seule page, assurez-vous de considérer GraphQL comme un moyen d'interroger vos données !

En relation: Authentification complète de l'utilisateur et contrôle d'accès - Un didacticiel sur le passeport Laravel, Pt. 1