GraphQL یک زبان کوئری نویسی برای کار با API ها و همچنین یک محیط اجرایی سمت سرور برای اجرای کوئری ها توسط type system هایی است که شما تعریف کرده اید.
GraphQL به هیچ نوع پایگاه داده یا موتور ذخیره سازی وابسته نیست و بجای آن از همان کدهایی که نوشته اید استفاده می کند.
GraphQL ابزاری است که باعث افزایش انعطاف پذیری فراخوانی API ها می شود و ما می توانیم از یک زبان کوئری همانند زبان کوئری که در هنگام کار با دیتابیس استفاده می کنیم، برای دسترسی به APIها استفاده کنیم. این یک قابلیت خیلی قدرتمند برای ساخت API های پیچیده است.
GraphQL یک رابط کاربری برای کمک به نوشتن کوئری ارائه کرده که از قابلیت تکمیل خودکار کدها برخوردار است و در هنگام نوشتن کوئری ها کمک زیادی به ما می کند.
برای درک مفهوم GraphQL تصویر زیر را مشاهده کنید، همان طور که می بینید GraphQL درخارج از لایه منطق تجاری برنامه اجرا می شود.
مطالعه موردی: یک مثال درباره API لیست محصولات و لیست کاربران
ابتدا با دستور زیر آخرین نسخه لاراول را نصب کنید.
# run in terminal composer global require "laravel/installer" laravel new laravel-graphql
پکیج graphql-laravel را توسط کامپوزر نصب کنید، این پکیج قابلیت های زیادی برای یکپارچه کردن لاراول با GraphQL دارد.
جدول مدل های product ،user_profile ،product_image را همانند زیر ایجاد کنید و روابط بین آنها را هم مانند تصویر زیر تعریف کنید.
Query در GraphQL همانند تعریف مسیر endpoint در Restful Api ها است.
Query تنها برای دریافت داده ها استفاده می شود و برای انجام عملیات های create، update و delete از Mutationها استفاده می کنیم.
Typeها برای تعریف نوع فیلدهای query استفاده می شود. Typeها به ما کمک می کنند تا نوع فیلدهای نتایجی که از اجرای یک کوئری بدست می آید را فرمت بندی کنیم. برای مثال نوع های بولین، رشته ای، اعشاری و اعداد صحیح و ... . همچنین می توانیم نوع های سفارشی تعریف کنیم.
تصویر زیر ساختار دایرکتوری مربوط به query و Typeها را نمایش می دهد.
در زیر کد کامل userQuery.php و usersType.php را آورده ایم.
<?php namespace App\GraphQL\Query; use App\User; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; use Rebing\GraphQL\Support\SelectFields; class UsersQuery extends Query { protected $attributes = [ 'name' => 'Users Query', 'description' => 'A query of users' ]; public function type() { // result of query with pagination laravel return GraphQL::paginate('users'); } // arguments to filter query public function args() { return [ 'id' => [ 'name' => 'id', 'type' => Type::int() ], 'email' => [ 'name' => 'email', 'type' => Type::string() ] ]; } public function resolve($root, $args, SelectFields $fields) { $where = function ($query) use ($args) { if (isset($args['id'])) { $query->where('id',$args['id']); } if (isset($args['email'])) { $query->where('email',$args['email']); } }; $user = User::with(array_keys($fields->getRelations())) ->where($where) ->select($fields->getSelect()) ->paginate(); return $user; } }
<?php namespace App\GraphQL\Type; use App\User; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Type as GraphQLType; class UsersType extends GraphQLType { protected $attributes = [ 'name' => 'Users', 'description' => 'A type', 'model' => User::class, // define model for users type ]; // define field of type public function fields() { return [ 'id' => [ 'type' => Type::nonNull(Type::int()), 'description' => 'The id of the user' ], 'email' => [ 'type' => Type::string(), 'description' => 'The email of user' ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of the user' ], // field relation to model user_profiles 'user_profiles' => [ 'type' => GraphQL::type('user_profiles'), 'description' => 'The profile of the user' ] ]; } protected function resolveEmailField($root, $args) { return strtolower($root->email); } }
بعد از ایجاد query و Typeها، باید آنها را در فایل config/graphql.php ثبت کنیم.
<?php use App\GraphQL\Query\ProductsQuery; use App\GraphQL\Query\UsersQuery; use App\GraphQL\Type\ProductImagesType; use App\GraphQL\Type\ProductsType; use App\GraphQL\Type\UserProfilesType; use App\GraphQL\Type\UsersType; return [ 'prefix' => 'graphql', 'routes' => 'query/{graphql_schema?}', 'controllers' => \Rebing\GraphQL\GraphQLController::class . '@query', 'middleware' => [], 'default_schema' => 'default', // register query 'schemas' => [ 'default' => [ 'query' => [ 'users' => UsersQuery::class, 'products' => ProductsQuery::class, ], 'mutation' => [ ], 'middleware' => [] ], ], // register types 'types' => [ 'product_images' => ProductImagesType::class, 'products' => ProductsType::class, 'user_profiles' => UserProfilesType::class, 'users' => UsersType::class, ], 'error_formatter' => ['\Rebing\GraphQL\GraphQL', 'formatError'], 'params_key' => 'params' ];
ما می توانیم به راحتی از GraphQL برای دریافت نتایج از APIها استفاده کنیم.
چون هنگامی که شروع به کدنویسی کنیم قابلیت تکمیل خودکار کد در GraphQL به ما در کدنویسی کمک زیادی می کند و همچنین توسط برنامه postman می توانیم به راحتی APIها را فراخوانی کنیم. در زیر مثالی از تکمیل خودکار کد را می بینید.
و نتیجه کدهای بالا را در تصویر زیر می بینید:
در این قسمت درباره Mutation و اعتبارسنجی Api توسط GraphQL توضیح خواهم داد.
GraphQL یک ابزار عالی برای ساخت راحت و دینامیک Api ها است و می توانید از این ابزار در برنامه های سمت کلاینتی که با ReactJs/ReactNative نوشته اید، استفاده کنید. همچنین کتابخانه های زیادی برای پشتیبانی از GraphQL ساخته شده اند.
Mutation ها در حقیقت یک نوع (Type) برای درج داده در دیتابیس یا تغییر داده هایی که قبلاً در دیتابیس درج شده است.
در بخش قبلی دیدید که یک مدل به نام user داشتیم، حال می توانیم به راحتی دو کلاس Mutation، یکی برای افزودن کاربر جدید یعنی کلاس NewUserMutation.php و دیگری برای بروزرسانی کلاس user یعنی updateUserMutation.php ایجاد کنیم.
در فایل NewUserMutation.php تابعی به نام args داریم که در آن نام فیلد ورودی و نوع فیلدهای ورودی مان را تعریف می کنیم: Type::nonNull یعنی پر کردن این فیلد اجباری است.
<?php /** * Created by PhpStorm. * User: ardani * Date: 8/4/17 * Time: 10:02 AM */ namespace App\GraphQL\Mutation; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; use App\User; class NewUserMutation extends Mutation { protected $attributes = [ 'name' => 'NewUser' ]; public function type() { return GraphQL::type('users'); } public function args() { return [ 'name' => [ 'name' => 'name', 'type' => Type::nonNull(Type::string()) ], 'email' => [ 'name' => 'email', 'type' => Type::nonNull(Type::string()) ], 'password' => [ 'name' => 'password', 'type' => Type::nonNull(Type::string()) ], 'first_name' => [ 'name' => 'first_name', 'type' => Type::nonNull(Type::string()) ], 'last_name' => [ 'name' => 'last_name', 'type' => Type::string() ], 'avatar' => [ 'name' => 'avatar', 'type' => Type::string() ] ]; } public function resolve($root, $args) { $args['password'] = bcrypt($args['password']); $user = User::create($args); if (!$user) { return null; } $user->user_profiles()->create($args); return $user; } }
updateUserMutation.php برای بروزرسانی داده های کاربر استفاده می شود. تمام عملیات های درج و بروزرسانی هنوز هم توسط Eloquent انجام می شود و برای کوئری های پیچیده می توانید از Query Builder استفاده کنید.
<?php /** * Created by PhpStorm. * User: ardani * Date: 8/4/17 * Time: 10:02 AM */ namespace App\GraphQL\Mutation; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; use App\User; class UpdateUserMutation extends Mutation { protected $attributes = [ 'name' => 'UpdateUser' ]; public function type() { return GraphQL::type('users'); } public function args() { return [ 'id' => [ 'name' => 'id', 'type' => Type::nonNull(Type::int()) ], 'name' => [ 'name' => 'name', 'type' => Type::nonNull(Type::string()) ] ]; } public function resolve($root, $args) { $user = User::find($args['id']); if (!$user) { return null; } $user->name = $args['name']; $user->save(); return $user; } }
کلاس graphql.php که در فولدر config قرار گرفته را باز کنید و در قسمت Mutation، کلاس های Mutationیی که در مرحله قبل ساختید را به آن اضافه کنید.
بعد از اضافه کردن کلاس Mutation آدرس http://127.0.0.1:8000/graphql-ui را در مرورگر باز کنید. با انجام این کار جزئیات Mutationها نمایش داده می شود.
Json Web Token به اختصار JWT، استاندارد متن باز (RFC7519) و یک روش کامل است که انتقال امن اطلاعات بین بخش های مختلف را در یک شیء json تعریف می کند.
این اطلاعات می تواند به راحتی اعتبارسنجی شود، چون بصورت دیجیتالی امضا می شوند.
JWT ها توسط یک کلید محرمانه ( با الگوریتم HMAC) یا یک کلید خصوصی/ عمومی که با الگوریتم RSA رمزنگاری شده، امضا می شود.
JWT ابزار مفیدی برای احراز هویت بدون حالت APIها است و توسط پکیج زیر به راحتی با لاراول یکپارچه می شود.
این پکیج را می توانید از این لینک دریافت کنید
برای آموزش نصب این پکیج این لینک را دنبال کنید.
ما از پارامتر Authorization:Bearer yourtokenhere در هدر تمام درخواست هایی که به GraphQL ارسال می شود استفاده می کنیم که در این پارامتر عبارت yourtokenhere با توکن (Token) کاربر که توسط پکیج jwt احراز هویت شده است، ایجاد می گردد.
ابتدا یک کنترلر برای احراز هویت ایجاد می کنیم.
<?php /** * Created by PhpStorm. * User: ardani * Date: 8/4/17 * Time: 11:18 AM */ namespace App\Http\Controllers; use Illuminate\Http\Request; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\JWTAuth; class AuthenticateController extends Controller { private $jwt; public function __construct(JWTAuth $jwt) { $this->jwt = $jwt; } public function authenticate(Request $request) { // grab credentials from the request $credentials = $request->only('email', 'password'); try { // attempt to verify the credentials and create a token for the user if (! $token = $this->jwt->attempt($credentials)) { return response()->json(['error' => 'invalid_credentials'], 401); } } catch (JWTException $e) { // something went wrong whilst attempting to encode the token return response()->json(['error' => 'could_not_create_token'], 500); } // all good so return the token return response()->json(compact('token')); } }
سپس کد زیر که برای login استفاده می شود را به فایل web.php اضافه کنید.
Route::post(‘graphql/login’, ‘AuthenticateController@authenticate’);
برای مثال ما از کوئری myProfile برای دسترسی به myProfile ایی که توسط JWT احراز هویت شود، استفاده می کنیم. ابتدا یک فایل به نام myProfileQuery.php ایجاد می کنیم.
<?php namespace App\GraphQL\Query; use App\User; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; use Rebing\GraphQL\Support\SelectFields; use Tymon\JWTAuth\Facades\JWTAuth; class MyProfileQuery extends Query { private $auth; protected $attributes = [ 'name' => 'My Profile Query', 'description' => 'My Profile Information' ]; public function authorize(array $args) { try { $this->auth = JWTAuth::parseToken()->authenticate(); } catch (\Exception $e) { $this->auth = null; } return (boolean) $this->auth; } public function type() { return GraphQL::type('myprofile'); } public function resolve($root, $args, SelectFields $fields) { $user = User::with(array_keys($fields->getRelations())) ->where('id', $this->auth->id) ->select($fields->getSelect())->first(); return $user; } }
عمل احراز هویت در متد authorize انجام می گیرد و ابتدا باید احراز هویت JWT را بررسی کنیم. در صورتی که هویت معتبر بود، ادامه فرآیند را انجام می دهیم، اما در صورتی که عمل احراز هویت ناموفق بود، پیام unauthorized را به عنوان نتیجه GraphQL بر می گردانیم.
یادتان باشد که حتماً این فایل کوئری را به config > graphql.php اضافه کنید.
سورس کامل برنامه را از اینجا دریافت کنید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
Route::get('user/{name?}', function ($name = null) { return $name; });
برای استفاده از API نیز به نظری که دوست دیگر ما (ali) پرسیده است مراجعه کنید.در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.