방식은 똑같지만 return이 되냐 안되냐의 차이
💡 return 안하고 state에 저장만 할꺼면 foreach의 성능이 낫다.
교차된 상태에서 데이터를 쉐어링 해줄 수 있는가?
YES or No
aaa.com에서 mystic.com 백엔드 API를 받아오려면
백엔드에서 CORS를 반드시 허용해줘야 함
※ 앱과 백엔드는 주소가 없기 때문에 요청이 가능(브라우저는 불가능)
브라우저가 백엔드에 데이터 요청을 2번 보내게 되는데(preflight(options),graphql)
먼저 preflight에서 CORS 허용인지 아닌지를 포함해서 백엔드를 줌
-> CORS유무에 따라 브라우저가 보낼지 말지 결정
프록시 서버
이렇게 백엔드에서 우회해서 서버를 받을 수 있도록 하는 데 이를 프록시 서버라 한다.
📌브라우저에서 api를 요청할 수 있도록 ApolloServer 세팅
graphql을 이용해서 api를 만들기 때문에 이를 위한 apollo-server
설치
yarn add apollo-server
아폴로 서버 생성을 위해 typeDefs
(API type) 와 resolver
(API) 필요
1) API 타입 지정(typeDefs)
type Query {
fetchProducts: [Product]
fetchProduct(productId: ID): Product
}
type Mutation {
createProduct(
seller: String!
createProductInput: CreateProductInput!
): String
updateProduct(
productId: ID
updateProductInput: UpdateProductInput!
): String
deleteProduct(productId: ID): String
}
2) API 생성(resolver)
const resolvers = {
Query: {
fetchProducts: async () => {
const result = await Product.find();
console.log(result);
return result;
},
fetchProduct: async (_: any, args: any) => {
const result = await Product.findOne({
where: { _id: args.productId },
});
return result;
},
},
Mutation: {
createProduct: async (_: any, args: any) => {
await Product.insert({
seller: args.seller,
...args.createProductInput,
// writer: args.createBoardInput.writer,
// title: args.createBoardInput.title,
// contents: args.createBoardInput.contents,
});
return "게시물 등록에 성공했습니다!!";
},
updateProduct: async (_: any, args: any) => {
await Product.update(
{ _id: args.productId },
{ ...args.updateProductInput }
);
return "게시물 수정에 성공했습니다!!";
},
deleteProduct: async (_: any, args: any) => {
await Product.update({ _id: args.productId }, { deletedAt: new Date() });
return "게시물 삭제에 성공했습니다!!";
},
},
};
// typeDefs와 resolvers는 위에 우리가 만들어준 타입과 api 입니다.
const server = new ApolloServer({
typeDefs : typeDefs,
resolvers : resolvers,
cors : true
})
AppDataSource.initialize().then(() => {
// DB 접속 성공시 실행
console.log("DB 연결 성공!!")
server.listen({ port: 4000 }).then(() => {
// 서버접속 완료시 콘솔 표기
console.log("서버 실행 성공!")
})
})
위의 기본 기능들을 사용하기 위해 postgres.ts 파일에서 💡BaseEntity를 사용
//Board.postgres.ts 파일
//Board 테이블
import { Column, Entity, PrimaryGeneratedColum, BaseEntity } from "typorm"
@Entity()
export class Board extends BaseEntity{
// Primary GenrateCOlum은 자동으로 생성되는 값(번호, 아이디 등)
@PrimaryGenerateColumn(’increment’)
number: number;
// 데이터베이스의 타입을 임의로 바꾸고 싶다면 아래와 같이 안에 적기
@Column({type : “text”})
writer: string;
@Column()
title: string;
@Column()
contents: string;
}
📌API 만들기 createBoard
1) 받아올 인자의 타입을 지정해주기
import {Board} from "Board.postgres.ts 경로"
const typeDefs = gql`
// 인풋값의 타입을 객체로 묶어 따로 지정
input CreateBoardInput {
writer : String!,
title : String!,
contents : String!
}
type Mutation {
createBoard(createBoardInput:CreateBoardInput) : String
}
// 인풋과 타입의 차이점은 type은 받아올 때만, input은 입력값을 넣을 때 사용
2) API 만들기(resolvers)
const resolvers = {
mutation : {
//인자에는 parent와 args가 있는데 쓰지 않는 parent 부분은 _ 넣기
createBoard : async (_: any , args: any) ⇒ {
// Board 테이블에 값넣기 ---> 백엔드에서 데이터 베이스에 값을 넣어주는 부분.
await Board.insert({
...args.CreateBoardInput
// writer : args.CreateBoardInput.writer,
// title : args.CreateBoardInput.title,
// contents : args.CreateBoardInput.contents
})
return "createBoard 요청이 완료되었습니다."
}
}
📌API 만들기 fetchBoard
1) 받아올 인자의 타입을 지정해주기
const typeDefs = gql`
type Board {
wirter : String
number : Int
title : String
contents : String
}
type Query {
fetchBoards : [Board]
}
//여러개 가지고 오기 때문에 타입을 [Board]라는 배열에 담아서 보내준다
2) API 만들기(resolvers)
Query : {
// 누군가 해당 api를 요청했다면 아래의 함수가 실행
fetchBoards: async() ⇒ {
// 여러개 조회할땐 find, 하나만 조회할땐 findOne
// isDelete는 삭제때문에 들어간 내용이니 아래에서 확인
result = await Board.find({ where : {writer : "철수"}, isDelete : false })
return
}
},
📌deleteBoard API 만들기
1) API 만드는부분
const resolvers = {
mutation : {
deleteBoards: async(_:any, args) ⇒ {
//update에는 2가지. 앞에는 조건, 뒤에는 변경내용
await Board.update({ number : args.number },{deleteAt : new Date()})
return
}
},
※ ❗❗실무에서는 실제로 삭제하지 않음❗❗
Board.update({ number: 3 }, { isDeleted: true}) 또는,
Board.update({ number: 3 }, { deletedAt: new date()});
을 사용하여 업데이트로 삭제된 부분을 표시