Instagram-clone#3-Functions

Seo·2020년 5월 28일
0

InastagramClone

목록 보기
3/15

instagram에 필요한 기능을 구현해본다.

  • graphql use authentication
  • like/unlike
  • comment
  • follow/unfollow
  • search user/search post
  • edit profile
  • See Profile
  • See Full Posts

graphql use authentication

login 후 passport-jwt.authentication을 이용하여 user를 식별한다.
그리고 user 권한이 필요한 요청일 경우 동작하기 전 validation 기능을 둔다.

graphql middleware

앞서 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

like/Unlike는 toggle이 되는 모듈로 만든다.
로그인되어 있는 userId와 대상이 되는 postId를 조건으로 toggle like를 한다.

  • user와 post에 해당하는 like가 없다면 create
  • user와 post에 해당하는 like가 있다면 delete

prisma.$exists

exists 기능을 사용하면 조건문에 해당하는 값이 존재하면 true, 없으면 false를 return한다.

사용 코드

const existingLike = await prisma.$exists.like(filterOptions);
if (existingLike) {
  await prisma.deleteManyLikes(filterOptions);
} else {
  await prisma.createLike(...)

Comment

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;
  },
},
  • connect를 통해 자동으로 relation되도록 한다.(실제 db에도 값이 들어가진다.)
  • comment를 삭제할 때는 disconnet로 update 해주면 된다.
  • 비슷한 기능들을 하는 components는 대부분 이렇게 작업했다.
  • Follow/UnFollow

Search User/Search Post

Query: {
  searchUser: async (_, args) =>
  prisma.users({
    where: {
      OR: [
        { username_contains: args.term },
        { firstName_contains: args.term },
        { lastName_contains: args.term },
      ],
    },
  }),
},

Edit Profile

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,
      },
    });
  },
},
  • 위와 같이 update시에 간단한 코드로 동작 가능하다.

See user Profile

Query: {
  seeUser: async (_, args, { request }) => {
    const { id } = args;
    return prisma.user({ id });
  },
},

See MY Profile

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
      }
  }
`;
  • fragment 기능을 이용하여 하위 항목에 접근해야 한다.(prisma는 웹 공격을 방지하기 위해 nested call을 막아두었다.)
  • 하위 항목에 접근할 때는 명시적으로 prisma 코드를 선언해야 된다.
  • fragment syntax는 위와 같다.
  • fragment 사용할 때 주의할 점은 가지고올 필드들을 모두 명시적으로 적어놔야 한다. 그렇지 않으면 데이터를 가져오지 못한다.

other method

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을 만들어서 내부적으로는 명시적으로 구분해서 prisma를 호출하고 return 한다.

See Full Post

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
        }
    }
`;

remind

  • prisma.$fragment : 더 깊은 참조를 원할 때 사용한다.
  • 외부 모델을 참조로 하는 필드는 connect(반드시 @id를 통해)를 통해 연결가능하다.
profile
개발관심자

0개의 댓글