라라벨로 GraphQL 서버 구축하기

게시 됨: 2022-03-11

아직 익숙하지 않은 경우를 대비하여 GraphQL은 API와 상호 작용하는 데 사용되는 쿼리 언어로 REST와 같은 대체 아키텍처에 비해 몇 가지 이점을 제공합니다. GraphQL은 모바일 및 단일 페이지 애플리케이션의 끝점 역할을 할 때 매우 편리합니다. GraphQL을 사용하면 요청에서 중첩 및 관련 데이터를 비교적 쉽게 쿼리할 수 있으므로 개발자가 서버로의 단일 왕복으로 필요한 정확한 데이터를 얻을 수 있습니다.

Laravel은 인기 있고 독단적인 PHP 웹 프레임워크입니다. 애플리케이션을 빠르게 시작하고 실행할 수 있는 수많은 내장 도구를 제공하지만, 개발자가 원하는 경우 자체 구현을 Laravel의 내장 인터페이스로 교체할 수도 있습니다.

GraphQL과 Laravel을 둘러싼 커뮤니티는 오픈 소스 이후 극적으로 성장했지만 이 두 기술을 함께 사용하는 방법을 설명하는 문서는 여전히 다소 부족합니다.

따라서 이 튜토리얼에서는 Laravel을 사용하여 자신만의 GraphQL 서버를 만드는 방법을 보여 드리겠습니다.

프로젝트 개요

GraphQL 서버 개요 그림

시작하기 전에 빌드하려는 프로젝트에 익숙해져야 합니다. 이를 위해 리소스를 정의하고 나중에 API를 제공하는 데 사용할 GraphQL 스키마를 생성합니다.

프로젝트 리소스

우리의 응용 프로그램은 ArticlesUsers 의 두 가지 리소스로 구성됩니다. 이러한 리소스는 GraphQL 스키마에서 객체 유형으로 정의됩니다.

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

스키마를 보면 두 객체 사이에 일대다 관계가 있음을 알 수 있습니다. 사용자는 많은 기사를 작성할 수 있으며 기사에는 작성자(사용자)가 할당되어 있습니다.

이제 객체 유형이 정의되었으므로 데이터를 생성하고 쿼리하는 방법이 필요하므로 쿼리 및 돌연변이 객체를 정의해 보겠습니다.

 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 }

Laravel 프로젝트 설정하기

GraphQL 스키마를 정의했으므로 이제 Laravel 프로젝트를 시작하고 실행해 보겠습니다. Composer 프로젝트를 통해 새 Laravel을 만드는 것으로 시작하겠습니다.

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

모든 것이 제대로 작동하는지 확인하기 위해 서버를 부팅하고 Laravel의 기본 페이지가 표시되는지 확인합니다.

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

데이터베이스 모델 및 마이그레이션

이 기사의 목적을 위해 우리는 SQLite를 사용할 것입니다. 따라서 기본 .env 파일을 다음과 같이 변경해 보겠습니다.

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

다음으로 데이터베이스 파일을 생성해 보겠습니다.

 $ touch ./database/database.sqlite

Laravel은 사용자 모델과 몇 가지 기본 마이그레이션 파일과 함께 제공됩니다. Laravel에서 제공한 CreateUsersTable 마이그레이션 파일에 api_token 열을 빠르게 추가해 보겠습니다.

 /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'); } }

나중에 승인을 받으면 이 추가 열에 대해 다시 설명하겠습니다. 이제 기사 모델과 마이그레이션 파일을 만들어 관련 테이블을 생성해 보겠습니다.

 $ php artisan make:model Article -m

참고: -m 옵션은 새로 생성된 기사 모델에 대한 마이그레이션 파일을 생성합니다.

생성된 마이그레이션 파일을 몇 가지 조정해 보겠습니다.

 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'); } }

우리는 users 테이블의 id 를 가리키는 외래 키와 GraphQL 스키마에서 정의한 titlecontent 열을 추가했습니다.

이제 마이그레이션 파일이 정의되었으므로 데이터베이스에 대해 실행해 보겠습니다.

 $ php artisan migrate

다음으로 필요한 관계를 정의하여 모델을 업데이트하겠습니다.

 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); } }

데이터베이스 시딩

이제 모델과 마이그레이션이 설정되었으므로 데이터베이스를 시드(seed)해 보겠습니다. articlesusers 테이블에 대한 몇 가지 시드 클래스를 만드는 것으로 시작하겠습니다.

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

다음으로, 일부 더미 데이터를 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); } }

마지막으로 데이터베이스 시더를 실행하여 일부 데이터를 데이터베이스에 가져오도록 하겠습니다.

 $ php artisan db:seed

Laravel Lighthouse 및 GraphQL 서버

