GraphQL - Laravel
A graphql egy alternatíva a rest api-k mellett. Graphql-ben egyetlen végpont van és egy speciális lekérdező nyelvvel tudunk adatokat lekérdezni vagy módosítani. Ebben a példában, laravel környezetben fogunk graphql-el dolgozni. Egy backend oldali megvalósítás fog készülni. |
|
Két részre bontjuk a graphql "parancsokat". Vannak a query-k és a mutációk. Előbbiekkel adatokat kérdezünk le, utóbbiakkal új adatot szúrunk be, módosítunk törlünk. Minden esetben egy json-t ad vissza válaszként. Tegyük fel a következő csomagokat: composer require mll-lab/laravel-graphql-playground composer require rebing/graphql-laravel Az application/config/graphql.php-ban vegyük fel a mutációkat és a query-ket. 'schemas' => [ 'default' => [ 'query' => [ App\GraphQL\Queries\UsersQuery::class, App\GraphQL\Queries\UserQuery::class, ], 'mutation' => [ 'newUser' => App\GraphQL\Mutations\CreateUserMutation::class, 'updateUser' => App\GraphQL\Mutations\UpdateUserMutation::class, 'deleteUser' => App\GraphQL\Mutations\DeleteUserMutation::class, ], 'types' => [ App\GraphQL\Types\UserType::class, ], 'middleware' => [], 'method' => ['get', 'post'], ], ], 'types' => [ App\GraphQL\Types\UserType::class, ], Vegyük fel a típust application/app/GraphQL/types/UserType.php <?php namespace App\GraphQL\Types; use App\Models\User; use App\GraphQL\Fields\FormattableDate; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Type as GraphQLType; use Rebing\GraphQL\Support\Facades\GraphQL; /** * Class UserType * @package App\GraphQL\Types */ class UserType extends GraphQLType { /** * @var string[] */ protected $attributes = [ 'name' => 'User', 'description' => 'User', 'model' => User::class, ]; /** * @return array */ public function fields(): array { return [ 'id' => [ 'type' => Type::int(), 'description' => 'The id of the user', ], 'email' => [ 'type' => Type::string(), 'description' => 'The email of user', 'resolve' => function ($root, $args) { return strtolower($root->email); }, 'rules' => ['required', 'email'] ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of user', ], 'dateOfBirth' => [ 'type' => Type::string(), 'description' => 'The dateofbirth of user' ], 'isActive' => [ 'type' => Type::boolean(), 'description' => 'True, if the queried user is active', ], 'createdAt' => new FormattableDate([ 'alias' => 'created_at', ]), 'updatedAt' => new FormattableDate([ 'alias' => 'updated_at', ]), 'phones' => [ 'type' => Type::listOf(GraphQL::type('UserPhones')), 'description' => 'user phones', ] ]; } } Vegyünk fel query-ket application/app/GraphQL/Queries/UsersQuery.php <?php namespace App\GraphQL\Queries; use App\GraphQL\Services\UserService; use App\GraphQL\Types\TagInput; use Rebing\GraphQL\Support\Facades\GraphQL; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Query; use App\GraphQL\Middleware; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Closure; /** * Class UsersQuery * @package App\GraphQL\Queries */ class UsersQuery extends Query { /** * @var UserService */ private UserService $userService; public function __construct(UserService $userService) { $this->userService = $userService; } /** * @var string[] */ protected $middleware = [ Middleware\ResolvePage::class, ]; /** * @var string[] */ protected $attributes = [ 'name' => 'users', 'description' => 'List of users with phones ' ]; /** * @return Type */ public function type(): Type { return GraphQL::paginate('User'); } /** * @return array[] */ public function args(): array { return [ 'limit' => [ 'name' => 'limit', 'type' => Type::int(), 'rules' => ['required'], 'description' => 'Limit of number', ], 'page' => [ 'name' => 'page', 'type' => Type::int(), 'rules' => ['required'], 'description' => 'Page of number', ], 'sortBy' => [ 'name' => 'sortBy', 'type' => Type::string(), 'rules' => ['required'], 'description' => 'Sort by of list params: ("id","name","email","dateOfBirth","isActive")', ], 'order' => [ 'name' => 'order', 'type' => Type::string(), 'rules' => ['required'], 'description' => 'Sort of list params: ("asc","desc")', ], 'phones' => [ 'type' => Type::listOf(new TagInput('UserPhones!')), 'description' => 'User phones', ] ]; } /** * @param $root * @param $args * @param $context * @param ResolveInfo $resolveInfo * @param Closure $getSelectFields * @return LengthAwarePaginator */ public function resolve($root, $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields): LengthAwarePaginator { return $this->userService->getAllPaginated($getSelectFields(), $args); } } Vegyünk fel mutációt user létrehozáshoz application/app/GraphQL/Mutation/CreateUserMutation.php <?php namespace App\GraphQL\Mutations; use App\Models\User; use App\GraphQL\Services\UserService; use Rebing\GraphQL\Support\Facades\GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Mutation; /** * Class NewUserMutation * @package App\GraphQL\Mutations */ class CreateUserMutation extends Mutation { /** * @var string[] */ protected $attributes = [ 'name' => 'newUser', 'description' => 'Create a new user with phone' ]; /** * @var UserService */ private UserService $userService; public function __construct(UserService $userService) { $this->userService = $userService; } /** * @return Type */ public function type(): Type { return GraphQL::type('User'); } /** * @return array[] */ public function args(): array { return [ 'name' => [ 'name' => 'name', 'type' => Type::nonNull(Type::string()), 'rules' => ['required'], 'description' => 'User name' ], 'email' => [ 'name' => 'email', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'email'], 'description' => 'User email' ], 'dateOfBirth' => [ 'name' => 'dateOfBirth', 'type' => Type::nonNull(Type::string()), 'rules' => ['required'], 'description' => 'User date of birth' ], 'isActive' => [ 'name' => 'isActive', 'type' => Type::nonNull(Type::boolean()), 'rules' => ['required'], 'description' => 'Active user' ], 'phoneNumber' => [ 'name' => 'phoneNumber', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'regex:/^([0-9\s\/-]{8,13})$/', 'min:7', 'max:12'], 'description' => 'User phone number' ], ]; } /** * @param $rootValue * @param array $args * @return User */ public function resolve($rootValue, array $args): User { return $this->userService->create($args); } } Vegyünk fel mutációt user módosításhoz application/app/GraphQL/Mutation/UpdateUserMutation.php <?php namespace App\GraphQL\Mutations; use App\GraphQL\Services\UserService; use Closure; use GraphQL\Error\Error; use GraphQL\Type\Definition\ResolveInfo; use Rebing\GraphQL\Support\Facades\GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Mutation; use App\Models\User; /** * Class UpdateUserMutation * @package App\GraphQL\Mutations */ class UpdateUserMutation extends Mutation { /** * @var string[] */ protected $attributes = [ 'name' => 'updateUser', 'description' => 'Update user data' ]; /** * @var UserService */ private UserService $userService; public function __construct(UserService $userService) { $this->userService = $userService; } /** * @return Type */ public function type(): Type { return GraphQL::type('User'); } /** * @return array[] */ public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::nonNull(Type::int()), 'rules' => ['required'], 'description' => 'User id' ], 'name' => [ 'name' => 'name', 'type' => Type::nonNull(Type::string()), 'rules' => ['required'], 'description' => 'User name' ], 'email' => [ 'name' => 'email', 'type' => Type::nonNull(Type::string()), 'rules' => ['required','email'], 'description' => 'User email' ], 'dateOfBirth' => [ 'name' => 'dateOfBirth', 'type' => Type::nonNull(Type::string()), 'rules' => ['required'], 'description' => 'User date of birth' ], 'isActive' => [ 'name' => 'isActive', 'type' => Type::nonNull(Type::boolean()), 'rules' => ['required'], 'description' => 'Active user (true,false)' ], ]; } /** * @param $rootValue * @param array $args * @return User * @throws Error */ public function resolve($rootValue, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields): User { return $this->userService->update($args); } } Vegyünk fel mutációt user törléshez application/app/GraphQL/Mutation/DeleteUserMutation.php <?php namespace App\GraphQL\Mutations; use App\GraphQL\Services\UserPhonesService; use GraphQL\Error\Error; use Rebing\GraphQL\Support\Facades\GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Mutation; use App\Models\User; use App\GraphQL\Services\UserService; /** * Class DeleteUserMutation * @package App\GraphQL\Mutations */ class DeleteUserMutation extends Mutation { /** * @var string[] */ protected $attributes = [ 'name' => 'deleteUser', 'description' => 'Delete user' ]; /** * @var UserService */ private UserService $userService; /** * @var UserPhonesService */ private UserPhonesService $userPhonesService; public function __construct(UserService $userService, UserPhonesService $userPhonesService) { $this->userService = $userService; $this->userPhonesService = $userPhonesService; } /** * @return Type */ public function type(): Type { return GraphQL::type('User'); } /** * @return array[] */ public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::nonNull(Type::int()), 'rules' => ['required'], 'description' => 'User id' ], ]; } /** * @param $rootValue * @param array $args * @return User * @throws Error */ public function resolve($rootValue, array $args): User { return $this->userService->destroy($args['id']); } } A user model nem tartalmaz semmi különbséget a rest api-hoz képest. A user service sem tartalmaz semmi izgalmasat, meghívjuk a repository-t, vagy elmentjük az adatokat stb. Kipróbálni a végpontot a következő url-en tudjuk: http://localhost/graphql-playground Pár példa a végpont használatára: // Lista lekérdezése query { users(limit: 2 page: 4, order: "desc", sortBy: "name") { data { id, name }, total, per_page } } // Új felhasználó mutation{ newUser( name: "My user" email: "test@example.com" dateOfBirth: "1973-08-08" isActive: true phoneNumber: "20/111-11111" ){ name email } } // Felhasználó módosítása mutation { updateUser( id: 11 name: "Test User" ){ name email dateOfBirth isActive } } // Felhasználó törlése mutation { deleteUser( id: 12 ){ name email dateOfBirth isActive } } Olvasnivaló: https://github.com/rebing/graphql-laravel https://github.com/supliu/laravel-graphql https://lighthouse-php.com/tutorial/#the-models https://packagist.org/packages/nuwave/lighthouse https://www.toptal.com/graphql/laravel-graphql-server-tutorial https://github.com/driesvints/graphql-shop https://mobiosolutions.com/steps-to-build-graphql-server-from-scratch-in-laravel/ |
2021.05.08. |
Figyelem! Az itt olvasható leírások, nem teljesek és nem biztos, hogy pontosak. Nem
frissülnek folyamatosan, ezért nem mindegyik használható az aktuális verziójú rendszerekben. Mindenki saját
felelősségére használja az itt található ötleteket. Az esetleges károkért nem vállalunk felelősséget.