인프런 강의를 시청하면서 graphQL 에 대해 배운 내용들을 기록하고자 한다.
Int: A signed 32‐bit integer.Float: A signed double-precision floating-point value.String: A UTF‐8 character sequence.Boolean: true or false.ID: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.! 기호는 반드시 할당되어야하는 타입이라는 의미이다.apollo-serverapollo-server-expressgraphql$yarn add apollo-server apollo-server-express graphqlserver/src/index.js 또는 server/src/index.ts 에 graphQL 사용을 위한 세팅을 한다.
//server/src/index.js
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import schema from './schema/index.js';
import resolvers from './resolvers/index.js';
import { readDB } from './dbController.js';
const server = new ApolloServer({
	typeDefs: schema,
	resolvers,
	context: {
		db: {
			messages: readDB('messages'),
			users: readDB('users')
		}
	}
});
const app = express();
// graphQL 의 playground 에서 CORS 접근을 허용하기 위함.
app.use((req, res, next) => {
	res.setHeader('Access-Control-Allow-Origin', '*');
	res.setHeader(
		'Access-Control-Allow-Methods',
		'GET, POST, OPTIONS, PUT, PATCH, DELETE'
	);
	res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
	if (req.method === 'OPTIONS') {
		return res.sendStatus(200);
	}
	next();
});
await server.start();
server.applyMiddleware({
	app,
	path: '/graphql',
	cors: {
		origin: ['http://localhost:3000', 'https://studio.apollographql.com/'],
		credentials: true
	}
});
await app.listen({ port: 8000 });
console.log('server listening on 8000');
server/src/schema/... 경로에 스키마를 정의해준다.
Int, Float 두 가지 키워드를 사용한다.# server/src/schema/index.js
import { gql } from 'apollo-server-express'
import <스키마1> from '<스키마 경로>'
import <스키마2> from '<스키마 경로>'
const linkSchema = gql`
	type Query {
		_: Boolean # _ :  type Query 정의를 index.js 에서 한꺼번에 몰아서 해주기 위해 의미없는 정보를 하나 선언한 것임.
	}
	type Mutation { # 함수 역할
		_: Boolean # 
	}
`
export default [linkSchema, <스키마1>, <스키마2]# server/src/schema/index.js
import { gql } from 'apollo-server-express'
import messageSchema from './message.js'
import userSchema from './user.js'
const linkSchema = gql`
	type Query {
		_: Boolean # _ :  type Query 정의를 index.js 에서 한꺼번에 몰아서 해주기 위해 의미없는 정보를 하나 선언한 것임.
	}
	type Mutation {
		_: Boolean # type Query를
	}
`
export default [linkSchema, messageSchema, userSchema]# server/src/schema/message.js
import { gql } from 'apollo-server-express'
const messageSchema = gql`
	type Message {
		id: ID!
		text: String!
		user: User!
		timestamp: Float #13자리 숫자
	}
	extend type Query {
		messages(cursor: ID): [Message!]!
		message(id: ID!): Message! 
	}
	extend type Mutation {
		createMessage(text: String!, userId: ID!): Message!
		updateMessage(id: ID!, text: String!, userId: ID!): Message!
		deleteMessage(id: ID!, userId: ID!): ID!
	}
`
export default messageShema;
# server/src/schema/user.js
import { gql } from 'apollo-server-express'
const userSchema = gql`
	type User {
		id: ID!
		nickname: String!
	}
	extend type Query {
		users(): [User!]!
		user(id: ID!): User 
		
	}
`
export default userShema;
기존  REST API의 routes 를 대체할 resolver 을 정의한다.
보통 /server/src/resolvers/... 경로를 이용한다.
db 파라미터는 서버 루트 파일에서 정의한 context 의 데이터를 뜻한다.# /server/src/index.js
const server = new ApolloServer({
	typeDefs: schema,
	resolvers,
	context: {
		db: {
			messages: readDB('messages'),
			users: readDB('users')
		}
	}
});# /server/src/resolvers/index.js
import messageResolver from './message.js';
import userResolver from './users.js';
export default [messageResolver, userResolver];# /server/src/resolvers/message.js
import { v4 } from 'uuid';
import { writeDB } from '../dbController.js';
const setMsgs = (newMsgs) => writeDB('messages', newMsgs);
/**
 * parent: 거의 사용 x
 * args: Query에 필요한 필드에 제공되는 인수(parameter)
 * context: 로그인한 사용자. DB Access 등의 중요한 정보들
 */
const messageResolver = {
	Query: {
		// 59 line: GET MESSAGES (전체 메세지 조회) API 기능과 같음
		messages: (parent, args, { db }) => {
			return db.messages;
		},
		// 70 line: GET MESSAGE (단일 메세지 조회) API 기능과 같음
		message: (parent, { id = '' }, { db }) => {
			return db.messages.find((msg) => msg.id === id);
		}
	},
	Mutation: {
		// 86 line: POST MESSAGE (단일 메세지 조회) API 기능과 같음
		createMessage: (parent, { text, userId }, { db }) => {
			const newMsg = {
				id: v4(),
				text,
				userId,
				timestamp: Date.now()
			};
			db.messages.unshift(newMsg);
			setMsgs(db.messages);
			return newMsg;
		},
		updateMessage: (parent, { id, text, userId }, { db }) => {
			const targetIdx = db.messages.findIndex((msg) => msg.id === id);
			if (targetIdx < 0) throw Error('메세지 데이터가 없습니다.');
			if (db.messages[targetIdx].userId !== userId)
				throw '사용자 정보가 일치하지 않습니다.';
			const newMsg = { ...db.messages[targetIdx], text: text };
			db.messages.splice(targetIdx, 1, newMsg);
			setMsgs(db.messages);
			return newMsg;
		},
		deleteMessage: (parent, { id, userId }, { db }) => {
			const targetIdx = db.messages.findIndex((msg) => msg.id === id);
			if (targetIdx < 0) throw Error('메세지 데이터가 없습니다.');
			if (db.messages[targetIdx].userId !== userId)
				throw '사용자 정보가 일치하지 않습니다.';
			msgs.splice(targetIdx, 1); // 삭제
			setMsgs(db.messages);
			return msgs;
		}
	}
};
export default messageResolver;# /server/src/resolvers/user.js
const userResolver = {
	Query: {
		users: (parent, args, { db }) => ({
			result_code: 0,
			payload: Object.values(db.users)
		}),
		user: (parent, { id }, { db }) => {
			// { db } : /server/src/index.js: 25line에 정의된 key 값
			const user = db.users[id];
			if (!user) throw Error('Not exist user data');
			return { result_code: 0, payload: db.users };
		}
	}
};
export default userResolver;설치 패키지 종류들을 알 수 있었다.schema, resolver의 개념과 목적을 알 수 있었다.