콘텐츠 대표 이미지 - PHP에서 GraphQL과 Lighthouse로 구현하는 현대적 API 설계 가이드
PHP · GraphQL · API 설계

PHP에서 GraphQL과 Lighthouse로 구현하는 현대적 API 설계 가이드

REST API의 한계를 넘어, 유연하고 강력한 GraphQL API를 PHP로 직접 만들어보자! 🚀

GraphQL 단일 엔드포인트 허브 PHP Lighthouse 스키마 정의 웹 클라이언트 React / Vue 모바일 앱 iOS / Android 외부 서비스 API 연동 데이터베이스 GraphQL + Lighthouse 아키텍처 구조 하나의 엔드포인트로 모든 클라이언트를 연결하는 현대적 API

🤔 REST API, 뭔가 불편하지 않았어?

솔직히 말해보자. REST API 쓰다 보면 이런 상황 한 번쯤 겪어봤을 거야.
프론트엔드 개발자가 "이 화면에서 유저 이름이랑 프로필 사진이랑 최근 주문 3개만 필요해요"라고 하는데,
백엔드에서는 /api/users/{id}, /api/users/{id}/orders 이렇게 두 번 요청해야 하고,
게다가 유저 API에서는 필요 없는 데이터가 한 트럭씩 딸려오는 상황 말이야. 😅

이게 바로 REST API의 고질적인 문제인 오버페칭(Over-fetching)과 언더페칭(Under-fetching)이야.
오버페칭은 필요 이상의 데이터를 받아오는 것, 언더페칭은 한 번의 요청으로 필요한 데이터를 다 못 받아서 여러 번 요청해야 하는 것.
이 두 가지 문제를 동시에 해결해주는 게 바로 GraphQL이야! 🎯

💡 GraphQL은 2012년 Facebook이 내부적으로 개발하고 2015년에 오픈소스로 공개한 API 쿼리 언어야.
클라이언트가 필요한 데이터를 정확히 명시해서 요청하고, 서버는 딱 그만큼만 응답하는 방식이지.

🌟 GraphQL이 뭔지 제대로 알아보자

GraphQL은 이름에 "Graph"가 들어가는 것처럼, 데이터를 그래프 구조로 바라봐.
각 데이터 타입이 노드(Node)가 되고, 그 관계가 엣지(Edge)가 되는 구조야.
그래서 복잡하게 연결된 데이터도 한 번의 쿼리로 원하는 형태로 가져올 수 있어.

GraphQL의 핵심 개념 3가지

1
Query (쿼리) — 데이터를 읽어오는 작업이야. REST의 GET 요청과 비슷하지만, 원하는 필드만 골라서 가져올 수 있어.
예: 유저 이름과 이메일만 가져오고 싶다면? 딱 그것만 명시하면 돼!
2
Mutation (뮤테이션) — 데이터를 생성, 수정, 삭제하는 작업이야. REST의 POST, PUT, DELETE에 해당해.
데이터를 변경하는 모든 작업은 Mutation으로 처리해.
3
Subscription (서브스크립션) — 실시간 데이터 업데이트를 위한 기능이야. WebSocket을 통해 서버에서 클라이언트로 데이터를 푸시해줘.
채팅, 알림, 실시간 대시보드 같은 기능에 딱이야!
📌 GraphQL의 핵심 특징 요약

단일 엔드포인트 타입 시스템 클라이언트 주도 쿼리 강력한 인트로스펙션 실시간 지원

REST API는 엔드포인트가 수십 개가 되지만, GraphQL은 단 하나의 엔드포인트(/graphql)로 모든 걸 처리해. 깔끔하지? 😎

🔦 Lighthouse란? PHP의 GraphQL 영웅

PHP에서 GraphQL을 구현하는 방법은 여러 가지가 있어. webonyx/graphql-php 같은 저수준 라이브러리도 있고,
Lighthouse처럼 Laravel 위에서 동작하는 고수준 프레임워크도 있어.
오늘 우리가 집중할 건 바로 Lighthouse야! 🏔️

