본문 바로가기
카테고리 없음

ApolloServer, firebase (복습 18일차)

by 제이엠_ 2022. 4. 26.

오픈API 실습

import axios from "axios";
import { useEffect, useState } from "react";
import OpenapiListUI from "./OpenapiList.presenter";

export default function OpenapiList() {
  const [imgUrls, setImgUrls] = useState<string[]>([]);

  useEffect(() => {
    const getImg = async () => {
      // [1, 1, 1, 1, 1, 1, 1, 1, 1]
      new Array(9).fill(1).map(async (_) => {
        const result: any = await axios.get(
          "https://dog.ceo/api/breeds/image/random"
        );
        setImgUrls((prev) => [...prev, result.data.message]);
      });
    };
    getImg();
  }, []);

  return <OpenapiListUI imgUrls={imgUrls} />;
}

axios로 오픈api의 값을 불러와서 map으로 배열을 만들어준다. 그러면서 setImgUrls로 imgUrls의 배열을 채워준다.

 

export default function OpenapiListUI(props: IOpenapiListUIProps) {
  return (
    <Wrapper>
      <div>
        {props.imgUrls.map((el, index) => (
          <>
            <DogImg key={el} src={el} />
            {(index + 1) % 3 === 0 && <br />}
          </>
        ))}
      </div>
    </Wrapper>
  );
}

Fragment를 사용하는데 그 이유는 div를 넣었을 때 블록요소가 되기 때문에 개행이 되어버리는데 Fragment는 사진들을 연결해주어 화면에 괜찮게 보여준다. 그리고 ( index + 1 ) % 3 === 0 && <br />을 통해서 한 행에 사진을 3개씩 보여주게 한다. 하지만 이런 방법은 css를 통해서 구현하는 것이 좋다.

 

간단하게 넘어가기

api를 씀에 있어서 CORS(Cross Origin Resource Sharing) 에러가 나오는 건, 백엔드에서 요청하면 받아와지는데, 허용함을 하고 브라우저에 보내줘야한다. 이를 프록시 서버라고 한다. 

 

ApolloServer

import { createConnection } from "typeorm";
import { ApolloServer, gql } from "apollo-server";
import { Board } from "./Board.postgres";

const typeDefs = gql`
  type Board {
    number: Int
    wrtier: String
    title: String
    age: Int
  }

  input CreateBoardInput {
    writer: String!
    title: String!
    age: Int!
  }

  type Query {
    fetchBoards: [Board]
  }

  type Mutation {
    createBoard(createBoardInput: CreateBoardInput): String
    deleteBoard(number: Int!): String
  }
`;

const resolvers = {
  Query: {
    fetchBoards: async () => {
      // DB 와 연결
      const result = await Board.find({
        where: { wrtier: "철수", deletedAt: null },
      });
      console.log(result);

      return result;
    },
  },

  Mutation: {
    createBoard: async (_: any, args: any) => {
      // delteBoard({ number: 22 });

      // DB 와 연결
      await Board.insert({
        // ...args.createBoardInput,
        wrtier: args.createBoardInput.writer,
        title: args.createBoardInput.title,
        age: args.createBoardInput.age,
      });

      return "createBoard를 요청하셨습니다!!!";
    },

    deleteBoard: async (parent: any, args: any) => {
      await Board.update(
        { number: args.number || parent.number },
        { deletedAt: new Date() }
      );
      // Board.delete({ wrtier: "철수" });

      return "삭제가 완료되었습니다!";
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  cors: true,
});

console.log("Hello Typescript!!!");

createConnection({
  type: "",
  database: "",
  username: "",
  password: "",
  port: 5001, // 각자의 포트로 입력하기!!,
  host: "",
  entities: ["./*.postgres.ts"],
  logging: true,
  synchronize: true,
})
  .then(() => {
    // 연결 성공시 실행!!
    console.log("접속 완료!!!");

    server.listen({ port: 4000 });
  })
  .catch((error) => {
    // 연결 실패시 실행!!
    console.log(error);
  });

apolloServer를 연결해준 뒤에 typeDef, resolvers를 가지고 오는데 typeDef는 타입을 지정해주고 resolver는 api를 만드는 역할이라고 보면 된다. 인자에는 첫번째는 parent, 두번째는 args 순으로 들어오게 된다.

 

delete를 할 때는 .delete를 활용할 수 있지만 데이터가 사라져서 위험할 수 있다. 소프트 delete를 활용해야하는데 delete가 아닌 update를 활용한다. isDeleted를 사용하여 boolean값을 보여주는 방법도 있지만 언제 삭제했는지 알 수 없기에 deletedAt에 초기값을 null로 두고 이후에 시간 데이터를 넣어줌으로써 언제 삭제했는지 확인할 수 있게 한다.

 

update({ 조건 }, { 바꿀 내용 })의 구조로 되어 있다.

 

firebase

BAAS(Backend as a Servie)로 firebase가 있다. 백엔드에서 검증하는 과정은 파이어베이스 사이트에서 소스코드를 입력하면 된다. 작은 서비스를 만들 때 파이어베이스를 이용하면 괜찮다. 큰 서비스는 유지 보수를 하는데 어려움이 있다.

import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: "",
  authDomain: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: "",
  appId: "",
};

// Initialize Firebase
export const firebaseApp = initializeApp(firebaseConfig);

초기 세팅은 위 코드블록과 같다. export firebaseApp을 한 뒤에 import하면 된다.

import {
  getFirestore,
  collection,
  addDoc,
  getDocs,
} from "firebase/firestore/lite";
import { firebaseApp } from "../_app";

export default function FirebasePage() {
  const onClickSubmit = async () => {
    // firebase에 한줄 등록하기
    const board = collection(getFirestore(firebaseApp), "board");
    await addDoc(board, {
      writer: "철수",
      title: "제목입니다!!",
      contents: "내용!!",
    });
  };

  const onClickFetch = async () => {
    // firebase에서 데이터 꺼내오기
    const board = collection(getFirestore(firebaseApp), "board");
    const result = await getDocs(board);
    const docs = result.docs.map((el) => el.data());
    console.log(docs);
  };

  return (
    <div>
      <h1>파이어베이스 연습 페이지입니다!!!</h1>
      <button onClick={onClickSubmit}>등록하기</button>
      <button onClick={onClickFetch}>조회하기</button>
    </div>
  );
}

하지만 로그인 검증이나 결제의 경우에는 파이어베스 페이지에서 소스코드를 고쳐나가야하기 때문에 불편함이 있다. 작은 서비스를 구축할 때 활용하는 쪽으로 사용을 권장한다.

 

복습 회고

수강생일 때 백엔드 내용이 들어가면서 프론트엔드 수업도 어려웠는데 백엔드 내용이라니 하면서 넘어갔던 기억이 있다. 지금 와서 돌이켜보면 충분히 할 수 있었는데 겁부터 먹었던 것 같다. 이번에 복습을 하면서 파이어베이스로 한 번 프로젝트를 하나 만들어보면 좋겠다는 생각을 가졌다. 이번에 배운 canvas로 캐치마인드 문제 리스트를 뽑아서 풀어보는 게임 사이트를 만들어볼까 생각중이다.

댓글