묻고 답해요
129만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
레퍼지토리 주입 기준이 궁금합니다.
안녕하세요.개인프로젝트하면서 필요한부분들 다시 보는중인데 궁금한점이 생겨서 질문드립니다. 이전 1:1 관계등록 API 강의에서는 상품판매위치 레퍼지토리를 상품의 service에서 주입받지 않고 따로 service를 만들어서 거기서 주입받고 해당 로직을 처리했었습니다.검증로직을 통일시키기 위해서라고 하셨는데, 이번 강의에서는 포인트 레퍼지토리가 주입되어있는 상태에서 추가적으로 유저 레퍼지토리를 주입받아서 유저정보를 가져오시는데, 차이나 기준이 궁금합니다. 더불어 나중 강의인 트랜젝션에서도 현재 주입받은 유저 레퍼지토리를 기준으로 진행되는데, 만약 레퍼지토리를 service별로 분리해야된다면, 쿼리러너를 해당 service로 던졌다가 받던지, 아니면 해당 service에서 xxRepository.create()로 만든걸 받던지 하는 식으로 해야할듯 싶은데 그런 불편함보다는 그냥 한곳에서 처리하는게 낫지 않나 하는 생각이 들기도합니다. 그래서 트랜젝션 사용할때의 레퍼지토리 기준과 만약 service별로 나뉘게 된다면 사용 방법이 궁금합니다. 마지막으로 제가 트렌젝션을 써봤는데, 다른 테이블의 레퍼지토리를 한 개의 service에서 레퍼지토리 주입은 안받고, 모듈에서만 import의 TypeOrmModule.forFreature([]) 부분에 넣어줘도 잘 동작하던데 이렇게 써도 되는게 맞는지 궁금합니다. 혹시 몰라 아래에 해당 코드 첨부해봅니다.// restAPI입니다. // auth.module.ts import { Module } from '@nestjs/common'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; import { UsersService } from '../02.Users/users.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from '../02.Users/entities/users.entity'; import { Auth } from './entities/auth.entity'; @Module({ imports: [TypeOrmModule.forFeature([Auth, User])], controllers: [AuthController], providers: [AuthService], }) export class AuthModule {} // auth.service.ts import { BadRequestException, ConflictException, Injectable, InternalServerErrorException, } from '@nestjs/common'; import { UsersService } from '../02.Users/users.service'; import { InjectRepository } from '@nestjs/typeorm'; import { Auth } from './entities/auth.entity'; import { DataSource, Repository } from 'typeorm'; import { ConfigService } from '@nestjs/config'; import * as bcrypt from 'bcrypt'; import { IAuthServiceCheckInput, IAuthServiceCreate, IAuthServiceLogin, } from './interfaces/auth-service.interface'; import { User } from '../02.Users/entities/users.entity'; @Injectable() export class AuthService { constructor( @InjectRepository(Auth) private readonly authRepository: Repository<Auth>, private readonly configService: ConfigService, private readonly dataSource: DataSource, ) {} // 생략 async create({ createUserInput }: IAuthServiceCreate): Promise<User> { const { user_id, user_pw, id, ...userData } = createUserInput; const { user_email, user_nick } = userData; if (!id) { const checkUserInput = { user_id, user_email, user_nick }; await this.checkUser({ checkUserInput }); } const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const user = await queryRunner.manager.save( User, id ? { id: id, ...userData } : userData, ); const hashedPw = await this.hashPw({ user_pw }); await queryRunner.manager.save(Auth, { user_id, user_pw: hashedPw, user, }); await queryRunner.commitTransaction(); return user; } catch (error) { await queryRunner.rollbackTransaction(); throw new InternalServerErrorException('회원 가입 실패(DB)'); } finally { queryRunner.release(); } } // 생략
-
미해결따라하며 배우는 NestJS
"ID로 특정 게시물 가져오기" 부분이 잘못되었습니다.
@Param('id') 사용 http://localhost/board/id 로 들어가야 하는 것인데, http://localhost/board?id=xxxx 이렇게 설명이 되고 있습니다.아시겠지만.. ?로 처리하는 것은 Query로 해야 하는데, 잘못 설명하신거 같아서 적어봅니다..좋은 강의 감사합니다.다시 개념 잡으려고 보고 있는데, 좋네요.. ㅎㅎ 궁금한게 하나 있는데.. EntityRepostiory를 요새는 사용하지 않는거 같던데..그럼 EntityRepostiory 대신에 뭘 사용하는지 좀 알고 싶습니다. 0.3부터인가 사용하지 않는다고 들어서요..
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
socket io 미 연결 문제 (nest & flutter)
안녕하세요! socket관련한 서비스를 진행해보고 싶어서 제로초님의 강의를 들은 수강생입니다.현재 nest & flutter를 이용하고 있는데, flutter에서의 연결 및 다른 tool에서 socket io 연결이 되지 않으며 “외부 사이트로는 접근이 불가능한 오류”가 생겨서 조심스럽게 여쭤봅니다. 현재 로직은 채팅을 생성시, 채팅을 보여주는 리스트가 실시간으로 새로고침이 되는 부분을 작업중입니다.하지만, postman, httpie, hoppscotch의 부분에서 연결이 되지 않는 문제가 발생합니다.많은 방법을 찾아봤지만, 터미널에서 socket io cli를 통해서 로그는 볼 수 있지만, 다른 tool에서는 이용이 불가능한 방법에 대해서 알고 싶어서 질문드립니다!Socket io를 통해서 local, dev서버 연결 완료 하지만 postman의 socket io기능을 통해서 테스트를 진행하려고 할 때,postman으로 연결local에서는 문제가 없이 연길이 되지만, dev서버에서는 이러한 에러가 발생합니다. 또한 flutter 앱에서 연결을 하려면 다음과 같은 에러가 발생합니다.오류 메시지 "WebSocketException: Connection to 'http://~~~~.com:81/socket.io/?EIO=4&transport=websocket#' was not upgraded to websocket"는 클라이언트가 WebSocket 연결을 시도하였으나, 서버가 해당 연결을 WebSocket 프로토콜로 업그레이드하지 않았다는 것을 의미합니다. 이는 여러 가지 원인에 의해 발생할 수 있습니다: upgrade가 되지 않았다고 나와서 ,ngnix의 socket 부분에서 upgrade부분도 잘 넣어줬는데, 오류가 해결되지 않아서... 고민 끝에 질문 올립니다.Ngnix 설정부터 2주정도 시간을 들였지만, 해결이 되지 않아서…여쭤봅니다.방화벽도 해제가 되어 있는데 연결이 안되고 있습니다..다음은 nest에서 작성한 코드 입니다![chat.gateway.ts]import { WebSocketGateway, WebSocketServer, SubscribeMessage, OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, ConnectedSocket, MessageBody, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; @WebSocketGateway() export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() server: Server; afterInit(server: Server) { console.log('WebSocket initialized'); } handleConnection(client: Socket) { console.log(`Client connected: ${client.id}`); // 수정: client 객체 직접 출력 대신 id 출력 } handleDisconnect(client: Socket) { console.log(`Client disconnected: ${client.id}`); } @SubscribeMessage('sendMessage') handleMessage( @ConnectedSocket() client: Socket, @MessageBody() data: { message: string } ): void { console.log(`Received message from ${client.id}: ${data.message}`); this.server.emit('newMessage', data); // 모든 클라이언트에게 메시지 전송 console.log(`Received message: ${data.message}`); } } [main.ts]import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { join } from 'path'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './common/exceptions/http-exception.filter'; import { SuccessInterceptor } from './common/interceptors/success.interceptor'; import { IoAdapter } from '@nestjs/platform-socket.io'; import { CustomIoAdapter } from './adapters/custom-io.adapter'; async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); app.useWebSocketAdapter(new CustomIoAdapter(app)); const configService = app.get(ConfigService); const port = configService.get('server.port'); const mongoUrl = configService.get('DB.MONGO_URL'); console.log('MongoDB URL:', mongoUrl); app.enableCors({ origin: true, credentials: true, }); app.useStaticAssets(join(__dirname, '..', 'client'), { prefix: '/api/v1/client', }); app.useGlobalInterceptors(new SuccessInterceptor()); app.useGlobalFilters(new HttpExceptionFilter()); app.setGlobalPrefix('api/v1'); const swagger_options = new DocumentBuilder() .setTitle('Nyam-Docs') .setDescription('API description') .setVersion('2.0.1') .addApiKey( { type: 'apiKey', name: 'x-token', in: 'header', description: 'Enter token', }, 'x-token', ) .addApiKey( { type: 'apiKey', name: 'x-type', in: 'header', description: 'Enter type', }, 'x-type', ) .build(); const document = SwaggerModule.createDocument(app, swagger_options); SwaggerModule.setup('api-docs', app, document); await app.listen(port, '0.0.0.0'); console.log(`Application Listening on Port : ${port}`); } bootstrap();다음은 custom한 io입니다[custom.io.adpter.ts]import { IoAdapter } from '@nestjs/platform-socket.io'; import { INestApplication, Injectable } from '@nestjs/common'; import { ServerOptions } from 'socket.io'; @Injectable() export class CustomIoAdapter extends IoAdapter { constructor(app: INestApplication) { super(app); } createIOServer(port: number, options?: ServerOptions): any { const serverOptions: ServerOptions = { ...options, cors: { origin: '*', // 모든 도메인에서 접근 허용 methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true }, transports: ['websocket', 'polling'], //pooling 없으면 연결 안 됨(socket) allowEIO3: true // Engine.IO 3.x 버전 클라이언트 허용 }; return super.createIOServer(port, serverOptions); } } 혹시 해결방법을 아시거나, 도움을 주실만한 정보가 있으시다면 알려주시면 정말 감사하겠습니다!
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
no elements in sequence 에러 관해서 질문이 있습니다.
안녕하세요. nestjs를 사용해서 백엔드를 구성하고 있는데 RxJS의 no elements in sequence라는 에러에 대해서 질문이 있습니다.const findObject = await this.respository.findOne({ where: { data } }) if (findObject) { throw new HttpException("중복 접수 되었습니다.", HttpStatus.CONFLICT); }DB에서 찾은 객체가 있을 경우, Exception으로 에러를 내면서 종료를 시키는 로직을 생각하고 작성을 했습니다. 그런데 정작 오류는 no elements in sequence 와 함께 500 응답코드가 반환되는데요.반환 할 값이 없을경우 나는 에러로 알고있는데, throw만 하고 리턴하는 값이 없어서 발생 하는 것 같습니다.그리고 발생하는 두 오류 중, no elements in sequence가 먼저 반환되어 종료되기때문에 409에러가 묻히는 것으로 추측을 하고있는데 409에러를 먼저 내는 방법은 없을까요?
-
미해결따라하며 배우는 NestJS
선생님 nestjs랑 Nextjs랑 같이 연동해서 작업하는거 어떻게 생각하시나요?
선생님 안녕하세요!강의내용이랑 상관없는 질문이라 정말 죄송합니다..ㅜㅜ!다만 궁금한게있어서 염치불구하고 질문드립니다..다름아니라,Nextjs에 자체적으로 서버 api가 있는걸로 알고있습니다.그래서 Nextjs를 사용할때는 DB만 선정해서 작업하는식으로 해도된다고 알고있는데요.. 정말 인가요? 정말이겠지만.. 음 .. 옳은 방식인가요? 만약 제가말한 1번경우말고,Nextjs랑 Nestjs랑 같이 사용할경우 Nestjs용 서버폴더를 따로 만들고 사용하는게 나을까요? 회원가입 로직도 그럼 서버폴더에서 따로 할테고.. 그러면 넥스트js의 auth라이브러리를 따로 사용을 못하는걸까요?
-
미해결따라하며 배우는 NestJS
쌤 근데 enum 말고 type 으로 타입선언해주면안될까요?
export enum BoardStatus { PUBLIC = 'PUBLIC', PRIVATE = 'PRIVATE', }이런식으로 정의를 하셨는데 이러지말고 const BoardStatus = 'PUBLIC'|'PRIVATE'이런식의 사용은 어려운가요??
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
start:dev-backup으로 돌리면 핫 리로딩이 되요 정상인가요?
"start:dev-backup": "nest start --watch", "start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js",npm run start:dev로 실행 하였을떈 console.log을 바꾸면 작동하지 않는데 start:dev-backup으로 실행할땐 랏 리로딩이 됍니다. 정상인가요?`webpack-hmr.config.js`이 a-nest 파일 안에 있는게 맞겠죠? 영상에선 구분이 잘 가지 않아서const nodeExternals = require('webpack-node-externals'); const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin'); module.exports = function (options, webpack) { return { ...options, entry: ['webpack/hot/poll?100', options.entry], externals: [ nodeExternals({ allowlist: ['webpack/hot/poll?100'], }), ], plugins: [ ...options.plugins, new webpack.HotModuleReplacementPlugin(), new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/], }), new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }), ], }; };처음엔 실행이 안되길래 공식 문서에서 npm i --save-dev webpack-node-externals run-script-webpack-plugin webpack으로 설치 해주었습니다.
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
getUser 관련
안녕하세요 제로초님! 다음과 같이 로그인후 바로 me를 호출하도록했는데 undefined이 찍혀서 왜 유저값이 들어있지 않은지 잘 모르겠습니다. axios에서 withCredential tue 넣었고 쿠키에 세션값이 저장되고 보낼때 header에 들어간것까지 확인했습니다. 제가 놓친 부분이나 누락한 부분이 있을까요? deserializeUser가 실행이 안되는거 같은데 이유를 모르겠네요
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
회원가입시에 로그인
안녕하세요 제로초님!passport 를 nest에 붙이는 법에 대해 이해하기 쉽게 알려주셔서 감사합니다! 하나 질문이 있는데요! 보통 서비스에서는 회원가입을 완료하면 cookie에 session정보(유저정보)를 넣어줘서 로그인후와 같은 경험을 하도록하는데요. 혹시 그 부분은 어떻게 구현해야할까요?passport에서 session정보를 cookie에 담아 보내는 로직을 모두 포함하다보니 방법이 잘 생각나지 않네요 ㅠ
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
ChunkLoadError: Loading chunk 552 failed.
안녕하세요. 저는 nextjs와 nestjs를 사용하고 있습니다. nextjs는 13버전을 사용하고 있는데요.코드를 원하는대로 다 작성해서 배포를 해봤는데, 개발 환경과 프로덕션 환경이 달라서 그런지 에러가 많아서 고쳐보고 있는 중입니다.그런 와중에 버튼을 클릭했을때 링크된 곳으로 사용자를 보내주는 역할을 하는 부분에서 ChunkLoadError: Loading chunk 552 failed. 이런 에러 문구가 콘솔에 뜨면서 화면이 렌더링 되지 않고 있습니다. <Link href="http://<host 서버 주소>/counsel" className="nav-link"> 상담 접수하러가기 </Link>빌드한 결과물에 이상이 있나 싶어서, dist폴더도 삭제했다가 다시 빌드해봤는데 같은 증상이 계속 나옵니다 ㅠㅠ nginx 설정에 문제가 있는걸까요? nextjs를 사용하고 있어서 따로 nginx 설정파일에 정적파일을 명시해두지는 않고 proxypass로 서버 주소를 넣어놓기만 했습니다. 구글링 해서 조치해봐도 딱히 해결책이 나오지 않아서 여쭤봅니다 ㅜㅜ
-
미해결따라하며 배우는 NestJS
pgAdmin 4에서 데이터 베이스 만들어주기 부분
안녕하세요5. Postgres & TypeORM 정리하기이부분에서PostgresSQL, pgAdmin을 설치하고 데이터 베이스를 만들어주는 과정에서서버를 우선 만들고,BoardProject 하위 목록에Databases 에서 create -> Database에 들어가서 database 를 만들어주려고 하는데강의에서는 input 목록이Database, Owner, Comment 이 세가지만 있는데OID 라는것이 추가되어 있어요... 여기다가 어떤걸 적어줘야 하는지 모르겠고,비운 상태로 save 를 누르면이런 에러가 뜹니다.new locale provider (libc) does not match locale provider of the template database (icu) HINT: Use the same locale provider as in the template database, or use template0 as template.어떻게 해줘야할까요? ㅠㅠpgAdmin 4 를 다운받아서 이런 문제가 발생하는걸까요? 데이터베이스 자체를 만들지 못했으니 뒤로 넘어가지 못하고 계속 헤매는 중입니다 ㅠ 자세한 답변 부탁드리겠습니다.!!
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
ValidationPipe DTO 변환 대신 JS Object 로 변환되는 이유
DTO 변환이 잘 되다가 다른 테스트 케이스 작성중에 아래 처럼 SignInUserRequest DTO 로 변환이 안되는 경우를 겪었습니다. ValidationPipe 옵션 transform: true 임에도 불구하고, 이런 현상이 일어나는 이유를 알 수 있을까요?아래는 잘되는 경우입니다.읽어주셔서 감사합니다.
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
Exception 포스트맨으로 확인 시 undefined 에러
에러[Nest] 48206 - 01/24/2024, 4:13:26 PM ERROR [ExceptionsHandler] You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable. at Object.createInvalidObservableTypeError (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/util/throwUnobservableError.js:5:12) at Object.innerFrom (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/observable/innerFrom.js:93:36) at doInnerSub (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/operators/mergeInternals.js:22:21) at outerNext (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/operators/mergeInternals.js:17:70) at OperatorSubscriber._this._next (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/operators/OperatorSubscriber.js:33:21) at Subscriber.next (/Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/Subscriber.js:51:18) at /Users/kwonyeji/Documents/nestStudy/a-nest/node_modules/rxjs/dist/cjs/internal/observable/innerFrom.js:120:28 at process.processTicksAndRejections (node:internal/process/task_queues:95:5)2.의심 코드<main.ts>import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { HttpExceptionFilter } from './httpException.filter'; declare const module: any; async function bootstrap() { const app = await NestFactory.create(AppModule); const port = process.env.PORT || 3000; app.useGlobalFilters(new HttpExceptionFilter()); const config = new DocumentBuilder() .setTitle('Sleact API') .setDescription('Sleact 개발을 위한 API 문서입니다.') .setVersion('1.0') .addTag('connect.sid') .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, document); await app.listen(port); console.log(`listening on port ${port}`) if (module.hot) { module.hot.accept(); module.hot.dispose(() => app.close()); } } bootstrap(); 에러상황회원가입 구현 후 에러 확인 하려고 포스트맨 으로 요청 시 200성공이 떨어지는게 아니라 해당 에러가 발생합니다. 값을 모두 넣어도 같은 에러가 발생하고 console 찍었을떄 아예 controller에 접근하지도 못했습니다. 설정이 잘못된 건지 잘 모르겠습니다 ㅠ
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
class interface 질문
안녕하세요 제로초님 다른 비슷한 질문에서 다음과 같은 답변을 하셨어요 런타임에 있어서 런타임에도 타입체크를 수행하길 원하면 class로 선언하면 되고, 런타임에는 없길 원하면 interface를 쓰시면 됩니다. 런타임이 실제 코드가 실행될때라고 이해하고 있는데 런타임에 타입체크등 코드가 남아있으면 좋은점이 와닿지 않아서요!실제로 어떤 경우에 런타임에 코드가 남아있서서 좋은지, 타입체크가 되면 좋은지 여쭤봐도 될까요?
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
nestjs typeorm 에서 mariadb 고가용성 galera cluster 적용 관련
nestjs 좋은 강의 잘 들었습니다.~ 감사합니다.다만 질문이 있습니다.기존코드를 nestjs로 마이그레이션 하고 있습니다.mariadb 고가용성 적용을 해야됩니다. 구글링을 해도 해당 관련한 자료가 별로 없어서 질문드립니다.typeorm type을 보면 replication으론 mater, salves 필드로 고가용성이 지원되는데 cluster 구조로 지원이 되는게 맞는지 알고 싶습니다.아직 응용은 못하는 단계라서 질문 드립니다.만약 typeorm에서 cluster 지원이 되지 않는다면 어떤 방법으로 할 수 있나요?
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
빌드 후 /dist 디렉토리가 강사님과 다른데 괜찮을까요
npm run build 후npm run start:prod 했더니 main.js를 찾을 수 없다는 에러 메세지가 나와 디렉토리를 확인해보니 아래와 같았습니다.그리고 main.js는 /dist/src 아래에 있었고요. 일단 packakge.json에서 start:prod의 실행 경로를 'dist/src/main.js'로 변경했고,npm run start:prod해서 서비스 가동되는것 확인했습니다. vsc 종료해도 로컬 호스트로 백엔드 서버 접근과 api 사용까지 이상 없이 되는 것 확인했으니 이대로 aws에 올리고 루트 디렉토리에 /dist 폴더, .env, .gitignore, package-lock.json, package.json만 업로드 해주면 되는걸까요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
Exception Filter편에서 POST할 때 EntityMetadataNotFoundError에러가 납니다.
// users.module.ts import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Users } from '../entities/Users'; @Module({ imports: [TypeOrmModule.forFeature([Users])], providers: [UsersService], controllers: [UsersController], }) export class UsersModule {}// app.module.ts import { MiddlewareConsumer, Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { ConfigModule } from '@nestjs/config'; import { LoggerMiddleware } from './middlewares/logger.middleware'; import { UsersModule } from './users/users.module'; import { WorkspacesModule } from './workspaces/workspaces.module'; import { ChannelsModule } from './channels/channels.module'; import { DmsModule } from './dms/dms.module'; import { UsersService } from './users/users.service'; import * as process from 'process'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Users } from './entities/Users'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), UsersModule, WorkspacesModule, ChannelsModule, DmsModule, TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: process.env.DB_USER, password: process.env.DB_PW, database: process.env.DB_NAME, entities: ['./entities/*.{js,ts}'], synchronize: false, logging: true, keepConnectionAlive: true, migrations: [__dirname + '/src/migrations/*.ts'], }), TypeOrmModule.forFeature([Users]), ], controllers: [AppController], providers: [AppService, UsersService], }) export class AppModule { configure(consumer: MiddlewareConsumer): void { consumer.apply(LoggerMiddleware).forRoutes('*'); } }// users.controller.ts import { Body, Controller, Post, Get, Req, Res, UseInterceptors, } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { JoinRequestDto } from './dto/join.request.dto'; import { UsersService } from './users.service'; import { UserDto } from '../common/dto/user.dto'; import { User } from '../common/decorators/user.decorator'; import { UndefinedToNullInterceptor } from '../common/interceptors/undefinedToNull.interceptor'; @UseInterceptors(UndefinedToNullInterceptor) @ApiTags('USER') @Controller('api/users') export class UsersController { constructor(private usersService: UsersService) {} //..... @ApiOperation({ summary: '회원가입' }) @Post() async join(@Body() body: JoinRequestDto) { await this.usersService.join(body.email, body.nickname, body.password); }import { HttpException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Users } from '../entities/Users'; import bcrypt from 'bcrypt'; @Injectable() export class UsersService { constructor() {} @InjectRepository(Users) private usersRepository: Repository<Users>; getUser() {} async join(email: string, nickname: string, password: string) { const user = this.usersRepository.findOne({ where: { email } }); if (!email) { throw new HttpException('이메일이 없습니다.', 400); } if (!nickname) { throw new HttpException('닉네임이 없습니다.', 400); } if (!password) { throw new HttpException('비밀번호가 없습니다.', 400); } if (user) { throw new HttpException('이미 존재하는 사용자입니다.', 400); } const hashedPassword = await bcrypt.hash(password, 12); await this.usersRepository.save({ email, nickname, password: hashedPassword, }); } }// a-nest/src/entities/Users.ts import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn, } from "typeorm"; import { Channelchats } from "./Channelchats"; import { Channelmembers } from "./Channelmembers"; import { Dms } from "./Dms"; import { Mentions } from "./Mentions"; import { Workspacemembers } from "./Workspacemembers"; import { Workspaces } from "./Workspaces"; @Index("email", ["email"], { unique: true }) @Entity("users", { schema: "sleact" }) export class Users { @PrimaryGeneratedColumn({ type: "int", name: "id" }) id: number; @Column("varchar", { name: "email", unique: true, length: 30 }) email: string; @Column("varchar", { name: "nickname", length: 30 }) nickname: string; @Column("varchar", { name: "password", length: 100 }) password: string; @Column("datetime", { name: "createdAt" }) createdAt: Date; @Column("datetime", { name: "updatedAt" }) updatedAt: Date; @Column("datetime", { name: "deletedAt", nullable: true }) deletedAt: Date | null; @OneToMany(() => Channelchats, (channelchats) => channelchats.user) channelchats: Channelchats[]; @OneToMany(() => Channelmembers, (channelmembers) => channelmembers.user) channelmembers: Channelmembers[]; @OneToMany(() => Dms, (dms) => dms.sender) dms: Dms[]; @OneToMany(() => Dms, (dms) => dms.receiver) dms2: Dms[]; @OneToMany(() => Mentions, (mentions) => mentions.sender) mentions: Mentions[]; @OneToMany(() => Mentions, (mentions) => mentions.receiver) mentions2: Mentions[]; @OneToMany( () => Workspacemembers, (workspacemembers) => workspacemembers.user ) workspacemembers: Workspacemembers[]; @OneToMany(() => Workspaces, (workspaces) => workspaces.owner) workspaces: Workspaces[]; } 서버 실행 후 http://localhost:3002/api/users URL로 빈 값을 POST로 보내면 콘솔창에 400 이메일이 없습니다. 라는 문구가 뜬 이후에C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448 if (!metadata) throw new EntityMetadataNotFoundError(target) ^ EntityMetadataNotFoundError: No metadata for "Users" was found. at DataSource.getMetadata (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448:30) at Repository.get metadata [as metadata] (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:53:40) at Repository.findOne (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:597:42) at UsersService.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.service.ts:13:39) at UsersController.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.controller.ts:37:29) at C:\Users\xxx\Documents\Project\NestProject\a-nest\node_modules\@nestjs\core\router\router-execution-context.js:38:29 at processTicksAndRejections (node:internal/process/task_queues:95:5)위와 같이 EntityMetadataNotFoundError에러가 발생합니다. DB 커넥션 부분도 확인해보고, entities 부분이 문제인가 싶어 아래와 같이 변경도 해보았지만TypeOrmModule.forRoot({ entities: ['./entities/*.{js,ts}'], ],해결되지 않아 질문드립니다.추가적으로 \data-source\DataSource.ts 부분과\repository\Repository.ts부분은 실제 디렉토리에 없는 것들인데 왜 뜨는지도 모르겠습니다.해결 방법이 있을까요?
-
미해결따라하며 배우는 NestJS
강의 자료 관련해서 질문있습니다.
윈도우에서 강의 자료를 열람하기가 힘들어서 그런데 혹시 .DS_Store 파일 말고, 그냥 pdf 자료를 공유해 주시는건 힘들지 문의드립니다
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
하위 테이블이 되는 엔티티에서 외래키 컬럼을 별도로 작성하는 이유가 궁금합니다
강의에서 OneToMany, ManyToOne 관계인 엔티티들을 보면/entity/Users.ts// ... @Entity({ schema: 'sleact', name: 'users' }) export class Users { @PrimaryGeneratedColumn({ type: 'int', name: 'id' }) id: number; // ... @OneToMany( () => WorkspaceMembers, (workspacemembers) => workspacemembers.User, ) WorkspaceMembers: WorkspaceMembers[]; // ... }/entity/WorkspaceMembers.ts@Entity('workspacemembers', { schema: 'sleact' }) export class WorkspaceMembers { // ... @Column('int', { primary: true, name: 'UserId' }) UserId: number; // ... @ManyToOne(() => Users, (users) => users.WorkspaceMembers, { onDelete: 'CASCADE', onUpdate: 'CASCADE', }) @JoinColumn([{ name: 'UserId', referencedColumnName: 'id' }]) User: Users; // ... }WorkspaceMembers 엔티티에서 UserId 컬럼을 별도로 작성하신 뒤@JoinColumn 데코레이터에서 Users 엔티티에서 가져온 'id'컬럼을 본 엔티티에서 'UserId' 컬럼으로 사용하겠다고 지정하셨는데요 이외에도 다른 일대다, 다대일 관계인 엔티티 중 다대일 파일들에 모두 '(상위테이블)Id' 이런 식으로 컬럼을 직접 설정하셨더라구요.이 이유가 무엇인지에 대해서 질문드리고 싶어서 글 작성합니다. 개인적으로 연습하면서 TypeORM 공식문서나 깃북을 확인했을때는 관계에 대해서는 지정을 하되,하위 테이블에선 별도로 외래키에 대한 컬럼까지는 작성하지 않았는데요.제가 작업중인 환경에서 테스트할 때도user.entity.ts// ... @Entity({ name: 'Users' }) export class Users { @PrimaryGeneratedColumn({ type: 'int', name: 'id' }) id: number; // .. @OneToMany(() => Posts, (post: Posts) => post.user, { cascade: true, }) post: Posts[]; }posts.entity.ts// ... @Entity({ name: 'Posts' }) export class Posts { @PrimaryGeneratedColumn({ type: 'int', name: 'id' }) id: number; // @Column({ type: 'int' }) // userId: number; // ... @ManyToOne(() => Users, (user: Users) => user.post, { onDelete: 'CASCADE', }) // 외래키 정보 // @JoinColumn([ // { // referencedColumnName: 'id', // 상대방 컬럼 // name: 'userId', // 여기서 쓸 컬럼 // }, // ]) user: Users[]; }이 상태에서 DB와 테이블을 생성했을때 외래키가 되는 'userId'가 생성되는 것 확인하였습니다.단 이 상태에서는 서비스 단에서 리포지터리로 데이터를 입력할 수가 없었습니다. 이 부분은 JoinColumn 데코레이터가 있어도 결과는 같았습니다. 혹시 자동적으로 만들어지는 외래키 컬럼에는 서비스에서 typeorm 사용해도직접적으로 데이터를 집어 넣지 못하기 때문에,외래키 컬럼을 직접 만들어주고 JoinColumn 데코레이터 사용해서 명시적으로 지정을 해줘야만 한다 라고 생각하면 될까요? 제가 제대로 이해한 것이 맞을까요?
-
미해결따라하며 배우는 NestJS
port 5432 failed: recived invalid response to ssl negotiation
이런 오류메세지가 나오는데 방법좀 부탁드립니다. nestJS서버는 5432포트로 돌아가고 있습니다!!