이제 데이터베이스와 모델이 설정되었으므로 GraphQL 서버 구축을 시작할 때입니다. 현재 Laravel에 사용할 수 있는 여러 솔루션이 있지만 이 기사에서는 Lighthouse를 사용할 것입니다.

Lighthouse는 제가 몇 년 전에 만든 패키지로 최근에 주변 커뮤니티에서 놀라운 지원을 받았습니다. 이를 통해 개발자는 상용구를 거의 사용하지 않고 Laravel을 사용하여 GraphQL 서버를 빠르게 설정할 수 있으며 개발자가 거의 모든 프로젝트의 요구 사항에 맞게 사용자 정의할 수 있을 만큼 충분히 유연합니다.

Laravel Lighthouse 및 GraphQL 서버 그림

패키지를 프로젝트로 가져와 시작하겠습니다.

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

다음으로 Lighthouse의 구성 파일을 게시해 보겠습니다.

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

참고: 단순히 --tag=config 옵션을 제거하여 Lighthouse의 기본 스키마 파일을 게시하도록 선택할 수도 있습니다. 그러나 이 기사의 목적을 위해 스키마 파일을 처음부터 만들 것입니다.

config/lighthouse.php 파일을 살펴보면 스키마 파일을 Lighthouse에 등록하는 데 사용되는 설정을 확인할 수 있습니다.

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

이제 스키마 파일을 만들고 사용자 개체 유형과 쿼리를 설정해 보겠습니다.

 $ 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 }

스키마 지시문이라는 식별자를 추가했다는 점을 제외하면 스키마가 이전에 정의한 것과 유사하다는 것을 알 수 있습니다.

잠시 시간을 내어 정의된 스키마를 분석해 보겠습니다. 첫 번째 정의는 App\User 웅변 모델과 관련된 User 라는 객체 유형 입니다. 우리는 User 모델에서 쿼리할 수 있는 필드로 id , nameemail 을 정의했습니다. 또는 이는 password , created_atupdated_at 열이 API에서 쿼리할 수 없는 필드임을 의미합니다.

다음으로 API에 대한 진입점이며 데이터를 쿼리하는 데 사용할 수 있는 Query 유형이 있습니다. 첫 번째 필드는 User 개체 유형의 배열을 반환하는 users 필드입니다. @all 지시문은 Lighthouse가 User 모델을 사용하여 Eloquent 쿼리를 실행하고 모든 결과를 얻도록 지시합니다. 이것은 다음을 실행하는 것과 같습니다.

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

참고: Lighthouse는 구성 파일에 정의된 namespaces 옵션 때문에 \App\User 네임스페이스에서 모델을 찾는 것을 알고 있습니다.

쿼리 유형에서 두 번째로 정의된 필드는 id 를 인수로 사용하고 단일 User 개체 유형을 반환하는 call user 입니다. 또한 Lighthouse가 자동으로 쿼리를 작성하고 단일 User 모델을 반환하는 데 도움이 되는 두 가지 지시문을 추가했습니다. @eq 지시문은 Lighthouse에 id 열에 where를 추가하도록 지시하고 @find 지시문은 Lighthouse에 단일 결과를 반환하도록 지시합니다. Laravel의 쿼리 빌더를 사용하여 이 쿼리를 작성하려면 다음과 같이 보일 것입니다.

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

GraphQL API 쿼리

이제 Lighthouse가 스키마를 사용하여 쿼리를 생성하는 방법에 대한 약간의 통찰력을 얻었으므로 서버를 실행하고 데이터 쿼리를 시작하겠습니다. 서버를 실행하여 시작하겠습니다.

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

GraphQL 끝점을 쿼리하려면 터미널 또는 Postman과 같은 표준 클라이언트에서 cURL 명령을 실행할 수 있습니다. 그러나 GraphQL의 모든 이점(예: 자동 완성, 오류 강조 표시, 문서화 등)을 얻으려면 GraphQL Playground(릴리스 다운로드는 여기)를 사용합니다.

Playground를 시작할 때 "URL 끝점" 탭을 클릭하고 http://localhost:8000/graphql을 입력하여 GraphQL Playground가 우리 서버를 가리키도록 합니다. 편집기의 왼쪽에서 데이터를 쿼리할 수 있으므로 데이터베이스를 시드한 모든 사용자를 묻는 것부터 시작하겠습니다.

 { users { id email name } }

IDE 중간에 있는 재생 버튼을 누르면(또는 Ctrl+Enter 클릭) 오른쪽에 다음과 같은 서버의 JSON 출력이 표시됩니다.

 { "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" }, ... ] } }

참고: Faker를 사용하여 데이터베이스를 시드했기 때문에 emailname 필드의 데이터가 다릅니다.

이제 단일 사용자에 대해 쿼리해 보겠습니다.

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

