#4 GraphQL Best Practices > 앱개발

앱개발

#4 GraphQL Best Practices 정보

#4 GraphQL Best Practices

본문

GraphQL Best Practices

GraphQL 사양은 네트워크 처리, 승인 및 페이지 매김과 같은 API가 직면한 몇 가지 중요한 문제에 대해 의도적으로 침묵합니다. GraphQL을 사용할 때 이러한 문제에 대한 해결책이 없다는 것을 의미하는 것은 아니며 단지 GraphQL이 무엇인지에 대한 설명이 아니며 일반적인 관행이 아닌 것입니다. 

 

이 절에 있는 기사는 복음(gospel)으로 받아 들여서는 안되며 어떤 경우에는 다른 접근법에 찬성하여 무시될 수 있습니다. 일부 기사에서는 GraphQL 서비스를 설계하고 배포하는 과정에서 Facebook 내에서 개발 된 철학을 소개하는 반면, HTTP를 통해 서빙하고 인증을 수행하는 것과 같은 일반적인 문제를 해결하기위한 전술적 제안이 있습니다. 

 

다음은 GraphQL 서비스가 보유하고 있는 가장 일반적인 모범 사례와 의견이 있는 자세에 대한 간략한 설명입니다. 그러나 이 섹션의 각 기사에서는 이러한 주제 및 다른 주제에 대해 보다 자세히 설명합니다. 

HTTP

GraphQL은 일반적으로 서비스의 모든 기능을 표현하는 단일 종점을 통해 HTTP를 통해 제공됩니다. 이는 각각 하나의 리소스를 노출하는 일련의 URL을 노출하는 REST API와는 대조적입니다. GraphQL은 리소스 URL 모음과 함께 사용할 수 있지만 GraphiQL과 같은 도구를 사용하기가 어려울 수 있습니다.

 

이에 대한 자세한 내용은 HTTP를 통한 검색을 참조하십시오.

JSON (with GZIP)

GraphQL 서비스는 일반적으로 JSON을 사용하여 응답하지만 GraphQL 사양에는 JSON이 필요하지 않습니다. JSON은 더 나은 네트워크 성능을 약속하는 API 레이어의 이상한 선택처럼 보일 수 있지만 대부분 텍스트이기 때문에 GZIP로 매우 잘 압축됩니다.

 

모든 프로덕션 GraphQL 서비스가 GZIP를 활성화하고 고객이 헤더를 보내도록 권장합니다.

Accept-Encoding: gzip

JSON은 클라이언트 및 API 개발자들에게도 친숙하며 읽기 및 디버그가 쉽습니다. 실제로 GraphQL 구문은 JSON 구문에 부분적으로 영향을받습니다. 

Versioning

GraphQL 서비스가 다른 REST API와 같이 버전이 변경되는 것을 막을 수있는 것은 없지만 GraphQL은 GraphQL 스키마의 지속적인 발전을위한 도구를 제공하여 버전 관리를 피하는 것에 대해 강한 의견을 가지고 있습니다. 

 

왜 대부분의 API 버전은 무엇입니까? API 엔드 포인트에서 리턴 된 데이터에 대한 제한된 제어가 있을 경우, 변경 사항은 심각한 변경 사항으로 간주 될 수 있으며, 변경 사항은 새 버전이 필요합니다. API에 새로운 기능을 추가하는 데 새로운 버전이 필요한 경우 API를 이해하기 쉽고 유지 보수 할 수있는 버전을 자주 출시하고 증분 버전을 많이 사용하는 것이 좋습니다. 

 

반대로 GraphQL은 명시 적으로 요청 된 데이터만 반환하므로 새로운 유형과 새로운 유형의 필드를 통해 새로운 기능을 추가 할 수 있습니다. 이는 항상 변경 사항을 피하고 버전이없는 API를 제공하는 일반적인 관행으로 이어집니다. 

Nullability

