Construirea unui server GraphQL cu Laravel
Publicat: 2022-03-11În cazul în care încă nu sunteți familiarizat cu acesta, GraphQL este un limbaj de interogare utilizat pentru a interacționa cu API-ul dvs., care oferă unele beneficii în comparație cu arhitecturile alternative, cum ar fi REST. GraphQL este extrem de util atunci când este folosit ca punct final pentru aplicații mobile și cu o singură pagină. GraphQL vă permite să interogați datele imbricate și legate într-o solicitare cu relativă ușurință, permițând dezvoltatorilor să obțină datele exacte de care au nevoie într-o singură călătorie dus-întors la server.
Laravel este un cadru web PHP popular, cu opinie. Oferă numeroase instrumente încorporate pentru ca aplicațiile să funcționeze rapid, dar le permite, de asemenea, dezvoltatorilor să schimbe propriile implementări pentru interfețele încorporate ale Laravel, atunci când sunt preferate.
Deși comunitățile care înconjoară atât GraphQL, cât și Laravel s-au dezvoltat dramatic de când au fost open-source, documentația care explică modul de utilizare a acestor două tehnologii împreună este încă oarecum limitată.
Deci, în acest tutorial, vă voi arăta cum să vă creați propriul server GraphQL folosind Laravel.
rezumatul proiectului
Înainte de a începe, va trebui să ne familiarizăm cu proiectul pe care încercăm să îl construim. Pentru a face asta, ne vom defini resursele și vom crea schema noastră GraphQL, pe care o vom folosi ulterior pentru a servi API-ul nostru.
Resurse pentru proiect
Aplicația noastră va consta din două resurse: Articole și Utilizatori . Aceste resurse vor fi definite ca tipuri de obiecte în schema noastră GraphQL:
type User { id: ID! name: String! email: String! articles: [Article!]! } type Article { id: ID! title: String! content: String! author: User! }
Privind schema, putem vedea că avem o relație unu-la-mulți între cele două obiecte ale noastre. Utilizatorii pot scrie multe articole, iar un articol are un autor (utilizator) alocat.
Acum că avem tipurile de obiecte definite, vom avea nevoie de o modalitate de a crea și interoga datele noastre, așa că haideți să definim obiectele noastre de interogare și mutație:
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 }
Stabilirea proiectului nostru Laravel
Acum că ne-am definit schema GraphQL, să punem în funcțiune proiectul nostru Laravel. Să începem prin a crea un nou proiect Laravel prin Composer:
$ composer create-project --prefer-dist laravel/laravel laravel-graphql
Doar pentru a ne asigura că totul funcționează, să pornim serverul nostru și să ne asigurăm că vedem pagina implicită a lui Laravel:
$ cd laravel-graphql $ php artisan serve Laravel development server started: <http://127.0.0.1:8000>
Modele de baze de date și migrații
În scopul acestui articol, vom folosi SQLite. Deci, să facem următoarele modificări fișierului implicit .env
:
DB_CONNECTION=sqlite # DB_HOST= # DB_PORT= # DB_DATABASE=database.sqlite # DB_USERNAME= # DB_PASSWORD=
În continuare, să creăm fișierul nostru de bază de date:
$ touch ./database/database.sqlite
Laravel este livrat cu un model de utilizator și câteva fișiere de migrare de bază. Să adăugăm rapid o coloană api_token
în fișierul nostru de migrare CreateUsersTable
oferit nouă de 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'); } }
Vom reveni la această coloană suplimentară mai târziu în articol, când ajungem la autorizare. Acum să mergem mai departe și să creăm modelul nostru de articol și un fișier de migrare pentru a crea tabelul asociat:
$ php artisan make:model Article -m
Notă: opțiunea -m creează un fișier de migrare pentru modelul nostru de articol nou creat.
Să facem câteva ajustări la fișierul de migrare generat:
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'); } }
Am adăugat o cheie externă care indică id
-ul din tabelul users
, precum și coloanele de title
și content
pe care le-am definit în schema noastră GraphQL.
Acum că avem fișierele noastre de migrare definite, să mergem mai departe și să le rulăm în baza noastră de date:
$ php artisan migrate
În continuare, să ne actualizăm modelele prin definirea relațiilor necesare:
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); } }
Semănarea bazei de date
Acum că ne-am configurat modelele și migrațiile, haideți să ne înființăm baza de date. Vom începe prin a crea câteva clase de seeder pentru articles
noastre și tabelele users
:
$ php artisan make:seeder UsersTableSeeder $ php artisan make:seeder ArticlesTableSeeder
Apoi, să le setăm să insereze niște date false în baza noastră de date 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); } }
În cele din urmă, să mergem mai departe și să rulăm seedersele noastre de baze de date pentru a obține câteva date în baza noastră de date:
$ php artisan db:seed
Laravel Lighthouse și GraphQL Server
Acum că avem baza de date și modelele configurate, este timpul să începem să construim serverul nostru GraphQL. În prezent, există mai multe soluții disponibile pentru Laravel, dar pentru acest articol vom folosi Lighthouse.
Lighthouse este un pachet pe care l-am creat cu câțiva ani în urmă și recent a primit un sprijin uimitor din partea comunității în creștere din jurul lui. Le permite dezvoltatorilor să configureze rapid un server GraphQL utilizând Laravel cu un mic boilerplate, fiind, de asemenea, suficient de flexibil pentru a permite dezvoltatorilor să-l personalizeze pentru a se potrivi nevoilor aproape oricărui proiect.
Să începem prin a introduce pachetul în proiectul nostru:
$ composer require nuwave/lighthouse:"3.1.*"
În continuare, să publicăm fișierul de configurare al lui Lighthouse:
$ php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config
Notă: De asemenea, puteți alege să publicați fișierul de schemă implicit al Lighthouse prin simpla eliminare a --tag=config
. Dar în scopul acestui articol, vom crea fișierul nostru de schemă de la zero.
Dacă aruncăm o privire la fișierul config/lighthouse.php
, veți observa o setare folosită pentru a înregistra fișierul nostru de schemă cu Lighthouse:
'schema' => [ 'register' => base_path('graphql/schema.graphql'), ],
Deci, să mergem mai departe și să creăm fișierul nostru de schemă și să setăm tipul și interogarea obiectului utilizator:
$ 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 }
Veți observa că schema noastră arată similar cu cea pe care am definit-o mai devreme, cu excepția faptului că am adăugat niște identificatori numiți directive de schemă.
Să luăm un moment pentru a descompune schema noastră definită. Prima noastră definiție este un tip de obiect numit User
care are o relație cu modelul nostru elocvent App\User
. Am definit id
-ul, name
și e- email
ca câmpuri care pot fi interogate din modelele noastre de User
. Alternativ, aceasta înseamnă că coloanele password
, created_at
și updated_at
sunt câmpuri pentru care nu pot fi solicitate din API-ul nostru.
Apoi avem tipul nostru de Query
, care este un punct de intrare în API-ul nostru și poate fi folosit pentru a interoga date. Primul nostru câmp este câmpul users
, care returnează o serie de tipuri de obiecte User
. Directiva @all
îi spune lui Lighthouse să execute o interogare Eloquent, folosind modelul nostru User
și să obțină toate rezultatele. Acest lucru ar fi același cu rularea următoarelor:
$users = \App\User::all();
Notă: Lighthouse știe să caute un model în spațiul de nume \App\User
din cauza opțiunii de namespaces
de nume definite în fișierul său de configurare.
Al doilea câmp definit pe tipul nostru de interogare este call user
, care ia un id
ca argument și returnează un singur tip de obiect User
. De asemenea, am adăugat două directive pentru a ajuta Lighthouse să construiască automat o interogare pentru noi și să returneze un singur model de User
. Directiva @eq
îi spune lui Lighthouse să adauge un where pe coloana noastră id
, iar directiva @find
indică lui Lighthouse să returneze un singur rezultat. Pentru a scrie această interogare folosind generatorul de interogări Laravel, ar arăta astfel:
$user = \App\User::where('id', $args['id'])->first();
Interogarea API-ului nostru GraphQL
Acum că avem o mică perspectivă asupra modului în care Lighthouse folosește schema noastră pentru a crea interogări, să rulăm serverul nostru și să începem să interogăm datele. Vom începe prin a rula serverul nostru:
$ php artisan serve Laravel development server started: <http://127.0.0.1:8000>
Pentru a interoga un punct final GraphQL, puteți rula comanda cURL în terminal sau un client standard, cum ar fi Postman. Cu toate acestea, pentru a beneficia de toate beneficiile GraphQL (cum ar fi completarea automată, evidențierea erorilor, documentația etc., vom folosi GraphQL Playground (descărcări de lansare aici).
Când porniți Playground, faceți clic pe fila „URL Endpoint” și introduceți http://localhost:8000/graphql pentru a direcționa GraphQL Playground către serverul nostru. În partea stângă a editorului, putem interoga datele noastre, așa că să începem prin a întreba toți utilizatorii cu care am seed baza de date:
{ users { id email name } }
Când apăsați butonul de redare din mijlocul IDE-ului (sau faceți clic pe Ctrl+Enter ), veți vedea rezultatul JSON al serverului nostru în partea dreaptă, care va arăta cam așa:
{ "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" }, ... ] } }
Notă: Deoarece am folosit Faker pentru a genera baza noastră de date, datele din câmpurile de e- email
și name
vor fi diferite.
Acum să încercăm să interogăm un singur utilizator:
{ user(id: 1) { email name } }
Și vom obține următoarea ieșire pentru un singur utilizator:
{ "data": { "user": { "email": "[email protected]", "name": "Carolyn Powlowski" } } }
Este plăcut să începeți să interogați astfel de date, dar este foarte puțin probabil să vă aflați într-un proiect în care ați dori vreodată să interogați pentru toate datele dvs., așa că să încercăm să adăugăm o paginare. Când căutăm prin gama largă de directive încorporate Lighthouse, avem o directivă @paginate
disponibilă pentru noi, așa că haideți să actualizăm obiectul de interogare al schemei noastre astfel:

type Query { user(id: ID! @eq): User @find users: [User!]! @paginate }
Dacă reîncărcăm GraphQL Playground ( Ctrl/Cmd + R ) și încercăm din nou interogarea users
noștri, veți observa că primim un mesaj de eroare care indică Cannot query field "id" on type "UserPaginator"
, deci ce s-a întâmplat? În culise, Lighthouse manipulează schema noastră pentru a obține un set paginat de rezultate și face acest lucru schimbând tipul de returnare al câmpului users
noștri.
Să aruncăm o privire mai atentă, inspectând schema noastră în fila „Docs” a GraphQL Playground. Dacă aruncați o privire la câmpul users
, acesta returnează un UserPaginator
care returnează o serie de utilizatori și un tip PaginatorInfo
definit de 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! }
Dacă sunteți familiarizat cu paginarea încorporată a lui Laravel, câmpurile disponibile în tipul PaginatorInfo
vor părea probabil foarte familiare. Deci, pentru a interoga pentru doi utilizatori, pentru a obține numărul total de utilizatori din sistem și pentru a verifica dacă avem mai multe pagini de parcurs, vom trimite următoarea interogare:
{ users(count:2) { paginatorInfo { total hasMorePages } data { id name email } } }
Care ne va oferi următorul răspuns:
{ "data": { "users": { "paginatorInfo": { "total": 11, "hasMorePages": true }, "data": [ { "id": "1", "name": "Carolyn Powlowski", "email": "[email protected]" }, { "id": "2", "name": "Elouise Raynor", "email": "[email protected]" }, ] } } }
Relații
În general, atunci când dezvoltați o aplicație, multe dintre datele dvs. sunt legate. În cazul nostru, un User
poate scrie multe Articles
, așa că haideți să adăugăm acea relație la tipul nostru de utilizator și să definim tipul nostru de Article
:
type User { id: ID! name: String! email: String! articles: [Article!]! @hasMany } type Article { id: ID! title: String! content: String! }
Aici, folosim o altă directivă de schemă furnizată de Lighthouse @hasMany
, care îi spune lui Lighthouse modelului nostru de User
are o relație \Illuminate\Database\Eloquent\Relations\HasMany
cu modelul Article
.
Acum să interogăm relația noastră nou definită:
{ user(id:1) { articles { id title } } }
Acest lucru ne va oferi următorul răspuns:
{ "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." } ] } } }
În cele din urmă, să inversăm relația noastră și să adăugăm relația noastră cu author
la tipul nostru de obiect Article
folosind directiva de schemă @belongsTo
a Lighthouse, precum și actualizarea Query
noastre:
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 }
Veți vedea că am adăugat un argument de relation
opțional la directiva @belongsTo
. Acest lucru îi spune lui Lighthouse să folosească relația cu user
modelului Articles
și să o atribuie câmpului de author
.
Acum să căutăm o listă de articole și să luăm autorul asociat:
{ articles(count:2) { paginatorInfo { total hasMorePages } data { id title author { name email } } } }
Și ar trebui să obținem următoarele de la serverul nostru:
{ "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]" } } ] } } }
Mutația GraphQL
Acum că ne putem interoga datele, să creăm câteva mutații pentru a crea niște utilizatori și articole noi. Vom începe cu modelul nostru de utilizator:
type Mutation { createUser( name: String! email: String! @rules(apply: ["email", "unique:users"]) password: String! @bcrypt @rules(apply: ["min:6"]) ): User @create }
Acum să descompunem această definiție a schemei. Am creat o mutație numită createUser
care ia trei argumente ( name
, email
și password
). Am aplicat directiva @rules
atât argumentelor noastre de e- email
, cât și de password
. Acest lucru poate părea puțin familiar, deoarece este similar cu logica de validare pe care Laravel o oferă controlerelor sale.
Apoi, am atașat directiva @bcrypt
la câmpul nostru de password
. Aceasta va cripta parola înainte de a fi transmisă modelului nou creat.
În cele din urmă, pentru a ne ajuta să creăm noi modele, Lighthouse oferă o directivă @create
schema care va prelua argumentele pe care le-am definit și va crea un nou model. Efectuarea aceleiași logici într-un controler ar arăta astfel:
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]); } }
Acum că avem câmpul de mutație createUser configurat, să mergem mai departe și să-l rulăm în GraphQL Playground cu următoarele:
mutation { createUser( name:"John Doe" email:"[email protected]" password: "secret" ) { id name email } }
Ar trebui să obținem următorul rezultat:
{ "data": { "createUser": { "id": "12", "name": "John Doe", "email": "[email protected]" } } }
Autentificare și autorizare GraphQL
Deoarece trebuie să adăugăm un user_id
la modelele noastre de Article
, acum ar fi un moment grozav să trecem peste autentificare și autorizare în GraphQL/Lighthouse.
Pentru a autentifica un utilizator, trebuie să îi furnizăm un api_token
, așa că haideți să creăm o mutație pentru a gestiona asta și vom adăuga directiva @field
pentru a indica Lighthouse către un resolver personalizat care se va ocupa de logica. Am setat rezolutorul în același model ca și definirea unui controler în Laravel folosind argumentul resolver
.
Cu directiva @field
definită mai jos, îi spunem lui Lighthouse când se rulează mutația de login
, utilizați metoda createToken
în clasa noastră App\GraphQL\Mutations\AuthMutator
:
type Mutation { # ... login( email: String! password: String! ): String @field(resolver: "AuthMutator@resolve") }
Notă: nu trebuie să includeți aici întregul spațiu de nume. În fișierul de configurare lighthouse.php
, veți vedea că avem spațiul de nume definit pentru mutațiile noastre deja setat ca App\\GraphQL\\Mutations
—cu toate acestea, puteți utiliza spațiul de nume complet dacă preferați.
Să folosim generatorul Lighthouse pentru a crea noua clasă mutator:
$ php artisan lighthouse:mutation AuthMutator
În continuare, să actualizăm funcția de rezolvare astfel:
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; } }
Acum că avem soluția configurată, să-l testăm și să încercăm să obținem un token API folosind următoarea mutație în GraphQL Playground:
mutation { login(email:"[email protected]", password:"secret") }
Ar trebui să primim un token trimis înapoi la noi astfel:
{ "data": { "login": "VJCz1DCpmdvB9WatqvWbXBP2RN8geZQlrQatUnWIBJCdbAyTl3UsdOuio3VE" } }
Notă: Asigurați-vă că copiați simbolul returnat de la mutația de conectare, astfel încât să îl putem folosi mai târziu.
Apoi, să adăugăm un câmp de interogare care va returna utilizatorul autentificat pentru a ne asigura că logica noastră funcționează. Vom adăuga un câmp numit me
și vom folosi directiva Lighthouse @auth
pentru a returna utilizatorul autentificat în prezent. De asemenea, vom seta argumentul de guard
egal cu api
, deoarece așa vom autentifica utilizatorul.
type Query { # ... me: User @auth(guard: "api") }
Acum să rulăm interogarea. În GraphQL Playground, puteți seta antetele solicitării dvs. făcând dublu clic pe fila „Http Headers” din partea de jos. Adăugăm anteturi cu un obiect JSON, așa că pentru a adăuga un token purtător la fiecare solicitare, ați adăuga următoarele:
{ "Authorization": "Bearer VJCz1DCpmdvB9WatqvWbXBP2RN8geZQlrQatUnWIBJCdbAyTl3UsdOuio3VE" }
Notă: Înlocuiți simbolul purtător cu simbolul pe care l-ați primit când rulați interogarea de conectare .
Acum hai să rulăm interogarea me
:
{ me { email articles { id title } } }
Ar trebui să obținem rezultate care arată astfel:
{ "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." } ] } } }
Middleware
Acum că știm că autentificarea noastră funcționează corect, să creăm ultima noastră mutație pentru a crea un articol folosind utilizatorul autentificat în prezent. Vom folosi directiva @field
pentru a indica Lighthouse către soluția noastră și vom include, de asemenea, o directivă @middleware
pentru a ne asigura că un utilizator este conectat.
type Mutation { # ... createArticle(title: String!, content: String!): Article @field(resolver: "ArticleMutator@create") @middleware(checks: ["auth:api"]) }
Mai întâi, să generăm o clasă de mutație:
$ php artisan lighthouse:mutation ArticleMutator
În continuare, să actualizăm mutatorul cu următoarea logică:
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; } }
Notă: am redenumit funcția de resolve
implicită pentru a create
. Nu trebuie să creați o nouă clasă pentru fiecare rezolutor. În schimb, puteți grupa logica dacă are mai mult sens.
În cele din urmă, să rulăm noua noastră mutație și să verificăm rezultatul. Asigurați-vă că păstrați antetul de Authorization
din interogarea noastră anterioară în fila „Anteturi 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 } } }
Ar trebui să obținem următorul rezultat:
{ "data": { "createArticle": { "id": "56", "author": { "id": "1", "email": "[email protected]" } } } }
Încheierea
Pentru a recapitula, am folosit Lighthouse pentru a crea un server GraphQL pentru proiectul nostru Laravel. Am folosit câteva directive de schemă încorporate, am creat interogări și mutații și am gestionat autorizarea și autentificarea.
Lighthouse vă permite să faceți mult mai multe (cum ar fi să vă permiteți să vă creați propriile directive de schemă personalizată), dar în sensul acestui articol ne-am păstrat la elementele de bază și am reușit să punem în funcțiune un server GraphQL cu destul de puține standarde.
Data viitoare când trebuie să configurați un API pentru o aplicație mobilă sau cu o singură pagină, asigurați-vă că luați în considerare GraphQL ca o modalitate de a vă interoga datele!