묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
nestjs google login (섹션30과제) 질문
선생님 안녕하세요.구글 소셜로그인 기능에 대해서 과제를 진행하고 있었는데요.과제 영상에 따라서 따라 내려가고있었는데 nestjs로 REST API를 생성하는데 있어서 refreshToken을 발급해줘야하는 단계에서 res가 에러가 발생합니다.IAuthServiceRefreshToken의 인터페이스에서 res가 없다는 것으로 확인이되는것 같은데요.이전에 context로 graphql의 인터페이스를 사용해주었었는데context를 없애고req로 변경하고 Express의 Response를 생성해주면 REST API가 되는걸까요?!이전까지 진행했을때는 Icontext를 생성해서 유저를 찾아내는 방식이었는데 강의내용에는 이런게 빠져있어서 어떻게 해나가야 하는지 좀 헷갈리는것 같습니다. 참고내용으로 이전에 사용했던 소스코드들을 공유드려봅니다.//auth.service.ts import { Injectable, UnprocessableEntityException } from '@nestjs/common'; import { UsersService } from '../users/users.service'; import * as bcrypt from 'bcrypt'; import { JwtService } from '@nestjs/jwt'; import { IAuthServiceGetAccessToken, IAuthServiceLogin, IAuthServiceRestoreAccessToken, IAuthServiceSetRefreshToken, } from './interfaces/auth-service.interface'; @Injectable() export class AuthService { constructor( private readonly userService: UsersService, // private readonly jwtService: JwtService, ) {} async login({ email, password, context }: IAuthServiceLogin) { // 1. 이메일이 일치하는 유저를 DB에서 찾기 const user = await this.userService.findOneByEmail({ email }); // 2. 일치하는 유저가 없으면?! 에러 던지기!!! if (!user) throw new UnprocessableEntityException('존재하지 않는 이메일입니다.'); // 3. 일치하는 유저가 있지만, 비밀번호가 틀렸다면?! const isAuth = await bcrypt.compare(password, user.password); if (!isAuth) throw new UnprocessableEntityException('틀린 암호입니다.'); // 4. refreshToken(=JWT)을 만들어서 브라우저 쿠키에 저장해서 보내주기 this.setRefreshToken({ user, context }); // 5. 일치하는 유저도 있고, 비밀번호도 맞았다면?! // => accessToken(=JWT)을 만들어서 브라우저에 전달하기 return this.getAccessToken({ user }); } getAccessToken({ user }: IAuthServiceGetAccessToken): string { return this.jwtService.sign( { sub: user.id }, { secret: process.env.JWT_SECRET_KEY, expiresIn: process.env.JWT_ACCESS_TOKEN_EXPIRE, }, ); } setRefreshToken({ user, context }: IAuthServiceSetRefreshToken): void { const refreshToken = this.jwtService.sign( { sub: user.id }, { secret: process.env.JWT_REFRESH_SECRET_KEY, expiresIn: process.env.JWT_REFRESH_TOKEN_EXPIRE, }, ); //개발환경 context.res.setHeader( 'set-Cookie', `lovely soong=${refreshToken}; path=/;`, ); // 배포환경 // context.res.setHeader('set-Cookie', `refreshToken=${refreshToken}; path=/; domain=.mybacksite.com; SameSite=None; Secure; httpOnly`); // context.res.setHeader('Access-Control-Allow-Origin', 'https://myfrontsite.com'); } restoreAccessToken({ user }: IAuthServiceRestoreAccessToken): string { return this.getAccessToken({ user }); } } 확인부탁드리겠습니다 감사합니다.
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
Entity nullable
강사님 강의 다 수강 이후 코드를 하나씩 뜯어보며 이해하던 중 엔티티에서 컬럼의 속성 값에 대한 의문ㅇ이 생겨 질문 드립니다. 강사님의 ChannelChats.entity에서 이와 같이 userId와 channelId가 nullable true로 설정이 되어있는데 널값을 허용하는 이유가 궁금하여 질문 드립니다. 그리고 또 다른 질문이 있는데 아래에서 m:1 관계 설정 후 joinColumn만으로도 테이블에 컬럼이 추가되는 걸로 알고 있는데 위에서 Column데코레이터로 다시 한 번 만들어준 것은 후에 select과 같은 요청시 joinColumn만으로 생성된 컬럼 값은 안넘어와서 column 데코레이터를 다시 한 번 사용해준 것이라고 이해해도 괜찮을까요??
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
다대다 관계에서 productTags의 타입에 관한 질문입니다
안녕하세요. 항상 알기쉽게 설명해주셔서 많은 도움이되고 있습니다. (myERD프로젝트하는데 거의 일주일 걸린것 같습니다 ㅎㅎ)섹션29 10-8 다대다 api설계에서 productTags에 대한 질문드립니다.아래와 같이 tags을 productTags에 넣어서 리턴을 해주는 상황입니다.그런데 여기서 ...prevTags와 ...newTags.identifiers의 타입이 서로 다른것 같아서 다음과같이 콘솔로 찍어 보았습니다. 배열요소의 3번째까지가 ...prevTags에 담긴 값인데 저렇게 리턴하면 타입관련에러나 DB에 저장이나 서로 연결이 안될줄 알았는데 강의와 같이 잘 작동하였습니다.그래서 아래와 같이 productTags의 타입인 ProductTag[]도 확인해보았는데도 잘 이해가 안갑니다제생각에는 prevTags에서 id만 뽑아낸 객체배열을 새로 정의한 다음에 스프레드시켜서 넣어주어야 할것같은데, 해보니 둘 다 결과는 같네요... 제가 어떤 걸 놓치고 있는 걸까요?사족 : 그런데 이 문제를 생각하는 도중에 힌트를 얻어서 update에서 에러나는 숙제를 해결했습니다^^
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
http 통신 과제 연습
http 과제 연습 graphql-API 문제에 https://practice.codebootcamp.co.kr/graphql 이 안들어가지는데 어디서 해야하나요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
typeORM Many to one 관계설정
안녕하세요 typeORM 관계설정 중에 궁금한게 생겨서 질문드립니다.공식문서에 나온 코드를 보면 ManyToOne 데코레이터 안에 두 가지 인자가 있는데 앞에 있는건 강의에서도 작성하지만 두번 째인자는 생략이 가능한 것 같네요.. 혹시 두번 째 인자는 OneToMany를 작성할 때도 생략이 가능한가요?그리고 혹시 OneToMany로 받아오는 배열을 배열말고 count해서 숫자로 칼럼에 넣을 수 있는 방법이 있을까요..? 힌트라도 알려주시면 감사하겠습니다!!@Entity() export class Photo { @PrimaryGeneratedColumn() id: number @Column() url: string @ManyToOne(() => User, (user) => user.photos) user: User }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
Ubuntu 듀얼부팅
안녕하세요 windows 사용자인데 램 24기가라서 듀얼부팅 메뉴얼대로 우분투 설치했습니다 (재부팅하는데 os 윈도우로 할거냐 우분투로 할거냐 선택창이 안떠서 엄청 헤매다가 유투브 찾아보고 결국 해결했네요 ㅠㅠ) 수업자료에 있는 20.04.4 LTS 버전은 안보여서 비슷한 버전으로 20.04.6 LTS로 설치했는데 문제 없겠죠? 그리고 파티션 할당할 때 c드라이브 용량을 최대한 줄여본다 해서 40기가 정도 우분투 환경에 할당해줬는데 충분할까요?빠른 답변 주시면 감사하겠습니다!!
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
nest-morgan 패키지 사용
안녕하세요! 강의 마지막 부분에 nest-morgan 패키지를 사용하면 된다고 하셨는데요. npm 문서를 확인해보니 해당 패키지가 deprecated 되어 있다고 명시돼 있습니다. 혹시 여전히 해당 패키지를 사용하고 계신지 혹은 다른 로그 패키지를 사용하고 계신지 궁금합니다!
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
passport와 인증 전략 & Custom decorator 수강 중 Unauthorized 문제가 발생했습니다.
포스트맨으로 정확히 헤더에 { Authorization: 토큰값 } 넣고 { "success": false, "timestamp": "2023-06-19T07:07:40.995Z", "path": "/cats", "statusCode": 401, "message": "Unauthorized"}으로 나와서 response를 콘솔로 찍어보니 authorization과 같이 a가 소문자로 변환되어 찍혔는데요, 혹시 이와 관련되서 토큰값을 제대로 못받는걸까요 ?혹시나해서 코드는 깃허브 참고해서 비교해봤는데 도저히 못찾겠어서 도움요청드립니다 ㅜ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
폴더 복사하고 이름바꾸는 과정에 생기는 문제
안녕하세요? 강의 잘 따라가고 있습니다. 강의진행할때마다 지난 강의폴더를 복사 후 이름을 바꾸는 식으로 진행을 하는데 좀 문제가 생겨서 질문드립니다. 폴더를 복사후 생성(~~~.copy)까지는 문제가 없는데 폴더이름을 변경하는 순간 아래 그림과 같이 프리티어관련 메시지가 나온 후 nestjs/graphql 모듈을 읽어오지 못하는 문제가 발생합니다.일단 node_modules와 yarn.lock폴더를 삭제후 yarn install을 하면 정상적으로 읽어오긴 하는데 매번 그렇게 하니 번거롭네요.. 뭐가 문제인걸까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
구글로그인에러
과제30 구글 로그인 과제 수행중 자꾸 이 에러 때문에... 정답을 찾지 못하였습니다..무엇이 문제인지 모르겠어요...
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
혹시 MYSQL만 사용하는 경우랑 graphql이랑 같이하는경우랑 TypeORM사용법
혹시 MYSQL만 사용하는 경우랑 graphql이랑 같이하는경우랑 TypeORM사용법 차이 많이 나나요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
외부 REST API 사용시 보안관련한 문제
안녕하세요~ 제가 현재 Nestjs 와 React로 구성한 app애서 추가로 다른 app의 API를 사용해야되는 상황인데요. API키와SECRET을 생성하고 이를 이용하여 호출하고 있는데, 이 때 클라이언트에서 요청을 한 내용을 보면 이 Authentication 관련된 토큰들이 다 노출되서 고민입니다.정확히 말하면 이건 백엔드 관련도 아니라 프론트쪽이긴한데요.. 프론트에서 다른 앱의 Restful API를 사용하여 요청할때 사용되는 토큰을 보안적으로 안전하게 숨길 수 있는 방법이 있을까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
로그인한 user의 비밀번호를 변경하는 API updateUserPwd 로직
quiz19 -2 에서토큰기반인증(로그인)된 유저의 비밀번호 변경 로직을 구현하고 있는데요..resolver와 service의 연결부분에서 에러가 발생하는데 혼자서 해결이 어려워 문의드립니다.제가 생각한 updateUserPwd의 로직은유저가 있는지의 여부 확인비밀번호의 일치 여부 확인bcrypt로 변경하고자하는 비밀번호의 암호화암호화된 변경비밀번호를 해당하는 email의 DB에 저장이렇게 하면 끝나는 로직이라고 생각하고 소스코드를 작성했습니다. 1차적으로 제가 생각한 로직에 빠진 부분이 있는지 궁금하고 지금의 소스코드로 어떤부분을 보완해야하는지 궁금합니다.(현재 코드블록으로 공유한 내용은 users.service.ts에서 return부분에 where에서 에러가 발생하는 상황입니다..) 추가로 필요한 정보나 내용, 소스코드가 있으면 추가적으로 공유하도록 하겠습니다. 도와주세요~~~나머지 import해온 class들은 수업을 통해서 그대로 가져온 내용들입니다.//users.resolver.ts @UseGuards(gqlAuthAccessToken) @Mutation(() => String) updateUserPwd( @Args('email') email: string, @Args('password') password: string, ): string { this.usersService.updateUserPwd({ email, password }); return '비밀번호 수정 성공'; }//users.service.ts async updateUserPwd({ email, password, }: IUserServiceUpdateUserPwd): Promise<UpdateResult> { const user = await this.findOneByEmail({ email }); if (!user) throw new UnprocessableEntityException('등록되지 않은 이메일 입니다.'); const isAuth = await bcrypt.compare(password, user.password); if (!isAuth) throw new UnprocessableEntityException('틀린 암호입니다.'); const hashedPassword = await bcrypt.hash( password, Number(process.env.SALT), ); return this.UsersRepository.update( { password: hashedPassword }, { where: { email: user.email }, }, ); }
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
param과 queryString차이
파라미터로 id나 URL 등 값 받아올 때와 쿼리스트링으로 받아올 때 파라미터로도 perPage나 page 등 받아올 수 있는데 어떤 차이로 파라미터와 쿼리스트링을 나누어서 사용해야 할지 질문드립니다.단순히 파라미터는 http 요청시 한 번 정해지면 고정되는 값에 사용하고 쿼리스트링은 매 요청마다 변하는 값에 사용한다고 생각이 드는데 맞을까요??
-
미해결타입스크립트의 모든 것
안녕하세요 정말 좋은 강의 감사합니다
안녕하세요 정말 좋은 강의 감사합니다.혹시 vscode extension은 어떤거 쓰시는지 알수있을까요..?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
15-02 gateway2 docker-compose 에러
도커 빌드하고 실행하는 과정에서 에러가 발생하네요.. 답변해주신 다른 글보고 해봐도 잘안되네요.. 일단 빌드시 생기는 에러입니다.yarn install 할때 경고가 엄청 발생하는데 apollo-server-express가 문제인 것 같은데 정확한건 잘 모르겠네요..사용한 버전정보입니다.도커 빌드가 완료되서 실행을 해도 gateway가 다운되고 1번에러라는 메세지만 받네요 .. 어떻게 해야 할 지 답변부탁드립니다 ㅜㅜ
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
createWorkspaceMembers 도 transaction 걸어줘야 하나요?
안녕하세요 이장우 닮은 제로초 선생님,// workspaces.service.ts async createWorkspaceMembers(url: string, email: string) { const workspace = await this.workspacesRepository.findOne({ where: { url }, relations: ['Channels'], }); // queryBuilder 버전 this.workspacesRepository .createQueryBuilder('workspaces') // typeorm은 innerJoin 하면 join한 테이블은 가져오지 않는데, // innerJoinAndSelect을 하면 join한 테이블을 다 가져온다. .innerJoinAndSelect('workspaces.Channels', 'channels') .getOne(); const user = await this.usersRepository.findOne({ where: { email } }); if (!user) return null; const workspaceMember = new WorkspaceMembers(); workspaceMember.WorkspaceId = workspace.id; workspaceMember.UserId = user.id; await this.workspaceMembersRepository.save(workspaceMember); const channelMember = new ChannelMembers(); channelMember.ChannelId = workspace.Channels.find( (v) => v.name === '일반', ).id; channelMember.UserId = user.id; await this.channelMembersRepository.save(channelMember); }강의에서 위와 같이 createWorkspaceMembers 를 작성하셨는데, 여기도 transaction을 걸어주는게 낫겠죠? 걸어주는게 맞다면, 아래와 같이 하면 되나요? async createWorkspaceMembers(url: string, email: string) { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const workspace = await queryRunner.manager.findOne(Workspaces, { where: { url }, relations: ['Channels'], }); const user = await queryRunner.manager.findOne(Users, { where: { email } }); if (!user) return null; const workspaceMember = new WorkspaceMembers(); workspaceMember.WorkspaceId = workspace.id; workspaceMember.UserId = user.id; await queryRunner.manager.save(workspaceMember); const channelMember = new ChannelMembers(); channelMember.ChannelId = workspace.Channels.find( (v) => v.name === '일반', ).id; channelMember.UserId = user.id; await queryRunner.manager.save(channelMember); await queryRunner.commitTransaction(); } catch (error) { console.error(error); await queryRunner.rollbackTransaction(); } finally { await queryRunner.release(); } }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
섹션2 회원가입 피그마 정답이 있나요
회원가입 피그마 정답이 있는지 궁금하네요 열심히 만들었는데 비교를 할 수가 없어서 문제이네요최대한 비슷하게 했는데 미묘하게 달라서 제가 맞게 한건지 모르겠네요 섹션 7에 파이널 정답이 있는건 아는데 섹션2랑은 많이 달라서 문제네요
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
회원가입 API graphql 오류 문의(quiz18 1-2 관련 문의)
안녕하세요! 오류내용 관련해서 질문사항이 있습니다.새로운 프로젝트로 nestjs를 생성해서 회원가입 create API를 생성하려할때 graphql연결 부문에 있어서 위 이미지와 같이 에러가 발생합니다.위 에러가 GraphQLError: Query root type must be provided.내용에 회원정보를 create하는 root type '@Mutation()'이 있는데도 오류가 나는데 여기서 '@Query()' 를 임의로 만들어 코드를 만들어 놓으면 정상적으로 연결이 완료가 되더라구요.. 조회역할을 하는 Query가 있어야 정상적으로 연결이 되는걸까요? 원리를 알고 싶습니다! ⬇️ @Query() 가 비활성화 됐을때 이미지(graphql 에러발생) ⬇️ @Query()가 활성화 됐을때 이미지(연결 정상)
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
letsStart파일들
package-lock.jspackage.jsontsconfig.json src디렉터리강의 보면 다운받아서 초기설정해주는것같은데얘네는 개발자가 원래 다 직접 쳐야하나요???아니면매번 파일들을 저장했다가 프로젝트처음할때붙여놓고 npm i 하고 해야하는건가요???