단일 사용자에 대해 다음과 같은 출력을 얻을 수 있습니다.

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

이와 같은 데이터 쿼리는 시작하는 것이 좋지만 모든 데이터를 쿼리하려는 프로젝트에 있을 가능성은 거의 없으므로 페이지 매김을 추가해 보겠습니다. Lighthouse의 광범위한 내장 지시문을 @paginate 지시문을 쉽게 사용할 수 있으므로 스키마의 쿼리 개체를 다음과 같이 업데이트하겠습니다.

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

GraphQL Playground( Ctrl/Cmd + R )를 다시 로드하고 users 쿼리를 다시 시도하면 Cannot query field "id" on type "UserPaginator" 없다는 오류 메시지가 표시됩니다. 그래서 무슨 일이 일어났습니까? 무대 뒤에서 Lighthouse는 페이지가 매겨진 결과 집합을 얻기 위해 스키마를 조작하고 users 필드의 반환 유형을 변경하여 그렇게 합니다.

GraphQL Playground의 "Docs" 탭에서 스키마를 검사하여 자세히 살펴보겠습니다. users 필드를 살펴보면 사용자 배열과 Lighthouse 정의 PaginatorInfo 유형을 반환하는 UserPaginator 를 반환합니다.

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

라라벨의 내장된 페이지 매김에 익숙 PaginatorInfo 유형에서 사용 가능한 필드가 매우 친숙하게 보일 것입니다. 따라서 두 명의 사용자를 쿼리하고 시스템의 총 사용자 수를 얻고 순환할 페이지가 더 있는지 확인하려면 다음 쿼리를 보냅니다.

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

그러면 다음과 같은 응답이 제공됩니다.

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

관계

일반적으로 애플리케이션을 개발할 때 많은 데이터가 관련됩니다. 우리의 경우 User 는 많은 Articles 를 작성할 수 있으므로 해당 관계를 사용자 유형에 추가하고 Article 유형을 정의하겠습니다.

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

여기서 우리는 Lighthouse에 User 모델이 Article 모델과 \Illuminate\Database\Eloquent\Relations\HasMany 관계가 있음을 알려주는 다른 Lighthouse 제공 스키마 지시문 @hasMany 를 사용하고 있습니다.

이제 새로 정의된 관계를 쿼리해 보겠습니다.

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

그러면 다음과 같은 응답이 제공됩니다.

 { "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." } ] } } }

마지막으로 관계를 반대로 하고 Lighthouse의 @belongsTo 스키마 지시문을 사용하고 Query 를 업데이트하여 Article 객체 유형에 author 관계를 추가해 보겠습니다.

 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 }

@belongsTo 지시문에 선택적 relation 인수를 추가했음을 알 수 있습니다. 이렇게 하면 Lighthouse가 Articles 모델의 user 관계를 사용하고 이를 author 필드에 할당하도록 지시합니다.

이제 기사 목록을 쿼리하고 관련 작성자를 알아보겠습니다.

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

그리고 서버에서 다음을 가져와야 합니다.

 { "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]" } } ] } } }

GraphQL 돌연변이

이제 데이터를 쿼리할 수 있으므로 몇 가지 새로운 사용자와 기사를 만들기 위해 몇 가지 변형을 만들어 보겠습니다. 사용자 모델부터 시작하겠습니다.

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

이제 이 스키마 정의를 분해해 보겠습니다. 세 개의 인수( name , emailpassword )를 사용하는 createUser 라는 변형을 만들었습니다. emailpassword 인수 모두에 @rules 지시문을 적용했습니다. 이것은 Laravel이 컨트롤러에 제공하는 유효성 검사 로직과 유사하기 때문에 다소 친숙해 보일 수 있습니다.

다음으로 password 필드에 @bcrypt 지시문을 첨부했습니다. 이렇게 하면 새로 생성된 모델에 암호가 전달되기 전에 암호가 암호화됩니다.

마지막으로 새 모델을 만드는 데 도움이 되도록 Lighthouse는 정의한 인수를 사용하여 새 모델을 만드는 @create 스키마 지시문을 제공합니다. 컨트롤러에서 동일한 논리를 수행하면 다음과 같습니다.

 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]); } }

이제 createUser 돌연변이 필드가 설정되었으므로 다음을 사용하여 GraphQL Playground에서 실행해 보겠습니다.

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

다음과 같은 결과가 나와야 합니다.

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

GraphQL 인증 및 권한 부여

Article 모델에 user_id 를 추가해야 하므로 지금이 GraphQL/Lighthouse에서 인증 및 권한 부여를 검토할 좋은 시간입니다.

이미지 대체 텍스트