Lighthouse는 Laravel 애플리케이션에서 GraphQL 서버를 구축하기 위한 PHP 패키지야.
가장 큰 특징은 스키마 우선(Schema-First) 접근 방식을 채택한다는 거야.
SDL(Schema Definition Language)로 스키마를 먼저 정의하고, 그에 맞는 리졸버를 구현하는 방식이지.

🏆 Lighthouse의 강점: Laravel의 Eloquent ORM, 인증 시스템, 미들웨어와 완벽하게 통합돼.
복잡한 설정 없이도 강력한 GraphQL API를 빠르게 구축할 수 있어!

Lighthouse vs 다른 PHP GraphQL 솔루션 비교

라이브러리 특징 난이도 Laravel 통합
Lighthouse 스키마 우선, 강력한 지시어 시스템 ⭐⭐⭐ ✅ 완벽
webonyx/graphql-php 저수준, 높은 유연성 ⭐⭐⭐⭐⭐ 🔧 수동 설정
rebing/graphql-laravel 코드 우선 방식 ⭐⭐⭐⭐ ✅ 좋음
nuwave/lighthouse Lighthouse 최신 버전 ⭐⭐⭐ ✅ 완벽

⚙️ 설치부터 시작하자! 환경 세팅

자, 이제 실제로 손을 움직여볼 시간이야! 🛠️
Laravel 프로젝트가 이미 있다고 가정하고 Lighthouse를 설치해보자.

1단계: Lighthouse 패키지 설치


# Composer로 Lighthouse 설치

composer require nuwave/lighthouse



# 설정 파일 퍼블리시

php artisan vendor:publish --tag=lighthouse-config



# 기본 스키마 파일 생성

php artisan vendor:publish --tag=lighthouse-schema



# GraphQL Playground (개발용 IDE) 설치 (선택사항)

composer require mll-lab/laravel-graphiql
💚 팁! 개발 환경에서는 GraphiQL이나 Altair 같은 GraphQL IDE를 꼭 설치해두자.
API를 테스트하고 문서를 자동으로 확인할 수 있어서 개발 속도가 엄청 빨라져!

2단계: 기본 스키마 파일 구조 이해하기

Lighthouse를 설치하면 graphql/schema.graphql 파일이 생성돼.
이 파일이 우리 API의 모든 것을 정의하는 핵심 파일이야.


"graphql/schema.graphql 기본 구조"



type Query {

user(id: ID! @eq): User @find

users: [User!]! @paginate

}



type Mutation {

createUser(input: CreateUserInput! @spread): User @create

updateUser(id: ID!, input: UpdateUserInput! @spread): User @update

deleteUser(id: ID! @whereKey): User @delete

}



type User {

id: ID!

name: String!

email: String!

created_at: DateTime!

posts: [Post!]! @hasMany

}



input CreateUserInput {

name: String!

email: String! @rules(apply: ["email", "unique:users"])

password: String! @hash

}

보이지? 스키마 파일에서 @find, @paginate, @create, @hasMany 같은 특별한 키워드들이 보일 거야.
이게 바로 Lighthouse의 지시어(Directive)야! 이게 Lighthouse의 핵심 마법이거든. ✨

Lighthouse 주요 지시어(Directive) 한눈에 보기 @기호로 시작하는 마법 같은 키워드들 📖 데이터 조회 @find 단일 레코드 조회 @all 전체 목록 조회 @paginate 페이지네이션 조회 @first 첫 번째 레코드 조회 ✏️ 데이터 변경 @create 새 레코드 생성 @update 레코드 수정 @delete 레코드 삭제 @upsert 생성 또는 수정 🔗 관계 정의 @hasMany 일대다 관계 @belongsTo 다대일 관계 @hasOne 일대일 관계 @belongsToMany 다대다 관계 🔒 보안 / 검증 @auth 인증 필요 @rules 유효성 검사 @can 권한 확인 @hash 값 해시 처리 이 지시어들 덕분에 복잡한 로직을 단 한 줄로 처리할 수 있어!