"null"을 인식하는 대부분의 유형 시스템은 공통 유형 및 해당 유형의 널 입력 버전을 제공하며, 명시적으로 선언하지 않는 한 디폴트 유형은 "널 (null)"을 포함하지 않습니다. 그러나 GraphQL 형식 시스템에서는 모든 필드가 기본적으로 nullable입니다. 이것은 데이터베이스 및 기타 서비스로 뒷받침 되는 네트워크 서비스에서 많은 일이 발생할 수 있기 때문입니다. 데이터베이스가 다운되거나 비동기 작업이 실패 할 수 있으며 예외가 발생할 수 있습니다. 단순한 시스템 실패 이외에도 권한 부여는 종종 세분화 될 수 있으며 요청 내의 개별 필드는 서로 다른 인증 규칙을 가질 수 있습니다. 

 

모든 필드를 기본적으로 nullable로 설정하면 이러한 이유로 인해 해당 필드가 요청에 대한 완전한 실패가 아닌 "null"로 반환 될 수 있습니다. 대신, GraphQL은 null이 아닌 변형을 제공합니다.이 변종은 클라이언트에게 요청시 필드가 결코 "null"을 반환하지 않도록 보장합니다. 대신 오류가 발생하면 이전 상위 필드는 대신 "null"이됩니다. 

 

GraphQL 스키마를 디자인 할 때, 잘못될 수 있는 모든 문제와 실패한 필드에 대해 "null"이 적절한 값임을 명심하는 것이 중요합니다. 일반적으로 그것은 그렇지만, 때로는 그렇지 않습니다. 이러한 경우, null이 아닌 유형을 사용하여 해당 보증을 작성하십시오.

Pagination

GraphQL 유형 시스템은 일부 필드가 값 목록을 반환하도록 허용하지만 API 설계자에게 더 긴 값 목록의 페이지 매김을 남깁니다. 페이지 매김 (pagination)을위한 다양한 API 디자인이 있으며, 각각 장단점이 있습니다. 

 

일반적으로 긴 목록을 반환 할 수있는 필드는 "first"및 "after"인수를 사용하여 목록의 특정 영역을 지정할 수 있습니다. 여기서 "after"는 목록의 각 값에 대한 고유 한 식별자입니다. 

 

기능이 풍부한 페이지 매김을 사용하여 궁극적으로 API를 디자인하면 "연결"이라는 모범 사례 패턴을 얻을 수 있습니다. Relay와 같은 GraphQL의 일부 클라이언트 도구는 Connections 패턴을 알고 있으며 GraphQL API가이 패턴을 사용할 때 클라이언트측 페이지 매김을 자동으로 지원합니다. 

 

자세한 내용은 페이지 매김에 대한 기사를 참조하십시오. 

Server-side Batching & Caching

GraphQL은 모든 유형의 모든 필드가 해당 값을 해결하는 데 초점을 맞춘 단일 용도의 기능을 가진 깨끗한 코드를 서버에 작성할 수 있도록 설계되었습니다. 그러나 추가 고려없이, 순진한 GraphQL 서비스는 매우 "chatty"또는 반복적으로 데이터베이스에서 데이터를 로드 할 수 있습니다. 

 

이는 일반적으로 백엔드의 데이터에 대한 여러 요청이 짧은 기간 동안 수집 된 다음 Facebook의 DataLoader와 같은 도구를 사용하여 기본 데이터베이스 또는 마이크로 서비스에 단일 요청으로 발송되는 일괄 처리 기법으로 해결됩니다. 

Thinking in Graphs

It's Graphs All the Way Down *

GraphQL을 사용하면 비즈니스 도메인을 그래프로 모델링 할 수 있습니다. 

