애플리케이션을 설계할 때 고려해야 할 가장 중요한 요소 중 하나는 사용할 API 아키텍처의 유형입니다. 효율적인 API 설계는 앱의 수명 주기 동안 성능을 보장하는 데 매우 중요합니다.
RESTful 아키텍처는 가장 널리 사용되는 접근 방식이지만, 미리 결정된 데이터를 반환하는 고정된 엔드포인트 구조라는 한 가지 중요한 단점이 있습니다. 이러한 설계는 비효율적인 통신을 초래할 수 있습니다.
이와는 대조적으로 REST의 대안인 GraphQL은 필요한 데이터만 요청할 수 있어 더 많은 유연성을 제공합니다.
GraphQL API란 무엇인가요?
GraphQL 은 백엔드 API(애플리케이션 프로그래밍 인터페이스)를 작성하는 데 사용할 수 있는 쿼리 언어입니다. 서로 다른 데이터에 대해 여러 개의 엔드포인트가 있는 REST API와 달리 GraphQL API에는 하나의 엔트리 포인트만 있습니다.
클라이언트는 이 단일 엔트리 포인트에서 쿼리에 필요한 데이터를 지정할 수 있으므로 필요한 데이터만 검색할 수 있어 더욱 유연하고 효율적입니다.
간단히 말해, GraphQL API는 GraphQL 사양 에 설명된 GraphQL 아키텍처를 구현합니다. 이 설계에는 클라이언트가 상호 작용할 수 있는 스키마, 쿼리 및 변형을 정의하는 것이 포함됩니다.
다음은 GraphQL API 아키텍처의 필수 구성 요소에 대한 단순화된 분석입니다:
⭐ 스키마: 스키마는 API가 제공하는 데이터 및 작업 유형에 대한 설명입니다. 기본적으로 스키마는 사용 가능한 데이터의 구조와 클라이언트가 데이터를 수정하기 위해 실행할 수 있는 쿼리 및 변경 유형을 정의합니다.
⭐ 쿼리: 클라이언트는 쿼리를 사용하여 필요한 데이터의 구조를 지정하여 데이터베이스에서 데이터를 가져옵니다. 또한 단일 HTTP 요청에 여러 쿼리를 중첩하여 여러 엔드포인트에서 관련 데이터를 가져올 수 있습니다.
⭐ 돌연변이: 변경은 데이터베이스의 데이터를 수정하는 데 사용되는 작업입니다. 클라이언트는 데이터를 생성, 업데이트 또는 삭제하기 위해 변경 요청을 보낼 수 있습니다.
MongoDB 데이터베이스 설정
시작하려면 MongoDB 데이터베이스를 만듭니다. 또는 클라우드에서 무료로 MongoDB 클러스터를 설정할 수 있습니다. 데이터베이스를 설정했으면 MongoDB의 데이터베이스 연결 URI 문자열을 복사합니다.
이 프로젝트의 코드는 GitHub 리포지토리에서 찾을 수 있습니다.
Apollo 서버 만들기
Apollo 서버 은 Node.js, Express 등을 포함한 JavaScript 환경에서 GraphQL API를 빌드할 수 있도록 해주는 널리 사용되는 GraphQL 서버 구현입니다.
새 프로젝트의 디렉터리를 만들고 그 안에 복사하세요:
mkdir graphql-API-mongoDB
cd graphql-API-mongoDB
다음으로, 새 Node.js 프로젝트를 초기화합니다.
npm init --yes
이 명령은 package.json 파일을 생성합니다.
필수 종속성 설치
다음 명령을 실행하여 패키지를 설치합니다.
npm install apollo-server graphql mongoose
마지막으로 프로젝트의 루트 디렉터리에 index.js 파일을 생성합니다.
Apollo 서버 설정
index.js를 열고 아래 코드를 추가합니다:
const { ApolloServer } = require('apollo-server');
const mongoose = require('mongoose');
const typeDefs = require("./graphql/typeDefs");
const resolvers = require("./graphql/resolvers");
const server = new ApolloServer({
typeDefs,
resolvers
});
const MONGO_URI = 'mongodb://localhost:27017';
mongoose
.connect(MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log(`Db Connected`);
return server.listen({ port: 5000 });
})
.then((res) => {
console.log(`Server running at ${res.url}`);
})
.catch(err => {
console.log(err.message);
});
이 코드는 Apollo Server 라이브러리를 사용하여 로컬 GraphQL 서버를 초기화합니다. 그런 다음 주어진 연결 URI를 사용하여 MongoDB 데이터베이스에 대한 연결을 설정합니다.
이 코드가 ApolloServer의 새 인스턴스에 두 개의 인자, 즉 typeDefs와 resolver를 전달하는 방식을 주목하세요. 이는 GraphQL API가 실행할 수 있는 데이터 유형과 연산을 지정합니다.
MongoDB 데이터베이스에 대한 연결이 설정된 후 서버는 포트 5000에서 수신 대기하기 시작합니다.
데이터 모델 정의
프로젝트 폴더의 루트 디렉터리에 새 폴더를 만들고 이름을 models로 지정합니다. 이 폴더에 데이터모델.js라는 이름의 새 파일을 만들고 다음 코드를 추가합니다:
const {model, Schema} = require('mongoose');
const employeeSchema = new Schema({
name: String,
department: String,
salary: String,
});
module.exports = model('Employee', employeeSchema);
GraphQL 스키마 정의
GraphQL 스키마는 GraphQL API를 사용하여 쿼리할 수 있는 데이터의 구조를 정의합니다. 스키마는 또한 API가 실행할 수 있는 쿼리 및 변형을 간략하게 설명합니다. 쿼리를 사용하여 데이터를 가져오고 변형을 사용하여 데이터를 수정할 수 있습니다.
프로젝트의 루트 디렉터리에 새 폴더를 만들고 이름을 graphql로 지정합니다. 이 폴더 안에 typeDefs.js와 resolvers.js 두 파일을 추가합니다.
typeDefs.js 파일에 아래 코드를 추가합니다:
const {gql} = require("apollo-server");
const typeDefs = gql`
type Employee {
id: ID!
name: String
department: String
salary: String
}
input EmployeeInput {
name: String
department: String
salary: String
}
type Query {
getEmployee(id: ID): Employee #return Employee by id
employees: [Employee] #return array of Employees
}
type Mutation {
createEmployee(employeeInput: EmployeeInput): Employee
updateEmployee(id: ID, employeeInput: EmployeeInput): Boolean
deleteEmployee(id: ID): Boolean
}
`;
module.exports = typeDefs;
위의 코드는 apollo-server 패키지에서 제공하는 gql 함수를 사용하여 Employee 데이터에 대한 GraphQL 스키마를 만듭니다.
스키마는 직원 정보에 대한 데이터 유형, 입력 유형, 쿼리 및 API가 수행할 수 있는 변이의 네 가지 주요 요소로 구성됩니다.
GraphQL API에 대한 리졸버 정의
리졸버는 클라이언트가 데이터를 가져오기 위해 API 쿼리를 보낼 때 전달할 데이터를 정의하는 GraphQL 함수입니다. 기본적으로 리졸버의 주요 역할은 지정된 데이터 소스에서 필요한 데이터를 검색하여 클라이언트에 반환하는 것입니다.
graphql 폴더의 resolvers.js 파일에 아래 코드를 추가합니다. 이 경우 리졸버는 쿼리 및 돌연변이 객체 내에 지정됩니다.
Query 객체는 employees와 getEmployee라는 두 가지 메서드를 정의합니다. 이 메서드는 클라이언트의 요청에 따라 데이터베이스에서 직원 데이터를 가져오는 역할을 담당합니다.
const Employee= require("../models/employeesModel");
// GraphQL Resolvers
const resolvers = {
Query: {
employees: async () => {
try {
const employees = await Employee.find({});
return employees;
} catch (error) {
console.error(error);
throw new Error('Failed to fetch employees');
}
},
getEmployee: async (parent, args) => {
try {
const employee = await Employee.findById(args.id);
return employee;
} catch (error) {
console.error(error);
throw new Error('Failed to fetch employee by ID');
}
},
},
Mutation 객체에는 createEmployee, updateEmployee 및 deleteEmployee의 세 가지 메서드가 있습니다. 이 메서드들은 MongoDB 데이터베이스에 저장된 데이터를 변경합니다.
Mutation: {
async createEmployee (_, { employeeInput: { name, department, salary } }) {
const newEmployee = new Employee({
name: name,
department: department,
salary: salary
});
const response = await newEmployee.save();
console.log(newEmployee);
return {
id: response._id,
...response._doc
}
},
async updateEmployee (_, {id, employeeInput: {name, department, salary}}) {
const updatedEmployee = await Employee.updateOne(
{ _id: id },
{ name, department, salary }
);
if (!updatedEmployee) {
throw new Error(`Employee with ID: ${id} not found`);
}
return true; // Return a boolean value indicating update success
},
async deleteEmployee (_, {id}) {
const deletedEmployee = await Employee.deleteOne({ _id: id });
if (!deletedEmployee || deletedEmployee.deletedCount === 0) {
throw new Error(`Employee with ID ${id} not found`);
}
return true; // Return a boolean value indicating deletion success
},
},
};
module.exports = resolvers;
마지막으로 이 명령을 실행하여 서버를 스핀업합니다:
node index.js
데이터베이스 연결이 설정되면 서버가 포트 5000에서 시작됩니다.
브라우저의 GraphQL 플레이그라운드에서 HTTP 요청을 수행하여 GraphQL API의 기능을 테스트할 수 있습니다.
예를 들어, createEmployee 변형을 사용하여 MongoDB 데이터베이스에 새 직원 데이터를 추가할 수 있습니다.
개발자 커뮤니티에서의 GraphQL 인기
GraphQL은 널리 사용되는 REST 아키텍처에 대한 대체 API 설계 접근 방식으로 개발자 커뮤니티에서 주목을 받고 있습니다.
이는 단일 진입점에서 다양한 소스에서 데이터를 검색할 수 있는 보다 유연하고 효율적인 방법을 제공하기 때문입니다. 따라서 REST API 아키텍처의 일반적인 문제인 서로 다른 데이터에 대해 여러 엔드포인트를 관리할 필요가 없습니다. 이 설계 솔루션은 백엔드 API 구축 및 관리 프로세스를 간소화합니다.