🏗️ 실전! 블로그 API 만들어보기

이론은 충분히 했으니 이제 실제로 뭔가를 만들어보자! 🎉
간단한 블로그 API를 Lighthouse로 구현해볼 거야.
유저, 포스트, 댓글이 있는 기본적인 구조야.

스키마 설계


"graphql/schema.graphql"



type Query {

# 단일 유저 조회

user(id: ID! @eq): User @find



# 유저 목록 (페이지네이션)

users: [User!]! @paginate(defaultCount: 10)



# 포스트 조회

post(id: ID! @eq): Post @find

posts(orderBy: [OrderByClause!] @orderBy): [Post!]! @paginate



# 내 정보 조회 (인증 필요)

me: User @auth

}



type Mutation {

# 회원가입

register(input: RegisterInput! @spread): AuthPayload

@field(resolver: "App\\GraphQL\\Mutations\\Register")



# 로그인

login(email: String!, password: String!): AuthPayload

@field(resolver: "App\\GraphQL\\Mutations\\Login")



# 포스트 생성 (인증 필요)

createPost(input: CreatePostInput! @spread): Post

@create

@inject(context: "user.id", name: "user_id")



# 포스트 수정 (본인만 가능)

updatePost(id: ID!, input: UpdatePostInput! @spread): Post

@update

@can(ability: "update", find: "id")

}



type User {

id: ID!

name: String!

email: String!

avatar: String

posts: [Post!]! @hasMany

posts_count: Int! @withCount(relation: "posts")

created_at: DateTime!

}



type Post {

id: ID!

title: String!

content: String!

published: Boolean!

user: User! @belongsTo

comments: [Comment!]! @hasMany

comments_count: Int! @withCount(relation: "comments")

created_at: DateTime!

updated_at: DateTime!

}



type Comment {

id: ID!

content: String!

user: User! @belongsTo

post: Post! @belongsTo

created_at: DateTime!

}



type AuthPayload {

access_token: String!

token_type: String!

user: User!

}



input RegisterInput {

name: String! @rules(apply: ["required", "min:2"])

email: String! @rules(apply: ["required", "email", "unique:users"])

password: String! @rules(apply: ["required", "min:8"]) @hash

}



input CreatePostInput {

title: String! @rules(apply: ["required", "min:5", "max:255"])

content: String! @rules(apply: ["required", "min:10"])

published: Boolean

}
💚 주목! 스키마 파일 하나로 데이터 구조, 관계, 유효성 검사, 권한까지 모두 정의할 수 있어.
별도의 Controller나 복잡한 로직 없이도 기본적인 CRUD가 완성돼!

🔧 커스텀 리졸버 만들기

Lighthouse의 내장 지시어만으로 해결이 안 되는 복잡한 비즈니스 로직이 있을 때는
커스텀 리졸버(Custom Resolver)를 만들어야 해.
로그인 기능처럼 토큰을 발급하고 인증을 처리하는 로직이 대표적인 예야.

로그인 뮤테이션 리졸버 구현


<?php

// app/GraphQL/Mutations/Login.php



namespace App\GraphQL\Mutations;



use App\Models\User;

use GraphQL\Type\Definition\ResolveInfo;

use Illuminate\Support\Facades\Auth;

use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;



class Login

{

/**

* 로그인 처리 리졸버

*/

public function __invoke(

mixed $root,

array $args,

GraphQLContext $context,

ResolveInfo $resolveInfo

): array {

$credentials = [

'email' => $args['email'],

'password' => $args['password'],

];



if (!Auth::attempt($credentials)) {

throw new \Exception('이메일 또는 비밀번호가 올바르지 않습니다.');

}



$user = Auth::user();

$token = $user->createToken('auth_token')->plainTextToken;



return [

'access_token' => $token,

'token_type' => 'Bearer',

'user' => $user,

];

}

}

커스텀 쿼리 리졸버 예시


<?php

// app/GraphQL/Queries/PopularPosts.php



namespace App\GraphQL\Queries;



use App\Models\Post;

