Node.js - GraphQL API 만들기

Temporary·2024년 7월 12일
0

Nods.js

목록 보기
7/39
post-thumbnail

GraphQL-API 만들기

Apollo server를 통해 어떤 방식으로 객체가 생성되고 반환되는지를 직접 확인했으니, 이제 API를 직접 작성해보자

지금 작업한 03-06-graphql-api-with-apollo-server 폴더를 복사해서
03-07-graphql-api-with-apollo-server-board로 변경해준다.
(node_modules는 제외)

node_modules는 제외하고 복사했으니 다시 yarn install을 해야한다.

CORS 적용

ApolloServer 내에 적용시켜줘야 한다.

// index.js

const app = new ApolloServer({
  typeDefs: typeDefs,
  resolvers: resolvers,
  cors: true,  // 모든 사이트 허용하고 싶을 때
  // cors: { origin: ["https://naver.com", "https://daum.net"] } // 특정 사이트만 지정하고 싶을 때
});

cors: true 로 설정하면 모든 사이트에 대해 접속을 허용한다는 의미이고,
cors: {origin:"url"} 로 설정하면 특정 origin만 접속을 허용한다는 의미이다.

GraphQL-API 만들기

이전 GraphQL-API를 연습할 때 확인했던 fetchBoardscreateBoard API를 직접 만들어보자

그 전에, 다시 한번 상기하자면 resolvers 부분이 express의 API와 같고, typeDefs는 api-docs를 구성하고 응답으로 돌려줄 타입을 정의해주는 부분이다.

GraphQL을 통해 api 를 생성할 떄는 api를 정의해주는 resolvers와 그 api의 docs를 정의해주는 typeDefs 2개를 정의해줘야 한다.

fetchBoards API 생성

index.js 파일의 내용을 수정하여 Query API인 fetchBoards를 만들어보자

Rest API에서는 GET 메서드(app.get)를 사용해서 데이터를 조회해서 반환해 주었다.

동일한 데이터를 반환하는 기능을 GraphQL-API로 변경해 보자.

// index.js

const resolvers = {
  Query: {
    fetchBoards: (_, args) => {
      // 게시글 목록조회
      // 1. DB에 접속 후 데이터를 조회 => 데이터를 조회했다고 가정
      const result = [
        {
          number: 1,
          writer: "tom",
          title: "tom and jerry",
          contents: "contents",
        },
        {
          number: 2,
          writer: "jerry",
          title: "tom and jerry",
          contents: "this is jerry",
        },
        {
          number: 3,
          writer: "glue",
          title: "this is title",
          contents: "this is glue",
        },
      ];

      // 2. DB에서 꺼내온 결과를 브라우저에 응답으로 주기 (return)
      return result;
    },
  },
}

Query 내부에 데이터를 조회하는 로직을 작성해야 한다.

Rest-API에서는 res.send를 이용해서 데이터를 반환했는데 graphql-API는 return을 사용해 함수를 종료하면서 데이터를 반환한다

resolvers 에서 반환되는 값들의 type 또한 typeDefs에서 지정해 주어야 한다.

resolvers 에 작성한 Query의 fetchBoards 함수의 반환값을 한번 확인해보자

# index.js

const typeDefs = `#graphql
    type myResultType { 
		# {number: ~, writer: ~~,,,,} <- 1 개를 의미한다.
        number: Int
        writer: String
        title: String
        contents: String
    }

  type Query {
        # fetchBoards: myResultType # 객체 1개를 의미함
        fetchBoards: [myResultType] # 배열 안에 객체 1개이상을 의미한다.
    }
`;

fetchBoards api의 반환값은 배열 안에 객체의 형태로 이루어져 있다.

먼저 객체의 타입을 지정해주기 위해서 type MyResult {}의 선언해주고 요소의 타입들 지정해야 한다.

객체안의 요소들의 타입을 모두 지정해 주었다면 MyResult을 배열로 감싸서 fetchBoards: [MyResult] 과 같이 지정해 준다.

다시 서버를 실행시켜 주고 localhost:4000/graphql 로 접속하여 기존과 동일하게 API 테스트를 해보자

