GraphQL CRUD (Server)

하성화·2022년 5월 12일
0

Mongoose 스키마 작성

Mongoose는 작성된 스키마를 기준으로 데이터를 검증하기 때문에 데이터를 다루기 위해선 스키마가 필요하다.

// server/models/Book.js
import mongoose from "mongoose";
const Schema = mongoose.Schema;

const bookSchema = new Schema(
  {
    title: String,
    author: String,
  },
);

const Book = mongoose.model("book", bookSchema);
export default Book;

기본적으로 Mongoose는 스키마에 id속성을 가지고 있어 따로 추가하지 않아도 된다.
Schema 메서드를 통해 스키마를 정의하고, model 메서드를 통해 모델로 변환해야한다.

GraphQL 스키마, 리졸버 수정

코드의 가독성을 위해 server/index.js에 있는 스키마와 리졸버의 내용을 typeDefs.js와 resolver.js로 나누었다.

// server/typeDefs.js
import { gql } from "apollo-server-express";

const typeDefs = gql`
  type Book {
    id: ID
    title: String
    author: String
  }
  type Query {
    getBooks: [Book]
  }
  type Mutation {
    // ...
  }
`;

export default typeDefs;

GraphQL 스키마의 가장 기본구성 요소인 객체 타입을 정의한다. 객체 타입은 서비스에서 가져올 수 있는 객체의 종류와 그 객체의 필드를 나타낸다.
모든 GraphQL 서비스는 query 타입을 가지며 mutation 타입은 가질 수도 있고 가지지 않을 수도 있다. query 타입은 데이터를 받아오는(R) 작업을, mutation 타입은 데이터를 변경하는(CUD)의 작업을 수행한다.

// server/resolver.js
const books = [
  {
    title: "The Awakening",
    author: "Kate Chopin",
  },
  {
    title: "City of Glass",
    author: "Paul Auster",
  },
];

const resolvers = {
  Query: {
    getBooks: () => {
      return books;
    },
  },
};

export default resolvers;

리졸버는 스키마의 필드에 데이터를 채우는 역할을 한다. 지금은 데이터를 하드코딩으로 넘겨주고 있다.

GraphQL CRUD

  1. CRUD 타입정의

    // server/typeDefs.js
    import { gql } from "apollo-server-express";
    
    const typeDefs = gql`
      type Book {
        id: ID
        title: String
        author: String
      }
      type Query { // Read
        getBooks: [Book]
        getBook(id: ID): Book
      }
      type Mutation { // CREATE, DELETE, UPDATE
        addBook(title: String, author: String): Book
        deleteBook(id: ID): String
        updateBook(id: ID, title: String, author: String): Book
      }
    `;
    
    export default typeDefs;

    getBooks은 전체 Book의 내용을 읽는다.
    getBook은 인자로 받은 id값과 일치하는 하나의 Book을 읽는다.

    addBook은 하나의 Book을 인자로 받은 값으로 추가하고, 추가된 Book을 반환한다.
    deleteBook은 인자로 받은 id값과 일치하는 하나의 Book을 삭제하고, 성공 메시지를 반환한다.
    updateBook은 인자로 받은 id값과 일치하는 Book의 내용을 수정하고, 수정된 Book을 반환한다.

  2. Query (getBooks, getBook)

    // server/resolver.js
    import Book from "./models/Book.js";
    const resolvers = {
      Query: {
        getBooks: async () => {
          const books = await Book.find();
          return books;
        },
        getBook: async (root, args) => {
          const book = await Book.findById(args.id);
          return book;
        },
      },
    },

    resolver에서 MongoDB의 model을 사용하려면 정의된 model을 가져와야 한다.
    find 메서드를 통해 Book에 있는 필드들을 얻을 수 있다.
    findById 메서드를 통해 인자로 받은 id에 해당하는 필드를 얻을 수 있다.

  3. Mutation (addBook, deleteBook, updateBook)

    // server/resolver.js
    import Book from "./models/Book.js";
    const resolvers = {
      addBook: async (root, args) => {
        const newBook = new Book({
          title: args.title,
          author: args.author,
        });
        await newBook.save();
        return newBook;
      },
      
      deleteBook: async (root, args) => {
        await Book.findByIdAndDelete(args.id);
        return "Delete Success";
      },
      
      updateBook: async (root, args) => {
        const { id, title, author } = args;
        const updatedBook = {};
        if ( title !== undefined ) {
          updatedBook.title = title;
        }
        if ( author !== undefined ) {
          updatedBook.author = author;
        }
        const book = await Book.findByIdAndUpdate(id, updatedBook, { new: true });
        return book;
      },
    },

    addBook: 새로운 Book을 정의하고 save 메서드를 통해 새로운 필드를 저장한다.
    deleteBook: 삭제하려는 필드의 id를 받아 findByIdAndDelete를 통해 삭제한다.
    updateBook: 업데이트하려는 필드의 정보를 받아 findByIdAndUpdate를 통해 저장한다.
    Update를 실행한 뒤의 정보를 받고 싶다면 new 옵션을 사용해야 한다.

실습 (Sandbox)

<서버 주소>/graphql로 접속하면 apollo에서 제공하는 Sandbox를 사용하여 쿼리를 작성할 수 있다.

  1. Create
    addBox를 실행했을 때 DB에 해당하는 data가 들어간 것을 확인할 수 있다.

    SandboxMongoDB
  2. Read
    getBooks과 getBook을 실행 했을 때 응답으로 Book필드가 넘어온것을 확인할 수 있다.

  3. Delete
    넘겨준 id값에 해당하는 필드(title: The Awakening)가 삭제된 것을 확인할 수 있다.

    SandboxMongoDB
    수행 전 수행 후
  4. Update
    넘겨준 id값에 해당하는 필드(title: The Awakening)의 값이 수정된 것을 확인할 수 있다.

    SandboxMongoDB
    수행 전 수행 후

참고 문헌
GraphQL 스키마 & 타입
https://graphql-kr.github.io/learn/schema/
GraphQL schema basics
https://www.apollographql.com/docs/apollo-server/schema/schema/
Resolvers
https://www.apollographql.com/docs/apollo-server/data/resolvers

0개의 댓글