use GraphQL\Type\Definition\ResolveInfo;

use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;



class PopularPosts

{

public function __invoke(

mixed $root,

array $args,

GraphQLContext $context,

ResolveInfo $resolveInfo

): \Illuminate\Database\Eloquent\Collection {

return Post::query()

->where('published', true)

->withCount('comments')

->orderByDesc('comments_count')

->limit($args['limit'] ?? 10)

->get();

}

}



// 스키마에 추가

// popularPosts(limit: Int): [Post!]!

//   @field(resolver: "App\\GraphQL\\Queries\\PopularPosts")

🚨 N+1 문제와 DataLoader로 해결하기

GraphQL을 처음 쓰다 보면 반드시 마주치는 문제가 있어. 바로 N+1 쿼리 문제야.
예를 들어 포스트 10개를 가져오면서 각 포스트의 작성자 정보도 함께 가져온다고 해보자.
그러면 포스트 목록 쿼리 1번 + 각 포스트마다 유저 쿼리 10번 = 총 11번의 DB 쿼리가 발생해! 😱

⚠️ N+1 문제는 GraphQL의 고질적인 성능 이슈야.
100개의 포스트를 조회하면 101번의 쿼리가 발생할 수 있어. 이건 심각한 성능 저하를 일으켜!

Lighthouse의 배치 로딩으로 해결!

Lighthouse는 이 문제를 해결하기 위해 배치 로딩(Batch Loading)을 내장하고 있어.
@belongsTo, @hasMany 같은 관계 지시어를 사용하면 자동으로 배치 로딩이 적용돼.


<?php

// 커스텀 배치 로더 구현 예시

// app/GraphQL/Loaders/UserLoader.php



namespace App\GraphQL\Loaders;



use App\Models\User;

use Illuminate\Support\Collection;



class UserLoader

{

/**

* 여러 ID를 한 번에 로드 (N+1 방지)

*/

public function loadMany(array $userIds): Collection

{

// 단 1번의 쿼리로 모든 유저를 가져옴

return User::whereIn('id', $userIds)

->get()

->keyBy('id');

}

}



// lighthouse.php 설정에서 배치 로딩 활성화

// 'batchload_relations' => true,
💚 꿀팁! Lighthouse의 @with 지시어를 사용하면 Eager Loading을 명시적으로 지정할 수 있어.
예: posts: [Post!]! @hasMany @with(relation: "user")
이렇게 하면 포스트를 가져올 때 유저 정보도 함께 로드해서 N+1 문제를 원천 차단해!

🔐 인증과 권한 관리

실제 서비스에서 API 보안은 정말 중요하지. Lighthouse에서는 Laravel의 인증 시스템과 완벽하게 통합돼서
간단한 지시어 몇 개로 강력한 보안을 구현할 수 있어.

인증 미들웨어 설정


// config/lighthouse.php

'route' => [

'prefix' => 'graphql',

'middleware' => [

\Nuwave\Lighthouse\Http\Middleware\AcceptJson::class,

// Sanctum 인증 미들웨어

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,

],

],



// 스키마에서 인증 적용

type Mutation {

# @guard 지시어로 인증 필요 설정

createPost(input: CreatePostInput! @spread): Post

@guard(with: "sanctum")

@create

@inject(context: "user.id", name: "user_id")



# @can 지시어로 Policy 기반 권한 확인

deletePost(id: ID! @whereKey): Post

@guard

@can(ability: "delete", find: "id")

@delete

}

Policy 기반 권한 관리


<?php

// app/Policies/PostPolicy.php



namespace App\Policies;



use App\Models\Post;

use App\Models\User;



class PostPolicy

{

/**

* 포스트 수정 권한: 작성자 본인만 가능

*/

public function update(User $user, Post $post): bool

{

return $user->id === $post->user_id;

}



/**

* 포스트 삭제 권한: 작성자 또는 관리자

*/

public function delete(User $user, Post $post): bool

{

return $user->id === $post->user_id

|| $user->hasRole('admin');

}

}

⚡ 실시간 기능: Subscription 구현

