알립니다
이 번역 시리즈는 2019년 10월 경에 작성되었습니다. 원본인 GraphQL - Node 튜토리얼은 현재 새로운 버전으로 새롭게 작성되었습니다. 따라서 이 글은 Deprecated된 글임을 알려드립니다.
- 본 시리즈에서는 How to GraphQL의 Tutorial 문서들을 차례대로 번역합니다.
- 본 시리즈는 GraphQL Basic and Advanced 시리즈에서 이어집니다. GraphQL을 처음 접하는 분들은 해당 시리즈를 먼저 읽고 오시는 것을 추천드립니다.
- 이 글은 GraphQL-Node Tutorial - Filtering, Pagination & Sorting을 번역한 글입니다.
- 오역 또는 의역이 있을 수 있습니다. 양해 부탁드리며, 수정할 필요한 부분은 댓글로 요청해주세요.
이번 장은 이 튜토리얼의 가장 마지막 부분으로, API 구현의 마무리 작업이 이루어집니다. 클라이언트 측에서 필터링과 페이지네이션을 위한 인자를 제공하여 feed
쿼리로부터 반환되는 Link
요소 목록을 제어할 수 있도록 하는 것이 목표입니다.
Prisma를 사용하면, 큰 수고를 들이지 않더라도 필터링 기능을 API에 구현할 수 있습니다. 이전 장에서 이루어졌던 것과 유사하게, 쿼리를 해결하는 무거운 작업은 강력한 Prisma 엔진을 통하여 이루어질 겁니다. 그저 들어오는 쿼리를 잘 전달해주기만 하면 됩니다.
첫번째 할일은, API를 통하여 노출시킬 필터에 대하여 생각해보는 것입니다. 지금의 경우, API의 feed
쿼리는 필터링 문자열을 받을 수 있습니다. 이제 이 쿼리는 해당 필터링 문자열 상에 적힌 url
또는 description
을 포함하고 있는 Link
요소만을 반환합니다.
어플리케이션의 스키마를 열고
filter
문자열을feed
쿼리에 추가합니다.
($ .../hackernews-node/src/schema.graphql)type Query { info: String! feed(filter: String): [Link!]! }
다음으로, 클라이언트가 제공하는 새로운 인자를 처리할 수 있도록 feed
리졸버의 구현 내용을 수정해야 합니다.
src/resolvers/Query.js
를 열고feed
리졸버를 아래와 같이 수정합니다.
($ .../hackernews-node/src/resolvers/Query.js)async function feed(parent, args, context, info) { const where = args.filter ? { // 수정 OR: [ // 수정 { description_contains: args.filter }, // 수정 { url_contains: args.filter }, // 수정 ], // 수정 } : {} // 수정 // 수정 const links = await context.prisma.links({ // 수정 where }) return links }
filter
문자열이 제공되지 않는다면, where
객체는 단지 빈 객체가 되며 links
쿼리에 대한 응답을 반환할 때에 필터링을 위한 조건이 Prisma 엔진에 적용되지 않게 됩니다.
args
를 통하여 filter
가 전달되는 경우, 앞서 논의한 바오 같이 2개의 필터링 조건을 표현하는 where
객체를 구성하게 됩니다. 여기서 where
인자는 명시된 조건에 부합하지 않는 Link
요소를 걸러내기 위하여 Prisma가 사용합니다.
그 정도면 필터링 기능을 위하여 충분합니다! 필터링 API를 테스트해보도록 하죠. 아래는 예시로 사용할 수 있는 쿼리입니다.
query {
feed(filter:"QL") {
id
description
url
postedBy {
id
name
}
}
}
API 디자인에서 페이지네이션은 까다로운 주제 중 하나입니다. 페이지네이션을 구현하는 데에는 크게 두 가지 접근 방식이 사용됩니다.
Prisma는 두 가지의 페이지네이션 방식을 모두 지원합니다(이 문서에서 관련 내용을 확인할 수 있습니다). 이 튜토리얼에서는 Limit-Offset 방식의 페이지네이션을 구현해보도록 하겠습니다.
참고: 각각의 페이지네이션 방식에 대한 다양한 생각들은 이 문서에서 확인할 수 있습니다.
Limit과 Offset은 Prisma API 상에서 다르게 불립니다.
first
라고 불리며, 이는 제공된 시작 인덱스 이후에 등장하는 첫번째 x개의 요소를 가져온다는 의미입니다. 참고로, last
인자를 사용하면 마지막 x개의 요소를 반환하게 됩니다.skip
이라고 불리며, 이는 반환될 항목들을 모으기 전에 전체 목록 상에서 해당 개수 만큼의 요소를 건너뛴다는 의미입니다. skip
이 제공되지 않는다면, 기본값으로 0
이 사용됩니다. 이 경우 항상 전체 목록의 맨 처음부터 페이지네이션이 이루어집니다. last
와 함께 사용할 경우, 맨 끝부터 이루어집니다.자, 이제 feed
쿼리에 skip
과 first
인자를 추가해봅시다.
어플리케이션의 스키마를 열고,
skip
및first
인자를 받을 수 있도록feed
쿼리를 수정합니다.
($ .../hackernews-node/src/schema.graphql)type Query { info: String! feed(filter: String, skip: Int, first: Int): [Link!]! // 수정 }
이제, 리졸버 구현으로 넘어가겠습니다.
src/resolvers/Query.js
를 열고feed
리졸버의 구현을 아래와 같이 수정합니다.
($ .../hackernews-node/src/resolvers/Query.js)async function feed(parent, args, context, info) { const where = args.filter ? { OR: [ { description_contains: args.filter }, { url_contains: args.filter }, ], } : {} const links = await context.prisma.links({ where, skip: args.skip, // 수정 first: args.first // 수정 }) return links }
달라진 것이라곤 단지 이제 links
쿼리를 호출할 때, args
객체를 통하여 전달된 두 개의 추가적인 인자를 받을 수 있다는 점입니다. 이번에도 역시, Prisma가 우리를 대신하여 수고해줄 겁니다 🙏.
아래의 쿼리를 사용하여 페이지네이션 API를 테스트해보세요. 이 쿼리는 전체 목록에서 두 번째 Link
를 반환합니다.
query {
feed(
first: 1
skip: 1
) {
id
description
url
}
}
Prisma를 사용하면 요소들의 목록을 특정 기준에 따라 정렬하여 반환할 수 있습니다. 예를 들어, Link
의 목록을 url
또는 description
의 가나다 순 기준으로 정렬할 수 있습니다. Hacker News API의 경우, GraphQL 서버 상의 Prisma API가 어떤 정렬 방식을 사용할 것인지 등을 클라이언트 측에서 결정할 수 있도록 해줄 겁니다. 정렬 방식을 가리키는 열거자(enum
)을 사용하면 됩니다.
schema.graphql
에 아래의 열거자 정의를 추가합니다.
($ .../hackernews-node/src/schema.graphql)enum LinkOrderByInput { description_ASC description_DESC url_ASC url_DESC createdAt_ASC createdAt_DESC }
Link
요소가 정렬될 수 있는 다양한 방식들을 나타냅니다.
orderBy
인자를 포함하도록feed
쿼리를 수정합니다.
($ .../hackernews-node/src/schema.graphql)type Query { info: String! feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): [Link!]! // 수정 }
리졸버 구현은 앞서 페이지네이션 API 구현과 유사합니다.
src/resolvers/Query.js
의feed
리졸버 구현을 아래와 같이 수정하고, Prisma를 통하여orderBy
인자를 전달합니다.
($ .../hackernews-node/src/resolvers/Query.js)async function feed(parent, args, context, info) { const where = args.filter ? { OR: [ { description_contains: args.filter }, { url_contains: args.filter }, ], } : {} const links = await context.prisma.links({ where, skip: args.skip, first: args.first, orderBy: args.orderBy // 수정 }) return links }
아주 좋습니다! 아래의 쿼리는 반환된 링크들을 각각의 생성 일자를 기준으로 정렬합니다.
query {
feed(orderBy: createdAt_ASC) {
id
description
url
}
}
Link
요소의 총 개수 반환Hacker News API에서 마지막으로 구현할 것은 바로 Link
요소가 현재 데이터베이스 상에 몇 개가 저장되어있는지 알 수 있는 API입니다. 이를 위해서는 feed
쿼리를 약간 다듬고, API에서 반환할 새로운 타입 Feed
를 만들어야 합니다.
GraphQL 스키마에 새로운 타입
Feed
를 추가합니다. 이에 맞추어feed
쿼리의 반환 타입도 수정합니다.
($ .../hackernews-node/src/schema.graphql)type Query { info: String! feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): Feed! // 수정 } type Feed { // 수정 links: [Link!]! // 수정 count: Int! // 수정 } // 수정
이제,
feed
리졸버를 수정합니다.
($ .../hackernews-node/src/resolvers/Query.js)async function feed(parent, args, context) { // 1 const where = args.filter ? { OR: [ { description_contains: args.filter }, { url_contains: args.filter }, ], } : {} const links = await context.prisma.links({ where, skip: args.skip, first: args.first, orderBy: args.orderBy, }) const count = await context.prisma // 수정 // 2 .linksConnection({ // 수정 where, // 수정 }) // 수정 .aggregate() // 수정 .count() // 수정 // 3 return { // 수정 links, // 수정 count, // 수정 } // 수정 }
가장 첫번째로, 필터링, 정렬, 페이지네이션을 위하여 제공된 인자를 사용하여 Link
요소의 개수를 반환할 때에 사용할 객체를 만들고 있습니다.
다음으로, Prisma 클라이언트 API의 linksConnection
쿼리를 사용합니다. 이를 통하여 현재 데이터베이스 상에 저장된 Link
요소의 총 개수를 가져올 수 있습니다.
links
와 count
는 GraphQL 스키마 상에 추가된 Feed
타입의 명세와 부합하도록 하나의 객체로 감싸집니다.
이제 마지막으로, GraphQLServer
를 인스턴스화 할 때 새로운 리졸버를 포함시키면 됩니다.
새로 고친 feed
쿼리를 아래와 같이 테스트해보세요.
query {
feed {
count
links {
id
description
url
}
}
}
Quiz
Limit-Offet 페이지네이션을 사용할 때 Prisma API에서 주로 사용되는 인자는 무엇인가?
- skip & last
- skip & first
- first & last
- where & orderBy