그래프는 우리의 자연스러운 정신 모델과 근본적인 프로세스에 대한 구두 설명과 닮았기 때문에 많은 실제 세계 현상을 모델링 할 수있는 강력한 도구입니다. GraphQL을 사용하면 스키마를 정의하여 비즈니스 도메인을 그래프로 모델링 할 수 있습니다. 스키마 내에서 다른 유형의 노드와 노드가 서로 연결/연관되는 방식을 정의합니다. 클라이언트에서 이것은 객체 지향 프로그래밍과 유사한 패턴을 생성합니다: 다른 유형을 참조하는 유형. 서버에서는 GraphQL이 인터페이스만 정의하므로 모든 백엔드 (새로운 또는 기존)에서 자유롭게 사용할 수 있습니다. 

Shared Language

이름 짓기는 직관적 인 API를 작성하는 데있어 어렵지만 중요한 부분입니다. 

GraphQL 스키마는 팀 및 사용자를위한 표현적인 공유 언어로 생각하십시오. 훌륭한 스키마를 구축하려면 비즈니스를 설명 할 때 사용하는 일상 언어를 살펴보십시오. 예를 들어 영어로 이메일 앱을 설명하려고합니다. 

 

  • 사용자는 여러 이메일 계정을 가질 수 있습니다.
  • 각 이메일 계정에는 주소,받은 편지함, 임시 보관함, 삭제 된 항목 및 보낸 편지함이 있습니다.
  • 각 전자 메일에는 보낸 사람, 수신 날짜, 제목 및 본문이 있습니다.
  • 사용자는 수신자 주소없이 이메일을 보낼 수 없습니다.

 

이름 짓기는 직관적 인 API를 개발하는 데 있어 어렵지만 중요한 부분이므로 문제가 되는 도메인과 사용자에게 무엇이 합당한 지 주의 깊게 생각해보십시오. GraphQL 스키마에서 노드와 관계에 대해 직관적이고 내구성있는 이름을 선택해야하기 때문에 팀은 이러한 비즈니스 도메인 규칙에 대한 이해와 합의를 공유해야 합니다. 실행할 쿼리 중 일부를 상상해보십시오. 

 

내 모든 계정에 대해 받은 편지함에 읽지 않은 이메일 수 가져 오기 

{
  accounts {
    inbox {
      unreadEmailCount
    }
  }
}

메인 계정의 처음 20 개 초안에 대한 "미리보기 정보" 가져 오기 

{
  mainAccount {
    drafts(first: 20) {
      ...previewInfo
    }
  }
}

fragment previewInfo on Email {
  subject
  bodyPreviewSentence
}

Business Logic Layer

비즈니스 로직 계층은 비즈니스 도메인 규칙을 적용하기위한 단일 진실의 소스로 작동해야합니다. 

실제 비즈니스 로직은 어디에 정의해야 합니까? 유효성 검사 및 권한 부여 확인은 어디서 수행해야 합니까? 대답: 전용 비즈니스 로직 계층 내부. 비즈니스 로직 계층은 비즈니스 도메인 규칙을 적용하기위한 단일 진실로 작동해야합니다. 

084c70eedf537bf592720a4475fff9ac_1482453146_7749.png
위의 다이어그램에서 시스템의 모든 진입 점 (REST, GraphQL 및 RPC)은 동일한 유효성 검사, 권한 부여 및 오류 처리 규칙으로 처리됩니다. 

Working with Legacy Data

클라이언트가 레거시 데이터베이스 스키마를 미러링하는 대신 데이터를 사용하는 방법을 설명하는 GraphQL 스키마를 작성하는 것이 좋습니다. 

때로는 클라이언트가 데이터를 소비하는 방식을 완벽하게 반영하지 않는 기존 데이터 소스로 작업하는 경우가 있습니다. 이 경우 레거시 데이터베이스 스키마를 미러링하는 대신 클라이언트가 데이터를 사용하는 방법을 설명하는 GraphQL 스키마를 작성하는 것이 좋습니다.

 

"방법"보다는 "무엇"을 표현하도록 GraphQL 스키마를 작성하십시오. 그런 다음 이전 클라이언트와의 인터페이스를 깨지 않고 구현 세부 정보를 향상시킬 수 있습니다.