사용자를 인증하려면 api_token 을 제공해야 하므로 이를 처리할 변형을 만들고 @field 지시문을 추가하여 Lighthouse가 논리를 처리할 사용자 지정 확인자를 가리키도록 하겠습니다. resolver 인수를 사용하여 Laravel에서 컨트롤러를 정의하는 것과 동일한 패턴으로 resolver를 설정합니다.

아래에 정의된 @field 지시문을 사용하면 login 변형이 실행될 때 Lighthouse에 App\GraphQL\Mutations\AuthMutator 클래스에서 createToken 메서드를 사용합니다.

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

참고: 여기에 전체 네임스페이스를 포함할 필요는 없습니다. lighthouse.php 구성 파일에서 이미 App\\GraphQL\\Mutations 로 설정된 변형에 대해 정의된 네임스페이스가 있는 것을 볼 수 있습니다. 그러나 원하는 경우 전체 네임스페이스를 사용할 수 있습니다.

Lighthouse의 생성기를 사용하여 새로운 mutator 클래스를 생성해 보겠습니다.

 $ php artisan lighthouse:mutation AuthMutator

다음으로 리졸버 기능을 다음과 같이 업데이트해 보겠습니다.

 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; } }

이제 리졸버를 설정했으므로 이를 테스트하고 GraphQL Playground에서 다음 변형을 사용하여 API 토큰을 얻으려고 합니다.

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

다음과 같이 토큰을 다시 보내야 합니다.

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

참고: 나중에 사용할 수 있도록 로그인 변형에서 반환된 토큰을 복사해야 합니다.

다음으로, 로직이 작동하는지 확인하기 위해 인증된 사용자를 반환할 쿼리 필드를 추가해 보겠습니다. me 라는 필드를 추가하고 Lighthouse의 @auth 지시문을 사용하여 현재 인증된 사용자를 반환합니다. 또한 guard 인수를 api 와 동일하게 설정합니다. 이것이 사용자를 인증하는 방법이기 때문입니다.

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

이제 쿼리를 실행해 보겠습니다. GraphQL Playground에서 하단의 "Http Headers" 탭을 더블 클릭하여 요청 헤더를 설정할 수 있습니다. JSON 객체가 있는 헤더를 추가하므로 각 요청에 전달자 토큰을 추가하려면 다음을 추가합니다.

 { "Authorization": "Bearer VJCz1DCpmdvB9WatqvWbXBP2RN8geZQlrQatUnWIBJCdbAyTl3UsdOuio3VE" }

참고: Bearer 토큰을 로그인 쿼리를 실행할 때 받은 토큰으로 바꾸십시오.

이제 me 쿼리를 실행해 보겠습니다.

 { me { email articles { id title } } }

다음과 같은 출력을 얻어야 합니다.

 { "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." } ] } } }

미들웨어

이제 인증이 제대로 작동한다는 것을 알았으므로 현재 인증된 사용자를 사용하여 기사를 생성하는 마지막 변형을 만들어 보겠습니다. @field 지시문을 사용하여 Lighthouse가 해석기를 가리키도록 하고 사용자가 로그인되어 있는지 확인하기 위해 @middleware 지시문도 포함합니다.

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

먼저 돌연변이 클래스를 생성해 보겠습니다.

 $ php artisan lighthouse:mutation ArticleMutator

다음으로 다음 논리로 mutator를 업데이트해 보겠습니다.

 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; } }

참고: 기본 resolve 함수의 이름을 create 로 변경했습니다. 모든 리졸버에 대해 새 클래스를 만들 필요는 없습니다. 대신, 더 합리적이면 논리를 함께 그룹화할 수 있습니다.

마지막으로 새로운 변형을 실행하고 출력을 확인하겠습니다. "HTTP 헤더" 탭에서 이전 쿼리의 Authorization 헤더를 유지해야 합니다.

 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 } } }

다음과 같은 결과가 나와야 합니다.

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

마무리

요약하자면, Lighthouse를 활용하여 Laravel 프로젝트를 위한 GraphQL 서버를 만들었습니다. 내장된 스키마 지시문을 사용하고 쿼리 및 변형을 생성하고 권한 부여 및 인증을 처리했습니다.

Lighthouse를 사용하면 훨씬 더 많은 작업을 수행할 수 있지만(예: 사용자 지정 스키마 지시문을 생성할 수 있음) 이 기사의 목적을 위해 우리는 기본 사항에 충실했고 상당히 적은 상용구로 GraphQL 서버를 가동할 수 있었습니다.

다음에 모바일 또는 단일 페이지 애플리케이션용 API를 설정해야 하는 경우 GraphQL을 데이터 쿼리 방법으로 고려해야 합니다!

관련 항목: 전체 사용자 인증 및 액세스 제어 – A Laravel Passport Tutorial, Pt. 1