데이터베이스 구조, 이어서

이전 기억 : yarn init으로 package.json파일을 만들고 yarn add로 필요한 것들을 추가했음

이후 index.ts에서 넣고싶은 데이터에 대해서 수정을한다.
이러면 백엔드 서버를 만들었다.

만약 백엔드 서버에 접속해보고싶으면??
graphql의 경우 apollo-server를 이용해서 접속해볼 수 있다.
rest-API의 경우는 express를 사용해야함

그럼 당연히 설치 해야함

yarn add apollo-server

graphql도 설치해야함

yarn add graphql

(띄어쓰기로 두 명령어를 붙이면 한번에 설치할수도있다)

상식 : 지난시간에 '서버'라고 하면 백엔드 서버를 의미한다. 일반적으로 서버 개발자라고 하면 백엔드라고 이해하는 것이 좋다
그래서 apollo server라고 하면 apllo (backend) server인것

이후 index.ts에서 설정을 해줘야한다.
설정 이후는 연결을 하는데 데이터 베이스 연결 - 아폴로 백엔드 서버 오픈 순서로 해야한다.

index의 설정

const MytypeDefs = gql`
  type Query {
    fetchBoards: String
  }

  type Mutation {
    createBoard(writer: String, title: String, age: Int): String
  }
`;
const Myresolvers = {
  Query: {
    fetchBoards: () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      return "게시물 조회에 성공했습니다!!";
    },
  },

  Mutation: {
    createBoard: () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      return "게시물 등록에 성공했습니다!!";
    },
  },
};

typedef : grphql의 타입을 지정, playground에서 보던 것을 만드는 것이라고 생각하는게 좋다.
resolvers: api는 함수, 다 모아서 이곳에 저장하는 것임, 실제로 실행될때 사용

아직 어쩌구 저쩌구 부분은 구현하지 않음

이후 then 부분에서

.then(() => {
    //연결 성공시 실생하기!!
    console.log("연결완료!");

    server.listen({ port: 4000 });
  })
  
const server = new ApolloServer({
  typeDefs: MytypeDefs,
  resolvers: Myresolvers,
});  
  


이후 4000번에서 열었으니 localhost/4000으로 들어가면 이렇게 볼 수 있다.
그런데 사실상 뭔가 등록한게 아니고 작동한걸 확인한 것에 가깝다

//어쩌구 저쩌구 부분을 수정해야한다

import Board from "./Board.mysql"

mysql의 보드를 가져온다

Mutation: {
    createBoard: () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      Board.insert({
        title: "안녕하세요! 테스트입니다!",
        writer: "짱구",
        age: 8
      })
      return "게시물 등록에 성공했습니다!!";
    },
  },

이후 Board.insert 로 값을 넣는다.
이렇게 해서 등록을 요청하는 것이다

  • 값이 올때까지 기다려야되니까 async, await를 붙인다.
  Mutation: {
    createBoard: async () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      await Board.insert({
        title: "안녕하세요! 테스트입니다!",
        writer: "짱구",
        age: 8,
      });
      return "게시물 등록에 성공했습니다!!";
    },
  },

이러면 이렇게 정해진 값을 추가하는 데 성공했을것이다.

확인은 디비버로 가서 확인해보자

한번 조회기능도 넣어보자
조회 쿼리는 Board.find()로 한다 짱쉽


옛날엔 이런 명령어를 하나씩 입력했어야한다. SQL 쿼리문이라고 함 근데 지금 이걸 ORM(object relation model)녀석이 알아서 해주고 있는것 오오..!
ORM도 종류가 많지만 우리는 타입스크립트에서 가장 사용자가 많은것인 typeorm을 사용하는것임

const Myresolvers = {
  Query: {
    fetchBoards: async () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      const result = await Board.find();
      console.log(result);
      return "게시물 조회에 성공했습니다!!";
    },
  },

이렇게 조회에 성공하면 터미널에도 보이게된다.

한번 AAA라는 타입을 만들어보자
typeDef안에

type AAA {
  number: Int
  writer: String
  title: String
  age: Int
  }

이후

  type Query {
    fetchBoards: [AAA]
  }
  ///
  Query: {
    fetchBoards: async () => {
      // 어쩌구 저쩌구 (데이터베이스에서 게시물 데이터 꺼내오기)
      const result = await Board.find();
      console.log(result);
      return result;
    },
  },

fetchBoards를 AAA로 하고 return 부분도 result로 가져오게 만든다

그런데 아까 creatboard는 항상 지정된 것만 작성하고 있다. 우리가 원하는 것을 입력받아서 작성하게하려면 수정이 필요하다.
거기서 나오는 부분이 argument, 인자이다
인자를 이해하기 위해서는 parameter, 매개변수도 알아야한다

아래의 인자들을 받아서 위의 매개변수에 넣는다고 생각하면 좋다

