GraphQL을 아직 잘 모르겠다면?
createAccount는 클라이언트에서 직접 호출하지 않고, 사용자가 Cognito에 가입하면 Cognito의 Pre-SignUp 트리거에서 호출됩니다.
참조: [인스타그램 클론코딩] Cognito Pre-SignUp 람다 함수
createAccount.graphql
userName과 email을 필수 매개값으로 받아서 문자열을 반환하는 Resolver입니다.
type Mutation {
createAccount(
userName: String!,
email: String!,
firstName: String,
lastName: String,
name: String,
bio: String,
picture: String
): String
}
Mutaion은 데이터베이스를 변형시킨다는 것을 의미합니다.
Cognito Pre-SignUp 트리거 핸들러
Pre-SignUp 트리거에서 사용된 createAccount 요청 코드입니다. createAccount는 문자열을 반환하기 때문에, 반환받을 필드를 지정해 줄 필요가 없습니다.
const { GraphQLClient } = require('graphql-request');
let firstName, lastName, name, picture = "";
// firstName, lastName, name, picture 변경
const createAccountMutation = `mutation{
createAccount(
userName: "${userName}",
email: "${email}",
firstName: "${firstName}",
lastName: "${lastName}",
name: "${name}",
picture: "${picture}"
)
}`;
await graphQLClient.request(createAccountMutation);
참조: [인스타그램 클론코딩] Cognito Pre-SignUp 람다 함수
createAccount.js
백앤드 서버는 createAccount 요청을 받으면 ApolloServer 객체 생성시 입력했던 schema.resolvers에서 createAccount 함수(Resolver)를 찾아서 실행시킵니다.
참조1: GraphQL 데이터 모델링 도구 (@graphql-tools, nexus-prisma)
참조2: 서버리스 GraphQL 백앤드 구축
const _default = {
Mutation: {
createAccount: async(_, args, { prisma }) => {
try {
const {userName, email, firstName = "", lastName = "", name="", bio="", picture="" } = args;
const existEmail = await prisma.user.findOne({
where: {
email
}
});
if(existEmail !== null) {
return "ExistEmailError"
}
const existUserName = await prisma.user.findOne({
where: {
userName
}
});
if(existUserName !== null) {
return "ExistUserNameError"
}
await prisma.user.create({
data: {
userName,
email,
firstName,
lastName,
name,
bio,
avatar: picture
}
});
return "SignUpComplete";
} catch (e) {
console.log(e);
return e;
}
}
}
}
exports.default = _default;
하나씩 알아볼까요?
Pre-SignUp 트리거에서 createAccount를 요청할 때 입력한 매개변수를 createAccount Resolver의 두 번째 매개변수에서 추출할 수 있습니다.
const { userName, email, firstName = "", lastName = "", name="", bio="", picture="" } = args;
데이터베이스에서 동일한 email 또는 userName을 사용하는 사용자가 있는지 검사합니다. 동일한 email을 사용하는 사용자가 검색되면 "ExistEmailError" 문자열을 반환하고, 동일한 userName을 사용하는 사용자가 검색되면 "ExistUserNameError" 문자열을 반환합니다.
참조: Prisma2 CLI를 사용하여 데이터베이스 테이블 생성
const existEmail = await prisma.user.findOne({
where: {
email
}
});
if(existEmail !== null) {
return "ExistEmailError"
}
const existUserName = await prisma.user.findOne({
where: {
userName
}
});
if(existUserName !== null) {
return "ExistUserNameError"
}
두 번에 걸쳐 검색하는 이유는 무엇인가요?
Prisma 데이터 모델링을 할 때 email과 userName 필드를 유니크(@unique) 속성으로 설정했었습니다.
참조: [인스타그램 클론코딩] Prisma2 데이터 모델링
findOne 메소드는 단 한 개의 unique 필드만 조건(where)으로 입력받을 수 있습니다.
그렇다면 email 또는 userName 둘 중 한 개만 검색해도 되는 것 아닌가요?
클라이언트에 정확히 무슨 이유때문에 가입이 안됐는지 알려주기 위해서 입니다.
물론 Pre-SignUp 람다 함수에서 Cognito 사용자를 검색하는 것만으로 필터링이 되겠지만, Cognito와 데이터베이스간의 연결이 너무 약해서(회원가입 및 탈퇴중에 람다 함수 오류 또는 시간 초과 등이 발생하면 예측할 수 없는 결과가 발생할 수 있음) 약간 무리해서라도 백앤드에서 다시 한 번 확인하도록 했습니다.
참조: [인스타그램 클론코딩] Cognito Pre-SignUp 람다 함수
여기까지 도달한다면 Prisma 클라이언트를 사용하여 데이터베이스에 사용자 정보를 복제합니다. 이 경우 bio는 항상 ""이겠군요.
성공적으로 복제하면 "SignUpComplete" 문자열을 반환합니다.
await prisma.user.create({
data: {
userName,
email,
firstName,
lastName,
name,
bio,
avatar: picture
}
});
return "SignUpComplete";
'백엔드 > Prisma + GraphQL' 카테고리의 다른 글
[인스타그램 클론코딩] toggleFollow (0) | 2020.05.31 |
---|---|
[인스타그램 클론코딩] toggleLike (0) | 2020.05.31 |
[인스타그램 클론코딩] Prisma2를 활용한 GraphQL Resolvers (0) | 2020.05.30 |
GraphQL 데이터 모델링 도구 (@graphql-tools, nexus-prisma) (0) | 2020.05.30 |
[인스타그램 클론코딩] GraphQL 데이터 모델링 (0) | 2020.05.30 |