[apollo-server] API 만들기

이주희·2022년 4월 9일
0

BackEnd

목록 보기
6/14

API 생성 및 서버 열어두기

server.listen()

listen : 브라우저에서 api를 요청할 수 있도록 백엔드 서버를 24시간 동안 접속 가능하게 대기상태로 만들어준다.

rest-API는 express, nest.js 프레임워크를 사용하고 graphQL-API는 Apollo-server를 사용한다.

[Apollo-server]

0. TypeORM 설치 및 DB 연동

1. ApolloServer & graphQL 설치

yarn add apollo-server graphql

2. [Docs]에서 내용 가져오기

3. import 형태 변경

import { ApolloServer, gql } from "apollo-server";

4. entity 생성

Board.postgres.ts

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Board extends BaseEntity {
  @PrimaryGeneratedColumn("increment")
  number!: number;

  @Column({ type: "text" })
  writer!: string;

  @Column({ type: "text" })
  title!: string;

  @Column({ type: "text" })
  contents!: string;
}
  • @: 데코레이터 함수, typeORM에게 테이블임을 알려준다.
  • extends BaseEntity: 추가/삭제하는 기능을 포함한 데이터베이스 테이블이 된다.
  • { type: "text" }: postgres database의 column타입을 넣어준다.
    int, text ...
  • PrimaryGeneratedColumn("increment"): 중복되지 않는 자동으로 증가하는 컬럼
  • PrimaryGeneratedColumn("uuid"): universial unique id(중복되지 않는 고유한 아이디가 자동으로 만들어진다.)

5. typeDefs(API type) 작성

  • index.ts gql에는 graphQL 타입을 적어주고,
  • Boards.postgres.ts Entity를 정의할 때는 TypeScript의 타입을 적어준다.
const typeDefs = gql`
  type Query {
    # 리턴 타입을 적어준다.
    # !를 붙이면 필수값이 된다.
    # 값이 배열 안에 들어있으면 [] 안에 넣어준다.
    fetchBoards: [Board!]
  }
  # 타입을 만들어서 지정해 줄 수 있다.
  type Board {
    number: Int
    writer: String
    title: String
    contents: String
  }
  type Mutation {
    # 받아올 데이터의 타입(요청시 입력값)과 리턴할 데이터의 타입을 적는다.
    createBoard(createBoardInput: CreateBoardInput!): String # (backend06)
  }
  # input데이터(프론트에서 전달 받는 데이터)는 type이 아닌 input으로 쓴다.
  input CreateBoardInput {
    writer: String
    title: String
    contents: String
  }
`;

6. resolver(API) 작성

  • Entity(Board.postgres.ts)가 BaseEntity를 상속받고 있어야 insert, find 등을 사용할 수 있다.
const resolvers = {
  /* 조회 */
  Query: {
    fetchBoards: async () => {
      const result = await Board.find();
      return result;
    },
  },
  /* 등록 */
  Mutation: {
    createBoard: async (_: any, args: any) => {
      await Board.insert({
        ...args.createBoardInput,
      });

      /* 수정 */
      // 앞에 조건, 뒤에 변경 내용을 적어준다.
      Board.update({ writer: "철수" }, { title: "제목2" });

      /* 삭제 */
      Board.delete({ writer: "철수" });
      // Board.update({writer:"철수"}, {deletedAt: new Date()}); // soft-delete 방식

      return "게시물을 등록했습니다.";
    },
  },
};

  • parent: api 안에서 다른 api를 요청할 때, 인자로 받는 값으로 사용된다.
    여기서는 args만 사용할 거라서 parent는 _로 처리했다.
  • args : 받아온 데이터. 프론트를 통해서 받아온다.
  • context : header에 들어가는 요약 정보, http 요청에 대한 정보들
  • info : API에 대한 기타 정보들

7. ApolloServer 서버 만들기

typeDefs resolver

  • 위에서 만든 타입과 api를 입력한다. (Docs에서 가져온 내용에 입력되어 있음)