GraphQL의 꽃이라고 할 수 있는 Subscription을 구현해보자!
채팅 앱이나 실시간 알림 기능에 딱 맞는 기능이야.
Lighthouse에서는 Pusher나 Redis를 통해 Subscription을 지원해.


// 스키마에 Subscription 추가

type Subscription {

# 새 댓글 실시간 알림

commentAdded(postId: ID!): Comment

@subscription(class: "App\\GraphQL\\Subscriptions\\CommentAdded")



# 포스트 업데이트 알림

postUpdated(id: ID!): Post

@subscription(class: "App\\GraphQL\\Subscriptions\\PostUpdated")

}



---



<?php

// app/GraphQL/Subscriptions/CommentAdded.php



namespace App\GraphQL\Subscriptions;



use App\Models\Comment;

use Illuminate\Http\Request;

use Nuwave\Lighthouse\Subscriptions\Subscriber;

use Nuwave\Lighthouse\Schema\Types\GraphQLSubscription;



class CommentAdded extends GraphQLSubscription

{

/**

* 구독 채널 이름 결정

*/

public function encodeTopic(Subscriber $subscriber, string $fieldName): string

{

$postId = $subscriber->args['postId'];

return "comment-added-post-{$postId}";

}



/**

* 이벤트 필터링

*/

public function filter(Subscriber $subscriber, mixed $root): bool

{

return $root->post_id == $subscriber->args['postId'];

}

}



// 뮤테이션에서 Subscription 이벤트 발행

// createComment 뮤테이션 리졸버에서:

// Subscription::broadcast('commentAdded', $comment);

🧪 GraphQL 쿼리 실제로 날려보기

API가 완성됐으면 실제로 쿼리를 날려봐야지! 🎯
GraphiQL이나 Altair에서 이런 식으로 쿼리를 작성해봐.

복잡한 중첩 쿼리 예시


# 포스트 목록과 작성자, 댓글 수를 한 번에 가져오기

query GetPostsWithDetails {

posts(first: 10, orderBy: [{column: CREATED_AT, order: DESC}]) {

data {

id

title

content

published

comments_count

created_at

user {

id

name

avatar

}

comments(first: 3) {

data {

id

content

user {

name

}

}

}

}

paginatorInfo {

currentPage

lastPage

total

}

}

}



# 로그인 뮤테이션

mutation Login {

login(email: "user@example.com", password: "password123") {

access_token

token_type

user {

id

name

email

}

}

}



# 포스트 생성 (Authorization 헤더 필요)

mutation CreatePost {

createPost(input: {

title: "GraphQL이 이렇게 편할 줄이야!"

content: "Lighthouse 덕분에 API 개발이 너무 쉬워졌어요."

published: true

}) {

id

title

user {

name

}

}

}
🎯 REST API였다면 여러 번 요청해야 했을 데이터를 GraphQL에서는 단 한 번의 요청으로 원하는 형태로 가져올 수 있어!
클라이언트가 필요한 것만 정확히 요청하니까 불필요한 데이터 전송도 없고, 성능도 훨씬 좋아져.

📊 성능 최적화 전략

GraphQL API를 프로덕션에 배포하기 전에 꼭 챙겨야 할 성능 최적화 전략들을 알아보자! 💪

1. 쿼리 복잡도 제한

악의적인 사용자가 엄청나게 복잡한 쿼리를 날려서 서버를 다운시킬 수 있어.
이를 방지하기 위해 쿼리 복잡도와 깊이를 제한해야 해.


// config/lighthouse.php

'security' => [

// 최대 쿼리 복잡도 (각 필드마다 복잡도 점수 합산)

'max_query_complexity' => 200,



// 최대 중첩 깊이

'max_query_depth' => 10,



// 인트로스펙션 비활성화 (프로덕션에서 권장)

'disable_introspection' => env('LIGHTHOUSE_DISABLE_INTROSPECTION', false),

],

2. 캐싱 전략


// 스키마에서 캐시 지시어 사용

