반응형
📝Apollo Server
- GraphQL코드를 효율적으로 관리하는데 도움을 줍니다
- GraphQL의 Query, Type 등 문서화하는데 도움을 줍니다
- Sandbox를 제공해 직접 GraphQL 테스트도 가능합니다
- 최적화 기능도 제공합니다
Graphql을 개발한 Meta에서 만든 Relay라는게 있지만 학습비용이 높고 React계열만 지원한다는 단점이 존재한다 그에 비해 Apollo는 유연하고 러닝커브가 높지 않다
📝리졸버
Apollo Server가 Graphql 작업 처리하는 방법입니다
요청이 들어오면 그에 따라 비즈니스 로직을 처리해 결과를 반환해주는 역할입니다
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
// Hardcoded data store
const books = [
{
title: 'The Awakening',
author: 'Kate Chopin',
},
{
title: 'City of Glass',
author: 'Paul Auster',
},
];
// Schema definition
const typeDefs = `#graphql
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
// Resolver map
const resolvers = {
Query: {
books() {
return books;
},
},
};
// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({
typeDefs,
resolvers,
});
// Launch the server
const { url } = await startStandaloneServer(server);
console.log(`🚀 Server listening at: ${url}`);
위에 예시 코드의 경우 resolvers에서 books Query에 대한 리턴을 정의합니다 그 이후에 server에 스키마와 resolver를 등록합니다
📝리졸버 체이닝
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
const libraries = [
{
branch: 'downtown',
},
{
branch: 'riverside',
},
];
// The branch field of a book indicates which library has it in stock
const books = [
{
title: 'The Awakening',
author: 'Kate Chopin',
branch: 'riverside',
},
{
title: 'City of Glass',
author: 'Paul Auster',
branch: 'downtown',
},
];
// Schema definition
const typeDefs = `#graphql
# A library has a branch and books
type Library {
branch: String!
books: [Book!]
}
# A book has a title and author
type Book {
title: String!
author: Author!
}
# An author has a name
type Author {
name: String!
}
# Queries can fetch a list of libraries
type Query {
libraries: [Library]
}
`;
// Resolver map
const resolvers = {
Query: {
libraries() {
// Return our hardcoded array of libraries
return libraries;
},
},
Library: {
books(parent) {
// Filter the hardcoded array of books to only include
// books that are located at the correct branch
return books.filter((book) => book.branch === parent.branch);
},
},
Book: {
// The parent resolver (Library.books) returns an object with the
// author's name in the "author" field. Return a JSON object containing
// the name, because this field expects an object.
author(parent) {
return {
name: parent.author,
};
},
},
// Because Book.author returns an object with a "name" field,
// Apollo Server's default resolver for Author.name will work.
// We don't need to define one.
};
// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({
typeDefs,
resolvers,
});
// Launch the server
const { url } = await startStandaloneServer(server);
console.log(`🚀 Server listening at: ${url}`);
// 호출
query GetBooksByLibrary {
libraries {
books {
title
author {
name
}
}
}
}
리졸버 체이닝이란 리졸버의 결과가 다음 리졸버의 입력으로 연결되는 패턴입니다
위 예시 코드에 대해 설명하면 Query Libraries에 대한 정의를 하고 해당 리턴의 타입인 [Library]의 값 받습니다 그 이후 결과값을 받아 Library 타입 안에 속하는 books의 타입인 [Book]의 값을 정의합니다
이렇게 이어받아서 작업하는 걸 리졸버 체이닝이라고합니다
아래는 리졸버 체이닝에 쓰이는 인자값 입니다
parent | 이전 리졸버의 반환값입니다. |
args | 이 필드 에 제공된 모든 GraphQL 인수를 포함하는 객체입니다 . 예를 들어 를 실행할 때 리졸버에 전달되는 객체 query{ user(id: "4") }는 입니다. argsuser { "id": "4" } |
contextValue | 특정 작업을 실행하는 모든 확인자 간에 공유되는 개체입니다. 이를 사용하여 인증 정보, 데이터로더 인스턴스 및 확인자 전체에서 추적할 기타 항목을 포함하여 작업별 상태를 공유합니다. |
info | 필드 이름, 루트에서 필드까지의 경로 등을 포함하여 작업 실행 상태 에 대한 정보가 포함되어 있습니다 . |
contextValue 예시
import { GraphQLError } from 'graphql';
const resolvers = {
Query: {
// Example resolver
adminExample: (parent, args, contextValue, info) => {
if (contextValue.authScope !== ADMIN) {
throw new GraphQLError('not admin!', {
extensions: { code: 'UNAUTHENTICATED' },
});
}
},
},
};
interface MyContext {
// You can optionally create a TS interface to set up types
// for your contextValue
authScope?: String;
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
// Your async context function should async and
// return an object
context: async ({ req, res }) => ({
authScope: getScope(req.headers.authorization),
}),
});
contextValue 예시 2
context: async () => ({
db: await client.connect(),
})
// Resolver
(parent, args, contextValue, info) => {
return contextValue.db.query('SELECT * FROM table_name');
}
contextValue 예시 3
import { AnimalAPI } from './datasources/animals';
const resolvers = {
Query: {
// All of our resolvers can access our shared contextValue!
dogs: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getDogs();
},
cats: (_, __, contextValue) => {
return contextValue.dataSources.animalApi.getCats();
},
},
};
interface MyContext {
// Context typing
dataSources: {
animalApi: AnimalAPI;
};
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
context: async () => {
const animalApi = new AnimalAPI();
return {
dataSources: {
animalApi,
},
};
},
});
contextValue통해 공유 객체에 액세스할 수 있습니다
반응형