# index.js

query {
  fetchBoards {
    number
    writer
    title
    contents
  }
}

resolvers 객체 안의 Query 객체에 작성해 놓은 fetchBoards 함수가 실행되면서 type Query에 지정해 놓은 타입과 type MyResult에 지정해 놓은 타입에 맞게 데이터의 결과 값이 반환 된 것을 확인할 수 있다.

createBoard API 생성

이번엔 게시글 등록 API를 만들어 보자. 게시글 등록은resolvers 객체 안에 Mutation 객체를 생성하면 된다.

생성된 함수를 통하여 입력값을 받아 올 수 있는데, 이 함수는 4개의 매개변수(parameter)를 가질 수 있다.

// index.js

const resolvers = {
  Mutation: {
    createBoard: (parent, args, context, info) => {
     
    },
  },
};

4개의 매개변수는 다음과 같은 역할을 한다.

  • parent : 부모 타입 resolver에서 반환된 결과를 가진 객체
  • args : 쿼리 요청 시 전달된 parameter를 가진 객체
  • context : GraphQL의 모든 resolver가 공유하는 객체로서 로그인 인증, 데이터베이스 접근 권한 등에 사용
  • info : 명령 실행 상태 정보를 가진 객체

Rest-API에서는 요청 데이터를 확인하기 위해 매개변수로 req를 사용했다.

GraphQL-API에서는 4개의 매개변수 중 요청 데이터를 확인 가능한 args를 사용하여 입력값을 가져오겠다. 사용하지 않는 매개변수는 _(언더바)로 선언하는 것을 기억해 두자.

// index.js

const resolvers = {
  Query: {
    fetchBoards: () => {
      // ...
    },
  },

  Mutation: {
    // graphql 은 (req, res) 가 아니라 (parent, args, context, info)가 들어온다.
    createBoard: (_, args) => {
      // 1. 브라우저에서 보내준 데이터를 확인하기
      console.log(args.createBoardInput.writer);
      console.log(args.createBoardInput.title);
      console.log(args.createBoardInput.contents);

      // 다른 백엔드에서 요청할때는 parent 로 들어오게 된다.

      return "게시글 등록에 성공하였습니다!";
    },
  },
};

이번에는 요청 데이터의 타입을 지정해 보자.

이 때, 유저가 입력하는 데이터의 타입을 지정하기 위해서는 type이 아니라

다음과 같이 input을 사용해 데이터의 타입을 지정해준다.

# index.js

const typeDefs = gql`
    # return 타입엔 type 이라고 쓰지만
    # 입력값으로 들어오는 input 에는 type 이 아니라 input 이라고 적어야한다.
    input CreateBoardInput {
        writer: String
        title: String
        contents: String
    }

    type Mutation { 
		# writer, title, contents 3개가 들어간다면
        # 만일 필수입력으로 받고 싶다면 ! 를 붙이면 된다.
        # createBoard(writer: String, title: String, contents: String!): String

        createBoard(createBoardInput: CreateBoardInput!): String 
		# ! 를 붙여 필수입력하게 해둠, return 은 string 타입
    }
`;

다시 apollo server를 실행시켜 주고 localhost:4000/graphql 로 접속하여 기존과 동일하게 API 테스트를 해보자.

# index.js

mutation {
  createBoard(createBoardInput: {
    writer: "안녕하세요",
    title: "제목 연습용",
    contents: "글자 연습용!"
  })
}

이 떄, createBoard를 사용할 때는
createBoard

아까 적어놓았듯이, input CreateBoardInput에 지정해 놓은 요소들의 데이터 타입에 맞게 요청을 보내야 한다.

resolvers 라는 객체 안의 Mutation 객체에 작성해 놓은 createBoard함수가 실행된다.

이 때, type Mutation 에 지정해 놓은 타입에 맞게 입력값을 받게 되면 결과 응답 메세지가 잘 반환되는 것을 확인할 수 있다.

입력 요청 값이 잘 들어왔는지 터미널을 통해 출력된 값을 확인해 보자

profile
Temporary Acoount

0개의 댓글