type Query {

# 결과를 60초 동안 캐시

popularPosts: [Post!]!

@field(resolver: "App\\GraphQL\\Queries\\PopularPosts")

@cache(maxAge: 60)



# 인증된 사용자별로 캐시

myProfile: User

@auth

@cache(maxAge: 300, private: true)

}



// 리졸버에서 직접 캐시 처리

use Illuminate\Support\Facades\Cache;



public function __invoke(...): Collection

{

return Cache::remember('popular-posts', 3600, function () {

return Post::popular()->limit(10)->get();

});

}

3. Persisted Queries (지속 쿼리)

클라이언트가 매번 전체 쿼리 문자열을 전송하는 대신, 미리 등록된 쿼리의 해시값만 전송하는 방식이야.
네트워크 트래픽을 줄이고 보안도 강화할 수 있어.

⚡ 성능 최적화 체크리스트
  • ✅ N+1 쿼리 방지 (배치 로딩 활성화)
  • ✅ 쿼리 복잡도 및 깊이 제한 설정
  • ✅ Redis 캐싱 적용
  • ✅ 데이터베이스 인덱스 최적화
  • ✅ Persisted Queries 적용
  • ✅ 프로덕션에서 인트로스펙션 비활성화
  • ✅ 응답 압축(gzip) 활성화

🧩 커스텀 지시어 만들기

Lighthouse의 내장 지시어로 부족할 때는 직접 커스텀 지시어를 만들 수 있어.
예를 들어 특정 필드를 자동으로 대문자로 변환하는 지시어를 만들어보자.


<?php

// app/GraphQL/Directives/UppercaseDirective.php



namespace App\GraphQL\Directives;



use Nuwave\Lighthouse\Schema\Directives\BaseDirective;

use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware;

use Nuwave\Lighthouse\Execution\Arguments\ArgumentSet;

use Closure;



class UppercaseDirective extends BaseDirective implements FieldMiddleware

{

public static function definition(): string

{

return /** @lang GraphQL */ <<

GRAPHQL

"""

필드 값을 대문자로 변환합니다.

"""

directive @uppercase on FIELD_DEFINITION

GRAPHQL;

}



public function handleField(

\Nuwave\Lighthouse\Execution\ResolveInfo $fieldValue,

Closure $next

): void {

$fieldValue->setResolver(function () use ($fieldValue, $next) {

$next($fieldValue);

$result = $fieldValue->getResolver()();

return is_string($result) ? strtoupper($result) : $result;

});

}

}



// 스키마에서 사용

type User {

name: String! @uppercase

}

🌐 실제 프로젝트에서의 활용 사례

이론과 코드는 충분히 봤으니, 실제로 어떤 상황에서 GraphQL + Lighthouse가 빛을 발하는지 알아보자!

언제 GraphQL을 선택해야 할까?

상황 GraphQL 추천 REST 추천
다양한 클라이언트 (웹, 앱, IoT) ✅ 강력 추천 🔶 가능하지만 복잡
복잡한 데이터 관계 ✅ 강력 추천 🔶 여러 엔드포인트 필요
실시간 기능 필요 ✅ Subscription 활용 🔶 WebSocket 별도 구현
단순한 CRUD API 🔶 가능하지만 오버스펙 ✅ 더 간단
파일 업로드 중심 🔶 추가 설정 필요 ✅ 더 자연스러움
빠른 프로토타이핑 ✅ 스키마로 빠른 개발 ✅ 둘 다 가능

재능 공유 플랫폼인 재능넷처럼 다양한 재능 카테고리, 유저 프로필, 리뷰, 거래 내역 등
복잡하게 연결된 데이터를 다루는 서비스라면 GraphQL이 정말 빛을 발할 수 있어!
클라이언트마다 필요한 데이터가 다를 때 GraphQL의 유연성이 극대화되거든. 🌟


🧪 테스트 작성하기

좋은 API는 테스트가 필수야! Lighthouse는 Laravel의 테스트 시스템과 완벽하게 통합돼서
GraphQL 쿼리를 테스트하는 것도 정말 쉬워.