cors: true

  • cors를 true로 지정하면 주소가 다른 브라우저에서도 api 활용이 가능해진다.
  • 주소를 명시하면 해당 주소만 접속이 가능하게 만들 수 있다.
  cors: {
    origin: 'http://naver.com' // 이 주소에서만 접속 가능
  },

8. 서버 열어주기

  • listen 위치를 변경한다.
    (연결이 성공하면 대기상태가 되도록 만든다.)
  • listen() 안에 접속할 포트번호를 지정할 수 있다.

9. package.json 실행할 파일 지정

"dev": "ts-node-dev index.ts"

  • 위 내용을 입력한 파일명이 입력되어 있는지 확인한다.

10. 터미널에서 yarn dev로 실행

yarn dev

  • liste() 안에 입력한 포트번호로 실행된다.

11. 브라우저에서 접속


전체 코드
class_backend/index.ts

import { DataSource } from "typeorm";
import { Board } from "./Board.postgres";
/* import 형태로 변경 */
// const { ApolloServer, gql } = require('apollo-server');
import { ApolloServer, gql } from "apollo-server";

/* 1. 타입 */
// graphQL 타입을 적어준다.
const typeDefs = gql`
  type Query {
    # 리턴 타입을 적어준다.
    # !를 붙이면 필수값이 된다.
    # 값이 배열 안에 들어있으면 [] 안에 넣어준다.
    fetchBoards: [Board!]
  }
  # 타입을 만들어서 지정해 줄 수 있다.
  type Board {
    number: Int
    writer: String
    title: String
    contents: String
  }
  type Mutation {
    # 받아올 데이터의 타입(요청시 입력값)과 리턴할 데이터의 타입을 적는다.
    createBoard(createBoardInput: CreateBoardInput!): String # (backend06)
  }
  # input데이터(프론트에서 전달 받는 데이터)는 type이 아닌 input으로 쓴다.
  input CreateBoardInput {
    writer: String
    title: String
    contents: String
  }
`;

/* 2. API */
const resolvers = {
  /* 조회 */
  Query: {
    fetchBoards: async () => {
      const result = await Board.find();
      return result;
    },
  },
  /* 등록 */
  Mutation: {
    createBoard: async (_: any, args: any) => {
      // parent : API에서 다른 API를 요청한 경우, 넣어준 데이터
      // args : 받아온 데이터. 프론트를 통해서 받아온다.
      // context : header에 들어가는 요약 정보, http 요청에 대한 정보들
      // info : API에 대한 기타 정보들
      // Board가 BaseEntity를 상속받고 있어야 insert를 사용 가능하다.
      await Board.insert({
        ...args.createBoardInput,
      });

      /* 수정 */
      Board.update({ writer: "철수" }, { title: "제목2" });

      /* 삭제 */
      Board.delete({ writer: "철수" });
      // Board.update({writer:"철수"}, {deletedAt: new Date()}); // soft-delete 방식

      return "게시물을 등록했습니다.";
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  cors: true,
  // true로 지정하면 주소가 다른 브라우저에서도 api 활용이 가능해짐
  // cors: {
  //   origin: 'http://naver.com' // 주소를 명시하면 적은 주소만 허용
  // },
});

const AppDataSource = new DataSource({
  type: "postgres",
  host: "34.64.124.189",
  port: 5022,
  username: "postgres",
  password: "postgres2021",
  database: "postgres",
  entities: [Board],
  synchronize: true,
  logging: true,
});

AppDataSource.initialize()
  .then(() => {
    // 연결에 성공하면 실행
    console.log("연결 성공!");
    // 백엔드 API를 오픈( = listen : 24시간 동안 접속 가능하게 대기상태로 만들어준다.)
    // listen() 안에는 접속할 포트번호를 지정할 수 있다.
    server.listen(4000).then(({ url }) => {
      console.log(`🚀 Server ready at ${url}`);
    });
  })
  .catch((error) => console.log(error, "연결 실패ㅜ"));
profile
🍓e-juhee.tistory.com 👈🏻 이사중

0개의 댓글