아래 _는 parents인데 이게뭐냐
api가 100개가 있다 그럼 frontend에서는 100번 요청한다.
근데 backend에서는 api가 100개가아니고 150개일수 있다. 뭐가있는가? 공통API가 있을 수 있음
외부에 공개가 안된 것들일뿐(공통된 로직같은거, ex : 로그인여부 체크)
그럼 하나하나 넣지 않고 공개는 안됐지만 backend에서 쓰고있는 API인것
(그래서 frontend는 알수 없고 사용할 수도 없음)

그래서 Parents는 이 공통된 부분, backend api가 backend에 있는 api를 호출한 것이다

  Mutation: {
    createBoard: async (_: any, args: any) => {
      await Board.insert({
        title: args.title,
        writer: args.writer,
        age: args.age,
      });
      return "게시물 등록에 성공했습니다!!";
    },
  },

arg는 어떤 인자들을 받는지 이야기함


등록이 됐고

디비버로 데이터베이스에도 들어간 것을 알 수 있다.

이제 값을 한번에 Input으로 받아보자

!는 이 값은 꼭 있어야한다는 것을 의미한다

데이터에 넣어줄때는 mysql의 방식대로 따로따로 넣어줘야한다.

      await Board.insert({
        title: args.createBoardInput.title,
        writer: args.createBoardInput.writer,
        age: args.createBoardInput.age,
      });

이거 스프레드 연산자를 이용해서 바꿀 수 있지 않을까?

console.log(args.createBoardInput)를 하면
createBoardInput : {
title: "안녕하세요! 제목입니다!!",
writer: "짱구",
age: 8
}
이렇게 나오니까 공통적인 부분이라고 생각하고 ...로 해버린다.

      await Board.insert({
        ...args.createBoardInput
      });

한줄 선에서 정리가능하다

삭제기능추가는?

mysql.ts파일에서

  @Column({ type: "timestamp", default: null, nullable: true })
  deletedAt?: Date;

nullable: true는 빈칸을 허용
deletedAt을 가져오는 이유는 삭제된 날짜를 가져와서 삭제여부 + 언제삭제됐는지 알게 하기 위해서다.

이건 사실 완전 삭제가 아니고 얕은삭제, 수정에 가깝다. (update인것)
Board.update({조건}, {]})

deleteBoard: async (_: any, args: any) => {
      await Board.update({ number: args.number }, { deletedAt: new Date() });
      return "게시물이 정상적으로 삭제되었습니다.";
    },

작동했고, 비버에서도 deletedAt이 변해있음을 알 수 있다

프런트엔드개발자 혼자 backend개발자 없이 backend기능 사용하기, Firebase

파이어베이스 홈페이지
BAAS Backend As A Service
이 외에도 PAAS Platform As A Servic6e
SAAS Service As A Service 등등이 있다

백엔드를 서비스로 제공해준다는 의미다
그 API를 사용하면 백엔드가 있는 것 처럼 사용할 수 있다는 의미다

(실무에서는 안쓰이니까 그럼 왜 백엔드개발자를 쓰죠? 라고 묻지말자. 백엔드 개발자도 반드시 필요하다.)

사이드 프로젝트에서 검증용, 테스트의 용도로 쓴다고 생각하면 좋다.


로그인, 프로젝트 만들기, 웹용으로 만들기를 고르면 이렇게 뜬다.

이후 설치, (yarn add firebase로 했다)
설정파일은 _app.tsx에 추가한다.

이렇게 어디서든 쓸 수 있도록 export를 시켜준다. 이럼 설정 끝

그럼 파이어 베이스 페이지를 한번 만들어보자

export default function FirebasePage() {

  function onClickSubmit() {

  }

  function onClickFetch() {

  }

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

독스에도 잘 나와있다 독스에서 우리가 쓸 데이터베이스를 볼 수 있다. ++ 독스도 진짜 쉽게 잘되어있는 편에 속함
실시간 데이터베이스, cloudfirestore 두개가 있다

실시간데이터베이스는 채팅같이 실시간으로 (새로고침없어도) 데이터가 들어오면 모든 사람에게 자동으로 뿌려주는 것
-> 만약에 이런게 없다면 소켓통신을 배워서 구현해야함

이런 기능이 필요없으면 firestore를 쓰면됨


콘솔에서 파이어스토어, 데이터베이스를 만든다

  • 테스트모드

위치를 asia-northeast3으로 설정한다 - 이후 사용설정

바로 빈 데이터베이스를 만든셈이다!

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

export default function FirebasePage() {
  async function onClickSubmit() {
    // const board = collection(getFirestore(firebaseApp), "board");
    // await addDoc(board, {
    //   writer: "철수",
    //   title: "제목입니다!",
    //   contents: "내용입니다!",
    // });
    const product = collection(getFirestore(firebaseApp), "board");
    await addDoc(product, {
      seller: "영희",
      name: "리모콘!",
      contents: "좋은 리모콘!",
    });
  }

  async function onClickFetch() {
    const board = collection(getFirestore(firebaseApp), "board");
    const result = await getDocs(board);
    const docs = result.docs.map((el) => el.data());
    console.log(docs);
  }

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

하나가 추가된 모습을 볼 수 있다.

profile
개발자 새싹🌱 The only constant is change.

0개의 댓글