GraphQL을 검색 서버에서 활용해보고 싶었다.
앱 내에 다양한 검색들이 있었는데,
검색 부분에서 restApi보단,
endpoint를 동일하게하고, 프론트에서 원하는 데이터만 축출해가는 디자인 패턴이
더 효율적이라 생각했기 때문이다.
일단 프로젝트 배포전 임의로 셋팅 해봤다.
app.ts
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import apolloServer from './apollo/apolloserver';
import 'dotenv/config';
const main = async () => {
  const app = express();
  app.use(express.json());
  app.use(express.urlencoded({ extended: false }));
  app.use(express.static('public'));
  app.use(bodyParser.urlencoded({ extended: true }));
  app.use(
    cors({
      origin: '*',
      credentials: true,
    }),
  );
  apolloServer.listen(process.env.PORT).then(({ url }) => {
    console.log(`Listening at ${url}`);
  });
};
main();
아폴로 서버를 사용했다.
실서버에선 cors를 origin에 맞게 넣어줘야겠다.
apolloserver.ts
import { ApolloServer } from 'apollo-server';
import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core';
import schema from '../gql/schema';
import memberAuthMiddleWare from '../middlewares/memberAuth.middleware';
import resolvers from '../gql/resolvers/member.resolvers';
import 'dotenv/config';
const apolloServer = new ApolloServer({
  rootValue: resolvers,
  schema,
  cors: {
    allowedHeaders: '*',
    origin: '*',
    credentials: true,
  },
  introspection: true,
  plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
  context: async ({ req }) => {
    const authorization = req.headers.authorization || '';
    const token = await memberAuthMiddleWare(authorization);
    return token;
  },
});
export default apolloServer;
cors는 실 프로덕트에선 사용할 origin만 넣어야겠다.
introspection은 playground와 applo-send-box사용할 때 사용되는 것인데,
메인 프로덕트는 false로 배포해야겠다.
plugins에선 playground를 사용하겠다는 옵션을 넣었다. (또한 실 프로덕트에선 빼야함)
context는 graphql에서 미들웨어라고 생각하면 편하다.
위 코드는 멤버 토큰을 받아오고, 나중에 context.token으로 불러올 수 있다.
member.typeDefs.ts
import { gql } from 'apollo-server';
const memberTypeDefs = gql`
  type MemberInfo {
    memberIdx: Int
    memberId: String
    memberPw: String
    memberJoin_type: String
    memberName: String
    memberPhone: String
    memberEmail: String
    gender: Int
    memberAge: Int
    dietMode: Int
    height: Int
    weightGoal: Int
    netCarbohydrateGoal: Int
    proteinGoal: Int
    fatGoal: Int
    caloriesGoal: Int
    status: Int
    profileCheck: Int
    joinRoute: Int
    profileImg: String
    delYn: Int
    createdAt: String
    updatedAt: String
  }
  type SnsInfo {
    memberIdx: Int
    followingMemberIdx: Int
  }
  type Query {
    getMemberListSearchedByWord(word: String): [MemberInfo]
    getFollowingList: [SnsInfo]
  }
`;
export default memberTypeDefs;
타입들을 지정해줬다. 지정한 것들은 리졸브나 뮤테이션에서 사용할 수 있다.
member.resolvers.ts
import { Context } from '../../types/context';
import memberService from '../../service/member.service';
const memberResolvers = {
  Query: {
    getMemberListSearchedByWord: async (_parent: any, args: any, _context: Context, _info: any) => {
      const result = await memberService.getMemberListSearchedByWord(args.word);
      return result;
    },
    getFollowingList: async (_parent: any, _args: any, context: Context, _info: any) => {
      const result = await memberService.getFollowingList(context.token);
      return result;
    },
  },
};
export default memberResolvers;
resolvers에서 사용되는 것들로, 클라이언트에서 쿼리로 요청할 때 return값을 반환한다.
memberService는 서비스 로직이다.
controller와 service로 나누던걸, resolvers와 service로 나누는 느낌이 들었다.
args는 클라이언트에서 보낸 데이터를 받는데 사용되고,
context는 아까 아폴로 서버에서 만들어 둔 미들웨어를 받는데 사용한다.
클라이언트 코드
import axios from "axios";
axios.get(serverEndPoint, {
			params: {
				query: `{
                  getMemberListSearchedByWord(word: “검색해보기“) {
                    memberIdx
 					memberName
                  }
                }`,
			},
		})
		.then((result) => {
			console.log("hello", result);
		})
		.catch((err) => {
			console.log(err);
		});
})
restApi처럼 axios나 request를 이용해서 요청할 수 있다.
다만 엔드포인트가 똑같고, params에 query를 넣어서 요청한다.
mutations같은 경우엔 post를 이용한다.
mutations나 resovlers나 모두 post로 통일해서 이용할 수 있지만, 해당 클라이언트 코드에선 get method를 사용했다.
'Back > Node.js' 카테고리의 다른 글
| [Nodejs, TypeScript] 도메인 로직 리팩토링 (0) | 2022.08.05 | 
|---|---|
| [Nodejs, GraphQL] Middleware(미들웨어) 만들기 (0) | 2022.08.04 | 
| [NestJs, Prisma] Prisma CRUD (0) | 2022.07.19 | 
| [Nodejs] Slack Message 슬렉 메시지 보내기 slack-freinds (0) | 2022.06.23 | 
| [Nodejs] Express Typescript SocketIo (0) | 2022.06.13 |