instagram에 필요한 기능을 구현해본다.
login 후 passport-jwt.authentication을 이용하여 user를 식별한다.
그리고 user 권한이 필요한 요청일 경우 동작하기 전 validation 기능을 둔다.
앞서 request 값을 GraphQLServer argument에 context 기능을 이용하여 graphql에서도 사용 가능하도록 했다.
그 기능에 더하여 graphql에서 user validation을 하는 middleware를 만들어 사용하도록 하자.
// middlewares.js
export const isAuthenticated = (request) => {
if (!request.user) {
throw Error("You need to log in to perform this action");
}
return;
};
// 사용 예시
Mutation: {
doWhatEver: async(_, args, {request, isAuthenticated}) => {
isAuthenticated(request);
const { user } = request;
return true;
}
}
like/Unlike는 toggle이 되는 모듈로 만든다.
로그인되어 있는 userId와 대상이 되는 postId를 조건으로 toggle like를 한다.
exists 기능을 사용하면 조건문에 해당하는 값이 존재하면 true, 없으면 false를 return한다.
const existingLike = await prisma.$exists.like(filterOptions);
if (existingLike) {
await prisma.deleteManyLikes(filterOptions);
} else {
await prisma.createLike(...)
Mutation: {
addComment: async (_, args, { request }) => {
isAuthenticated(request);
const { text, postId } = args;
const { user } = request;
const comment = await prisma.createComment({
user: {
connect: {
id: user.id,
},
},
post: {
connect: {
id: postId,
},
},
text,
});
return comment;
},
},
Query: {
searchUser: async (_, args) =>
prisma.users({
where: {
OR: [
{ username_contains: args.term },
{ firstName_contains: args.term },
{ lastName_contains: args.term },
],
},
}),
},
Mutation: {
editUser: async (_, args, { request, isAuthenticated }) => {
isAuthenticated(request);
const { username, email, firstName, lastName, bio } = args;
const { user } = request;
return prisma.updateUser({
where: {
id: user.id,
},
data: {
username,
email,
firstName,
lastName,
bio,
},
});
},
},
Query: {
seeUser: async (_, args, { request }) => {
const { id } = args;
return prisma.user({ id });
},
},
type Query {
me: User!
}
Query: {
me: (_, __, { request, isAuthenticated }) => {
isAuthenticated(request);
const { user } = request;
return prisma.user({ id: user.id }).$fragment(USER_FRAGMENT);
},
},
// USER_FRAGMENT
const USER_FRAGMENT = `
fragment UserParts on User{
id
username
email
firstName
lastName
bio
posts {
id
caption
}
}
`;
type ProfileResponse{
user: User!
posts: [Post!]!
}
type Query {
me: ProfileResponse!
}
Query: {
me: async (_, __, { request, isAuthenticated }) => {
isAuthenticated(request);
const { user } = request;
const userProfile = await prisma.user({ id: user.id });
const posts = await prisma.user({ id: user.id }).posts();
return {
user: userProfile,
posts
}
},
},
type FullPost {
post: Post!
comments: [Comment!]!
likeCount: Int!
}
type Query {
seeFullPost(id: String!): FullPost!
}
Query: {
seeFullPost: async (_, args) => {
const { id } = args;
const post = await prisma.post({ id });
const comments = await prisma
.post({ id })
.comments()
.$fragment(COMMENT_FRAGMENT);
const likeCount = await prisma
.likesConnection({
where: { post: { id } },
})
.aggregate()
.count();
return { post, comments, likeCount };
},
},
// 🗳fragments.js
export const COMMENT_FRAGMENT = `
fragment CommentParts on Comment{
id
text
user{
username
}
}
`;