애플리케이션을 설계할 때 고려해야 할 가장 중요한 요소 중 하나는 사용할 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 문자열을 복사합니다.

이 글도 확인해 보세요:  웹 개발을 위한 가장 인기 있는 8가지 백엔드 프레임워크

이 프로젝트의 코드는 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의 기능을 테스트할 수 있습니다.

이 글도 확인해 보세요:  Reqwest로 Rust에서 HTTP 요청 만들기

예를 들어, createEmployee 변형을 사용하여 MongoDB 데이터베이스에 새 직원 데이터를 추가할 수 있습니다.

개발자 커뮤니티에서의 GraphQL 인기

GraphQL은 널리 사용되는 REST 아키텍처에 대한 대체 API 설계 접근 방식으로 개발자 커뮤니티에서 주목을 받고 있습니다.

이는 단일 진입점에서 다양한 소스에서 데이터를 검색할 수 있는 보다 유연하고 효율적인 방법을 제공하기 때문입니다. 따라서 REST API 아키텍처의 일반적인 문제인 서로 다른 데이터에 대해 여러 엔드포인트를 관리할 필요가 없습니다. 이 설계 솔루션은 백엔드 API 구축 및 관리 프로세스를 간소화합니다.

By 최은지

윈도우(Windows)와 웹 서비스에 대한 전문 지식을 갖춘 노련한 UX 디자이너인 최은지님은 효율적이고 매력적인 디지털 경험을 개발하는 데 탁월한 능력을 발휘합니다. 사용자의 입장에서 생각하며 누구나 쉽게 접근하고 즐길 수 있는 콘텐츠를 개발하는 데 주력하고 있습니다. 사용자 경험을 향상시키기 위해 연구를 거듭하는 은지님은 All Things N 팀의 핵심 구성원으로 활약하고 있습니다.