<?php

// tests/Feature/GraphQL/PostTest.php



namespace Tests\Feature\GraphQL;



use App\Models\Post;

use App\Models\User;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;



class PostTest extends TestCase

{

use RefreshDatabase;



public function test_can_query_posts(): void

{

Post::factory(5)->create();



$this->graphQL(/** @lang GraphQL */ '

query {

posts(first: 5) {

data {

id

title

}

paginatorInfo {

total

}

}

}

')->assertJson([

'data' => [

'posts' => [

'paginatorInfo' => [

'total' => 5,

],

],

],

]);

}



public function test_authenticated_user_can_create_post(): void

{

$user = User::factory()->create();



$this->actingAs($user)

->graphQL('

mutation {

createPost(input: {

title: "테스트 포스트"

content: "테스트 내용입니다."

published: true

}) {

id

title

}

}

')->assertJsonPath('data.createPost.title', '테스트 포스트');



$this->assertDatabaseHas('posts', [

'title' => '테스트 포스트',

'user_id' => $user->id,

]);

}

}

🚀 배포 전 최종 체크리스트

드디어 배포할 준비가 됐어! 🎊 프로덕션 배포 전에 꼭 확인해야 할 것들을 정리해줄게.

1
인트로스펙션 비활성화
프로덕션에서는 스키마 정보가 외부에 노출되지 않도록 인트로스펙션을 꺼야 해.
LIGHTHOUSE_DISABLE_INTROSPECTION=true
2
쿼리 복잡도 제한 설정
DDoS 공격 방지를 위해 max_query_complexity와 max_query_depth를 적절히 설정해.
3
Rate Limiting 적용
Laravel의 Rate Limiter를 GraphQL 라우트에 적용해서 과도한 요청을 차단해.
4
에러 메시지 노출 제한
프로덕션에서는 상세한 에러 메시지가 클라이언트에 노출되지 않도록 설정해.
APP_DEBUG=false
5
스키마 캐싱
매 요청마다 스키마를 파싱하지 않도록 스키마를 캐시해.
php artisan lighthouse:cache
6
모니터링 설정
느린 쿼리를 감지하고 성능을 모니터링하기 위해 Telescope나 Debugbar를 활용해.
💚 보너스 팁! 재능넷처럼 다양한 사용자가 이용하는 플랫폼을 개발할 때는
GraphQL의 Fragment 기능을 활용하면 클라이언트 코드의 재사용성을 크게 높일 수 있어!
공통으로 사용하는 필드 집합을 Fragment로 정의해두면 쿼리 작성이 훨씬 깔끔해져.

🎯 정리: PHP GraphQL 개발의 핵심 포인트

자, 오늘 정말 많은 내용을 다뤘어! 마지막으로 핵심 포인트를 정리해볼게. 📝

🌟 GraphQL + Lighthouse의 핵심 가치

1️⃣ 단일 엔드포인트로 모든 데이터 요청 처리
2️⃣ 클라이언트 주도로 필요한 데이터만 정확히 요청
3️⃣ 강력한 타입 시스템으로 API 문서가 자동 생성
4️⃣ Lighthouse 지시어로 복잡한 로직을 단 한 줄로 처리
5️⃣ Laravel 완벽 통합으로 기존 코드 재활용 극대화
6️⃣ 실시간 Subscription으로 현대적 앱 기능 구현

처음에는 REST API에 익숙해서 GraphQL이 낯설게 느껴질 수 있어.
스키마를 먼저 설계하는 방식도 처음엔 어색할 수 있고.
하지만 한 번 익숙해지면 "이걸 왜 이제야 알았지?"라는 생각이 들 거야! 😄

특히 Lighthouse의 지시어 시스템은 정말 마법 같아.
복잡한 CRUD 로직, 관계 처리, 유효성 검사, 권한 관리를 스키마 파일 하나에서 선언적으로 처리할 수 있거든.

자, 이제 직접 만들어봐! 코드를 치다 보면 자연스럽게 익혀질 거야. 화이팅! 💪🔥

댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0