GraphQL یک زبان کوئری برای API ها است و می تواند برای کوئریی داده ها از یک سرور استفاده شود و در عین حال به کلاینت اجازه می دهد دقیقاً چه داده هایی را مورد نیاز قرار دهند.
رابط های برنامه نویسی کاربردی (API) یک عنصر حیاتی در توسعه وب مدرن هستند. آنها به برنامهها و سرویسهای مختلف اجازه میدهند با یکدیگر ارتباط برقرار کنند، دادهها و عملکرد را به اشتراک بگذارند، که توسعهدهندگان را قادر میسازد تا سیستمهای پیچیده و متصل به هم ایجاد کنند که با برنامههای مستقل غیرممکن است.
یکی از محبوب ترین و قدرتمندترین فناوری های API امروزه GraphQL است. برخلاف APIهای REST سنتی که دارای نقاط پایانی ثابت هستند و ساختارهای داده از پیش تعریف شده را برمیگردانند، APIهای GraphQL به کلاینت اجازه میدهند تا دادههای مورد نیاز خود را دقیقاً تعریف کنند و آنها را در قالبی قابل پیشبینی و سلسله مراتبی دریافت کنند. این امکان واکشی دادهها را انعطافپذیرتر و کارآمدتر میسازد و نیاز به واکشی بیش از حد یا کم واکشی دادهها را از بین میبرد.
در این مقاله، نحوه ایجاد یک API GraphQL با لاراول، یک فریمورک وب محبوب PHP را یاد خواهیم گرفت. ما یک مدل دانشجویی ساده ایجاد می کنیم، پایگاه داده را با داده های ساختگی می یابیم، یک اتصال پایگاه داده را راه اندازی می کنیم، و با تعریف اسکیما،کوئریها و جهش های(mutations) API خود، یک سرور GraphQL ایجاد می کنیم.
در پایان این مقاله، شما یک GraphQL API فعال خواهید داشت که می توانید به گسترش و بهبود آن ادامه دهید.
چندین مزیت برای استفاده از GraphQL برای API شما وجود دارد:
انعطاف پذیری: همانطور که در بالا ذکر شد، با GraphQL، کلاینت می توانند داده های مورد نیاز خود را مشخص کرده و در قالبی قابل پیش بینی و سلسله مراتبی دریافت کنند. این امکان واکشی دادهها را انعطافپذیرتر و کارآمدتر میسازد و تمایل به واکشی بیش از حد یا کمتر واکشی دادهها را از بین میبرد.
عملکرد بهتر: از آنجایی که APIهای GraphQL به کلاینتها اجازه میدهند دقیقاً دادههای مورد نیاز خود را مشخص کنند، کلاینت اغلب میتوانند آنها را در یک درخواست واکشی کنند، که تعداد رفت و برگشتها به سرور را کاهش میدهد و عملکرد را بهبود میبخشد.
اسکیما با تایپ قوی: اسکیما های GraphQL به شدت تایپ می شوند، به این معنی که داده های بازگردانده شده توسط GraphQL API همیشه در قالب یکسانی هستند. این امر پیشبینی شکل دادهها را آسانتر میکند و نیاز کلاینت به رسیدگی به موارد لبه و ساختارهای داده غیرمنتظره را کاهش میدهد.
سهولت استفاده: GraphQL یک زبان جستجوی ساده و بصری است که یادگیری و استفاده از آن برای توسعه دهندگان آسان است. همچنین دارای یک جامعه توسعهدهنده بزرگ و فعال است که کتابخانهها و ابزارهای زیادی (مانند Apollo، Relay، Prisma و GraphiQL) برای کمک به کارهای رایج در دسترس است.
سازگاری به بک اند: از آنجایی که GraphQL به کلاینت اجازه می دهد تا داده های مورد نیاز خود را مشخص کنند، می توان تغییرات سازگار با بک اند را در API بدون شکستن کلاینت های موجود ایجاد کرد.
پیش نیازها
برای ایجاد یک GraphQL API با لاراول، باید درک اولیه ای از چارچوب لاراول و زبان کوئری GraphQL داشته باشید.
علاوه بر این، مطمئن شوید که موارد زیر را روی دستگاه خود نصب کرده باشید:
PHP 7.4 یا بالاتر
لاراول 7.0 یا بالاتر
مرحله 1: راه اندازی پروژه لاراول
ترمینال خود را باز کنید و به دایرکتوری که می خواهید پروژه خود را ایجاد کنید بروید. سپس دستور زیر را برای ایجاد یک پروژه جدید لاراول اجرا کنید:
composer create-project --prefer-dist laravel/laravel graphql-anophel
با این کار یک پروژه لاراول جدید در دایرکتوری به نام graphql-anophel ایجاد می شود.
میکروسرویس ها در مقابل مونولیث ها
چگونه یک نقشه تست موفق بنویسیم
مرحله 2: راه اندازی پایگاه داده
بعد، باید یک اتصال پایگاه داده را راه اندازی کنیم. فایل env.
را در ریشه پروژه خود باز کنید و خطوط زیر را با اطلاعات پایگاه داده خود به روز کنید:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=YOUR_DATABASE_NAME
DB_USERNAME=YOUR_DATABASE_USERNAME
DB_PASSWORD=YOUR_DATABASE_PASSWORD
مرحله 3: ایجاد مدل Student
در مرحله بعد، یک مدل دانشجویی و یک فایل Migration
مربوطه ایجاد می کنیم تا جدول دانشجویان در پایگاه داده ایجاد شود. برای ایجاد مدل و فایل Migration دستور زیر را اجرا کنید:
php artisan make:model Student -m
این یک مدل Student و یک فایل Migration در دایرکتوری \Database\Migrations
ایجاد می کند. فایل Migration را باز کنید و ستون های زیر را به جدول دانشجویان اضافه کنید:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateStudentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('students', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->integer('age');
$table->string('country');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('students');
}
}
سپس دستور زیر را برای ایجاد جدول دانشجویان در پایگاه داده اجرا کنید:
php artisan migrate
همچنین میخواهید این فیلدها را به مدل Student در app/model/Student.php
اضافه کنید:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
protected $fillable = ["name", "email", "age", "country"];
}
مرحله 4: ایجاد یک فایل seder
در مرحله بعد، ما یک فایل seder ایجاد می کنیم تا جدول دانشجویان را با داده های ساختگی تخمین بزنیم:
php artisan make:seeder StudentTableSeeder
با این کار یک فایل seder به نام StudentTableSeeder.php
در فهرست Database/seeds
ایجاد می شود.
فایل seder را باز کنید و کد زیر را اضافه کنید:
<?php
use Illuminate\Database\Seeder;
use App\Student;
class StudentTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Create 10 students
factory(Student::class, 10)->create();
}
}
این کد از factory
لاراول برای ایجاد 10 دانشجو و درج آنها در جدول دانشجویان استفاده می کند. سپس فایل DatabaseSeeder.php
را باز کرده و خط زیر را به متد ()run
اضافه کنید:
$this->call(StudentTableSeeder::class);
هنگامی که دستور db:seed
را اجرا می کنید، StudentTableSeeder
را اجرا می کند. در نهایت دستور زیر را اجرا کنید تا جدول دانشجویان با داده های ساختگی ظاهر شود:
php artisan db:seed
داکر چیست؟ آشنایی با داکر و کانتینر
CI/CD چیست؟ آشنایی با استقرار مداوم و ادغام مستمر
مرحله 5: نصب بسته rebing/graphql-laravel
در مرحله بعد، بسته rebing/graphql-laravel
را نصب می کنیم که به ما امکان می دهد به راحتی یک سرور GraphQL در لاراول ایجاد کنیم.
composer require rebing/graphql-laravel
این وابستگی های لازم را به پروژه لاراول شما اضافه می کند. پس از نصب بسته، دستور زیر را برای انتشار فایل پیکربندی GraphQL اجرا کنید:
php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider"
مرحله 6: ایجاد سرور GraphQL
سپس سرور GraphQL را ایجاد می کنیم. ابتدا یک دایرکتوری graphql در routes ایجاد کنید. سپس یک فایل به نام StudentType.php
در پوشه routes/graphql
ایجاد کنید و کد زیر را اضافه کنید:
<?php
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
class StudentType extends GraphQLType
{
protected $attributes = [
'name' => 'Student',
'description' => 'A student',
'model' => \App\Student::class
];
public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The id of the student'
],
'name' => [
'type' => Type::string(),
'description' => 'The name of the student'
],
'email' => [
'type' => Type::string(),
'description' => 'The email of the student'
],
'age' => [
'type' => Type::int(),
'description' => 'The age of the student'
],
'country' => [
'type' => Type::string(),
'description' => 'The country of the student'
],
'created_at' => [
'type' => Type::string(),
'description' => 'The date the student was created',
'resolve' => function($model) {
return $model->created_at;
}
],
'updated_at' => [
'type' => Type::string(),
'description' => 'The date the student was last updated',
'resolve' => function($model) {
return $model->updated_at;
}
]
];
}
}
کد بالا یک نوع GraphQL به نام StudentType
ایجاد می کند که نشان دهنده دانشجو در پایگاه داده است. فیلدهایی را برای id، نام، ایمیل، سن، کشور، ستون های create_at
و updated_at
جدول دانشجویان تعریف می کند.
در تابع ()fields
متوجه خواهید شد که هر فیلد در StudentType
دارای پارامترهای نوع و توضیحات است. فیلدها در یک نوع GraphQL نیاز به یک نوع و توضیحات دارند زیرا این پارامترها اطلاعات مهمی را برای سرور GraphQL فراهم میکنند تا دادههای درخواست شده یا ارائه شده توسط کلاینت را درک و تأیید کند. نوع، نوع داده فیلد، مانند رشته یا عدد صحیح را مشخص میکند، و توضیحات اطلاعات بیشتری در مورد فیلد، مانند هدف یا قالب مورد انتظار آن، ارائه میدهد. این اطلاعات توسط سرور GraphQL برای رسیدگی و پاسخگویی مناسب به کوئری ها و جهش های کلاینت و همچنین توسط ابزارهای مختلف مانند کلاینت های GraphQL و IDE ها برای تولید اسناد و پشتیبانی بهتر برای توسعه دهندگان استفاده می شود.
اکنون یک فایل به نام StudentsQuery.php
در پوشه routes/graphql
ایجاد کنید. فایل را باز کنید و کد زیر را اضافه کنید:
?php
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
class StudentsQuery extends Query
{
protected $attributes = [
'name' => 'students'
];
public function type(): Type
{
return Type::listOf(GraphQL::type('student'));
}
public function args(): array
{
return [
'id' => [
'name' => 'id',
'type' => Type::int()
],
'name' => [
'name' => 'name',
'type' => Type::string()
],
'email' => [
'name' => 'email',
'type' => Type::string()
],
'age' => [
'name' => 'age',
'type' => Type::int()
],
'country' => [
'name' => 'country',
'type' => Type::string()
]
];
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return Student::where('id', $args['id'])->get();
}
if (isset($args['name'])) {
return Student::where('name', $args['name'])->get();
}
if (isset($args['email'])) {
return Student::where('email', $args['email'])->get();
}
if (isset($args['age'])) {
return Student::where('age', $args['age'])->get();
}
if (isset($args['country'])) {
return Student::where('country', $args['country'])->get();
}
return Student::all();
}
}
کدی که در بالا داریم یک فیلد Query GraphQL را برای لیستی از دانشجویان تعریف می کند. آرایه attributes$
محافظت شده نام فیلد را به عنوان "students"
تنظیم می کند. بنابراین، هنگامی که یک برنامه کلاینت یک کوئری انجام می دهد، از این نام برای درخواست لیست دانشجویان استفاده می کند. تابع ()public type
نوع فیلد را برمی گرداند. در این مورد، از تابع کمکی ()Type::listOf
استفاده می کند تا نشان دهد که این فیلد لیستی از موارد است. آرگومان ارسال شده به تابع GraphQL::type('student')
، مشخص می کند که هر آیتم در لیست از نوع Student است. بنابراین، هنگامی که کلاینت برای این فیلد کوئری می کند، سرور می داند که در انتظار لیستی از اشیاء دانشجویی است و داده های مناسب را بازیابی و به کلاینت باز می گرداند.
تابع عمومی ()args
آرایه ای از فیلدهای ورودی را برای کوئری برمی گرداند. ما از این فیلدها برای بازیابی داده ها از سرور GraphQL خود استفاده خواهیم کرد. پارامتر نام برای هر فیلد مشخص میکند که چگونه دادههای این فیلد در سمت سرویس گیرنده بازیابی شوند و پارامتر type نوع دادههایی را که از این فیلد بازیابی میشوند را مشخص میکند.
تابع Resolution در یک کوئری GraphQL مسئول واکشی داده ها از سرور بر اساس آرگومان های ورودی است. تابع دارای دو پارامتر root$ و args$ است. root$ به شی ریشه کوئری اشاره می کند و args$ به آرگومان های ورودی ارسال شده به کوئری اشاره دارد.
در تابع، با بررسی اینکه آیا آرگومان id در کوئری ارسال شده است، شروع می کنیم. اگر اینطور باشد، با استفاده از روش Eloquent's where، شناسه را در پایگاه داده خود جستجو می کنیم، نتیجه را با استفاده از متد get دریافت می کنیم و آن را به کلاینت خود برمی گردانیم. وقتی آرگومان name پاس شد، با استفاده از روش Eloquent's where و گرفتن نتیجه با استفاده از متد get، همه دانشجویان را با نام داده شده برمی گردانیم. همین منطق در مورد آرگومان های ایمیل، سن و کشور نیز صدق می کند. اگر هیچ یک از این آرگومان ها پاس نشود، با استفاده از متد all، همه دانشجویان را برمی گرداند.
جهش mutations
شما باید این را از قبل بدانید، اما جهش GraphQL نوعی عملیات است که به کلاینت اجازه می دهد تا داده های سرور را تغییر دهد. شبیه درخواست POST، PUT یا PATCH در REST است. در اینجا جهش هایی وجود دارد که سرور ما به آن نیاز دارد:
Create: به کلاینت امکان می دهد دانشجو جدیدی در سرور ایجاد کند.
به روز رسانی: به کلاینت امکان می دهد یک دانشجو موجود در سرور را به روز کند.
Delete: به کلاینت اجازه می دهد دانشجوی را در سرور حذف کند.
برای اولین جهش، یک فایل به نام CreateStudentMutation.php
در فهرست مسیرها ایجاد کنید و کد زیر را اضافه کنید:
<?php
use App\Student;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class CreateStudentMutation extends Mutation
{
protected $attributes = [
'name' => 'createStudent'
];
public function type(): Type
{
return GraphQL::type('student');
}
public function args(): array
{
return [
"id" => [
'name' => 'id',
'type' => Type::nonNull(Type::int()),
],
'name' => [
'name' => 'name',
'type' => Type::nonNull(Type::string())
],
'email' => [
'name' => 'email',
'type' => Type::nonNull(Type::string())
],
'age' => [
'name' => 'age',
'type' => Type::nonNull(Type::int())
],
'country' => [
'name' => 'country',
'type' => Type::nonNull(Type::string())
]
];
}
public function resolve($root, $args)
{
$student = new Student();
$student->name = $args['name'];
$student->email = $args['email'];
$student->age = $args['age'];
$student->country = $args['country'];
$student->save();
return $student;
}
}
در بالا، ما یک جهش GraphQL به نام createStudent ایجاد کردیم که به کلاینت اجازه می دهد دانشجو جدیدی در پایگاه داده ما ایجاد کنند. نام، ایمیل، سن و کشور دانشجو را به عنوان آرگومان در نظر می گیرد.
آرایه attributes$ محافظت شده نحوه استفاده کلاینت از جهش را مشخص می کند. تابع عمومی ()type نوع جهش، شی student را برمی گرداند.
تابع ()args آرایه ای از آرگومان ها را برمی گرداند. این فیلدها برای هر ورودی جهش ایجاد خواهند شد. هر ورودی یک نام (نام ستون پایگاه داده) و یک نوع (داده) مانند int و String دارد. محدودیت Type::nonNull
تضمین می کند که مقادیر null در پایگاه داده وارد نمی شوند.
تابع Resolution کار نهایی وارد کردن مقادیر ارائه شده در پایگاه داده را انجام می دهد. در این تابع، نمونهای از مدل Student ایجاد میکنیم، مقادیر نام، ایمیل، سن و کشور را در برخی از متغیرها ذخیره میکنیم و مقادیر را با استفاده از (student->save$
) در پایگاه داده خود ذخیره میکنیم.
در مرحله بعد، برای به روز رسانی ورودی های دانشجو در پایگاه داده ما، یک فایل به نام UpdateStudentMutation.php
در فهرست مسیرها ایجاد کنید و کد زیر را اضافه کنید:
<?php
namespace App\graphql\Mutations;
use App\Student;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class UpdateStudentMutation extends Mutation
{
protected $attributes = [
"name" => "updateStudent",
];
public function type(): Type
{
return GraphQL::type("Student");
}
public function args(): array
{
return [
'name' => [
'name' => 'name',
'type' => Type::nonNull(Type::string())
],
'email' => [
'name' => 'email',
'type' => Type::nonNull(Type::string())
],
'age' => [
'name' => 'age',
'type' => Type::nonNull(Type::int())
],
'country' => [
'name' => 'country',
'type' => Type::nonNull(Type::string())
]
];
}
public function resolve($root, $args)
{
$student = Student::findOrFail($args["id"]);
$student->fill($args);
$student->save();
return $student;
}
}
کد CreateStudentMutation
بسیار شبیه به کد UpdateStudentMutation است. تنها تفاوت در تابع حل است، جایی که ما دانشجو خاص را برای به روز رسانی جستجو می کنیم. با Student::findOrFail($args["id"])
، شناسه دانشجویی ارائه شده توسط یک برنامه کلاینت را می گیریم و آن را در پایگاه داده جستجو می کنیم. با تابع fill، تمام داده های ردیف شناسه ارائه شده را با داده های جدید ارائه شده جایگزین می کنیم. سپس داده های جدید را در پایگاه داده ذخیره می کنیم.
برای حذف دانشجو از پایگاه داده، فایلی به نام DeleteStudentMutation.php
در فهرست مسیرها ایجاد کنید و کد زیر را اضافه کنید:
<?php
namespace App\graphql\Mutations;
use App\Student;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class DeleteStudentMutation extends Mutation
{
protected $attributes = [
"name" => "deleteStudent",
"description" => "Delete a student",
];
public function type(): Type
{
return Type::boolean();
}
public function args(): array
{
return [
"id" => [
"name" => "id",
"type" => Type::int(),
"rules" => ["required"],
],
];
}
public function resolve($root, $args)
{
$student = Student::findOrFail($args["id"]);
return $student->delete() ? true : false;
}
}
برای حذف یک دانشجو از پایگاه داده خود، تنها چیزی که نیاز داریم یک شناسه است که از یک برنامه کلاینت دریافت می کنیم. "rules" => ["required
"] تضمین می کند که یک id ارائه شده است. با findOrFail
، شناسه را در پایگاه داده خود جستجو می کنیم و تابع ()delete
تمام داده های آن id را حذف می کند.
ثبت درخواست، جهش و نوع ما
آخرین مرحله ثبت نوع،کوئری و جهش هایی است که در فایل پیکربندی GraphQL، config/graphql.php ایجاد کردیم.
return [
...
'schemas' => [
'default' => [
'query' => [
'students' => App\GraphQL\Queries\StudentsQuery::class,
],
'mutation' => [
// Create a student
'createStudent' => App\GraphQL\Mutations\CreateStudentMutation::class,
// update student
'updateStudent' => App\GraphQL\Mutations\UpdateStudentMutation::class,
// delete a student
'deleteStudent' => App\GraphQL\Mutations\DeleteStudentMutation::class,
],
'middleware' => [],
'method' => ['get', 'post'],
],
],
'types' => [
'Student' => App\GraphQL\Types\StudentType::class,
],
...
]
نتیجه
در این مقاله، نحوه ایجاد یک API GraphQL با استفاده از لاراول و بسته rebing/graphql-laravel را یاد گرفتیم. ما همچنین یک مدل Student ایجاد کردهایم، پایگاه داده را با دادههای ساختگی پیوند دادهایم، یک اتصال پایگاه داده را راهاندازی کردهایم، سرور GraphQL را ایجاد کردهایم. اکنون می توانید API های GraphQL خود را با لاراول و پکیج graphql-laravel ایجاد کنید.