One Step at a time

검증과 피드백을보다 자주 얻으십시오. 

한 번에 전체 비즈니스 도메인을 모델링하지 마십시오. 오히려 한 번에 하나의 시나리오에 필요한 스키마 부분만 빌드하십시오. 점진적으로 스키마를 확장함으로써 올바른 솔루션을 구축하기 위해 검증 및 피드백을 보다 자주 얻을 수 있습니다. 

 

Serving over HTTP

GraphpQL을 사용할 때 편재성 때문에 HTTP는 클라이언트 - 서버 프로토콜을 위한 가장 일반적인 선택입니다. 다음은 HTTP를 통해 작동하도록 GraphQL 서버를 설정하기위한 몇 가지 지침입니다. 

Web Request Pipeline

대부분의 최신 웹 프레임 워크는 요청이 미들웨어 스택 (AKA 필터/플러그인)을 통과하는 파이프 라인 모델을 사용합니다. 요청이 파이프 라인을 통해 흐를 때 응답을 통해 검사, 변환, 수정 또는 종료 될 수 있습니다. GraphQL은 모든 인증 미들웨어 다음에 배치되어야하므로 HTTP 엔드 포인트 핸들러에서 사용하는 동일한 세션 및 사용자 정보에 액세스 할 수 있습니다. 

URIs, Routes

HTTP는 일반적으로 자원을 핵심 개념으로 사용하는 REST와 관련이 있습니다. 반대로 GraphQL의 개념 모델은 엔티티 그래프입니다. 결과적으로 GraphQL의 엔티티는 URL로 식별되지 않습니다. 대신, GraphQL 서버는 단일 URL/endpoint, 보통 /graphql에서 작동하며 주어진 서비스에 대한 모든 GraphQL 요청은이 끝점에서 지정되어야합니다. 

HTTP Methods, Headers, and Body

GraphQL HTTP 서버는 HTTP GET 및 POST 메서드를 처리해야합니다. 

GET request

HTTP GET 요청을 수신하면 GraphQL 쿼리는 "쿼리" 문자열에 지정되어야합니다. 예를 들어, 다음 GraphQL 쿼리를 실행하려면: 

{
  me {
    name
  }
}

이 요청은 다음과 같이 HTTP GET을 통해 전송 될 수 있습니다. 

http://myapi/graphql?query={me{name}}

쿼리 변수는 variables라는 추가 쿼리 매개 변수에서 JSON 인코딩 문자열로 보낼 수 있습니다. 쿼리에 여러 개의 명명 된 연산이 포함되어 있으면 operationName 쿼리 매개 변수를 사용하여 어느 것을 실행해야하는지 제어 할 수 있습니다. 

POST request

표준 GraphQL POST 요청은 application/json 콘텐츠 유형을 사용해야하며 다음 형식의 JSON 인코딩 본문을 포함해야합니다. 

{
  "query": "...",
  "operationName": "...",
  "variables": { "myVariable": "someValue", ... }
}

operationName 및 variables는 선택적 필드입니다. operationName은 쿼리에 여러 연산이 있는 경우에만 필요합니다.

 

위의 내용 외에도 추가로 두 가지 사례를 지원하는 것이 좋습니다.

 

  • 위의 GET 예에서와 같이 "query" 문자열 매개 변수가 있으면 HTTP GET 경우와 같은 방식으로 구문 분석하고 처리해야합니다.
  • "application/graphql"Content-Type 헤더가있는 경우 HTTP POST 본문 내용을 GraphQL 쿼리 문자열로 처리하십시오.
express-graphql을 사용하고 있다면, 당신은 이미 이러한 행동을 무료로 얻을 수 있습니다.

 

Response

 

쿼리와 변수가 전송된 방법에 관계없이 응답은 요청 본문에 JSON 형식으로 반환되어야합니다. 스펙에서 언급했듯이 쿼리는 데이터와 오류를 유발할 수 있으며 이러한 오류는 다음과 같은 형식의 JSON 객체로 반환되어야합니다.

 

