// in seeProfile.typedefs.js
type seeProfileResult {
ok: Boolean!
error: String
user: User
}
type Query {
seeProfile(username: String!): seeProfileResult!
}
in seeProfile.resolvers.js
Query: {
seeProfile: async (_, {username}) => {
const user = await client.user.findUnique({where: {username}});
if (!user) {
return {
ok: false,
error: "유저의 아이디를 찾을 수 없습니다.",
};
}
return {
ok: true,
user,
};
},
},
// in login.typedefs.js
export default gql`
type loginResult {
ok: Boolean!
error: String
token: String
}
type Mutation {
login(username: String!, password: String!): loginResult!
}
`;
// in login.resolvers.js
Mutation: {
login: async (_, {username, password}) => {
const user = await client.user.findUnique({where: {username}});
if (!user) {
return {
error: "유저를 찾을 수 없습니다.",
ok: false,
};
}
const match = await bcrypt.compare(password, user.password);
if (!match) {
return {
error: "비밀번호가 틀립니다.",
ok: false,
};
}
const token = await jwt.sign({id: user.id}, process.env.SECRET_KEY);
return {
ok: true,
token,
};
},
},
bcrypt 패키지를 사용해서 비밀번호 채크를 하고
session 대신 jwt토큰을 사용하겠다.
// in editProfile.typedefs.js
export default gql`
type editProfileResult {
ok: Boolean!
error: String
}
type Mutation {
editProfile(
password: String
name: String
avatarURL: String
): editProfileResult!
}
`;
// in editProfile.resolvers.js
const resolverFn = async (_, {password, name, avatarURL}, {loggedInUser}) => {
let hashedPassword = null;
if (password) {
hashedPassword = await bcrypt.hash(password, 10);
}
const updatedUser = await client.user.update({
where: {id: loggedInUser.id},
data: {
// password : hashedPassword,
...(hashedPassword && {password: hashedPassword}),
avatarURL,
name,
},
});
if (updatedUser.id) {
return {
ok: true,
};
} else {
return {
ok: false,
error: "업데이트 실패",
};
}
};
export default {
Mutation: {
editProfile: protectedResolver(resolverFn),
},
};
protectedResolver라는 함수를 반환하는 함수를 이용해서
로그인되지 않은 사용자에게 에러를 발생시킬 수 있다.
export function protectedResolver(resolver) {
return function (root, args, context, info) {
if (!context.loggedInUser) {
return {
ok: false,
error: "먼저 로그인을 해주세요",
};
}
return resolver(root, args, context, info);
};
}
매 함수마다 jwt를 검증하는 것이 불필요해
resolver 의 세번째 매개변수 Context를 사용해보저ㅏ
const server = new ApolloServer({
schema,
context: async ({req}) => {
return {
loggedInUser: await getUser(req.headers.token),
};
},
});
Context에는 오브젝트와 함수를 지정할 수 있는데
cotext에 지정된 값들은 프로젝트 내 모든 resover에서 상용 할 수 있다.
또 context에는 매개변수로 req,res를 받을 수 있다.
헤더 안에 token 을 넣어주고 req를 보내면 context에서 받을 수 있다.
export const getUser = async (token) => {
try {
if (!token) {
return null;
}
const {id} = await jwt.verify(token, process.env.SECRET_KEY);
const user = await client.user.findUnique({where: {id}});
if (user) {
return user;
} else {
return null;
}
} catch (error) {
console.error(error);
return null;
}
};
매번 토큰을 verify하고 client 를 통해 유저를 찾는 것보다
context를 이용해 user 정보를 통채로 보내주는게 소스코드의 량을 줄 일 수 있다