{
  "data": { ... },
  "errors": [ ... ]
}

 

반환 된 오류가 없는 경우 응답에 "오류"필드가 없어야 합니다. GraphQL 스펙에 따라 데이터가 반환되지 않으면 "데이터"필드는 실행 중에 오류가 발생한 경우에만 포함되어야합니다.

 

GraphiQL

 

GraphiQL은 테스트 및 개발 중에 유용하지만 기본적으로 프로덕션 환경에서 사용하지 않도록 설정해야합니다. express-graphql을 사용하는 경우 NODE_ENV 환경 변수를 토대로 토글 할 수 있습니다.

 

app.use('/graphql', graphqlHTTP({
  schema: MySessionAwareGraphQLSchema,
  graphiql: process.env.NODE_ENV === 'development',
}));

Node

 

NodeJS를 사용하는 경우 express-graphql 또는 graphql-server를 사용하는 것이 좋습니다.

 

Authorization

 

비즈니스 로직 계층에 권한 부여 로직 위임
권한 부여는 주어진 사용자 / 세션 / 컨텍스트가 작업을 수행하거나 데이터를 볼 수있는 권한이 있는지 여부를 나타내는 비즈니스 논리 유형입니다. 예:

"저자 만 초안을 볼 수 있습니다"

이러한 종류의 동작을 적용하려면 비즈니스 로직 계층에서 수행해야합니다. GraphQL 레이어에 다음과 같이 권한 부여 논리를 배치해야합니다.

 

var postType = new GraphQLObjectType({
  name: ‘Post’,
  fields: {
    body: {
      type: GraphQLString,
      resolve: (post, args, context, { rootValue }) => {
        // return the post body only if the user is the post's author
        if (context.user && (context.user.id === post.authorId)) {
          return post.body;
        }
        return null;
      }
    }
  }
});

 

게시물의 authorId 필드가 현재 사용자의 ID와 같은지 여부를 확인하여 "저자가 게시물을 소유하고 있음"을 정의합니다. 문제를 발견 할 수 있습니까? 각 코드에 대한이 코드를 서비스에 복제해야 합니다. 완벽하게 동기화되지 않은 상태에서 사용자는 어떤 API를 사용하는지에 따라 다른 데이터를 볼 수 있습니다 .Yikes! 인증을위한 진실의 단일 소스를 확보함으로써 이를 피할 수 있습니다.

그래프 알고리즘이나 프로토 타입을 배울 때 리졸버 내부에 인증 로직을 정의하는 것이 좋습니다. 그러나 프로덕션 코드베이스의 경우 비즈니스 논리 계층에 권한 부여 논리를 위임합니다. 다음은 그 예입니다.

 

//Authorization logic lives inside postRepository
var postRepository = require('postRepository');

var postType = new GraphQLObjectType({
  name: ‘Post’,
  fields: {
    body: {
      type: GraphQLString,
      resolve: (post, args, context, { rootValue }) => {
        return postRepository.getBody(context.user, post);
      }
    }
  }
});

 

위의 예에서 비즈니스 로직 계층은 호출자가 사용자 객체를 제공해야 한다는 것을 알 수 있습니다. GraphQL.js를 사용하는 경우 사용자 객체는 컨텍스트 인수 나 리졸버의 네 번째 인수에있는 rootValue에 채워 져야합니다.

불투명 한 토큰 또는 API 키 대신 완전 수화된 사용자 개체를 비즈니스 로직 계층에 전달하는 것이 좋습니다. 이렇게하면 요청 처리 파이프 라인의 여러 단계에서 인증 및 권한 부여와 관련된 뚜렷한 문제를 처리 할 수 있습니다.

 

공감
0

댓글 0개

전체 756 |RSS
앱개발 내용 검색

회원로그인

진행중 포인트경매

  1. 참여76 회 시작24.04.19 15:40 종료24.04.26 15:40
(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT