inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

176만명의 커뮤니티!! 함께 토론해봐요.

프로젝트 배포

해결됨

풀스택 리액트 토이프로젝트 - REST, GraphQL (for FE개발자)

내용 정리해서 프로젝트로 사용하고 싶어서요 로컬에서만 돌릴 수 있고 따로 배포하거나 할 수는 없나요??

  • react
  • rest-api
  • graphql
뿌뿌죠 댓글 1 좋아요 0 조회수 348

DispatcherServlet과 프로젝트 동작의 이해

미해결

[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발

Port번호 변경이 안 됩니다. debug모드는 적용이 되는 것 같은데 왜그럴까요

  • rest-api
  • spring-boot
whdud 댓글 2 좋아요 0 조회수 211

window.event 문제가 있어요

미해결

[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스

섹션2. 훈훈한 Javascript에서 JS로 HTML태그 생성 강의 듣고 있습니다. 강의 초반부터 window.event.keyCode === 13을 조건문으로 활용하여 엔터키 입력을 감지하는 코드가 있는데.. 저 같은 경우 event 부분에 가로줄이 그어지면서 마우스를 올려 문구를 확인해보면 'event' is deprecated. 라는 메시지가 나옵니다. 경고 메시지만 출력되고 작동에 이상이 없다면 상관이 없지만, 키 입력 시 마다 브라우저의 콘솔창에 undefined가 뜨고 엔터키 또한 마찬가지입니다. 구글링을 좀 해보니, event를 이용한 키 코드 체크를 하는 것이 권장되지 않는다고 하는데.. 다른 방법이 있나요? 구글링으로 찾은 포스팅들은 이해가 되지 않아서.. 도와주세요.

  • javascript
  • node.js
  • docker
  • rest-api
  • nestjs
이예찬 댓글 2 좋아요 0 조회수 455

window 환경 powershell의 UnauthorizedAccess오류

미해결

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

만약 window환경 powershell 에서 아래 해당 권한 오류가 발생한다면 해당 명령어로 해결됩니다. Set-ExecutionPolicy RemoteSigned

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
bigcat0815 댓글 2 좋아요 0 조회수 242

dock 환경설정에 대해 잘 이해가 가지 않습니다.

미해결

실리콘밸리 엔지니어가 가르치는 파이썬 장고 웹프로그래밍

다커 인스톨 후 설명을 들은 후 같이 따라가려고 하는데 이미 파일들이 다 존재하던데,, 그 파일은 임의로 만들고 그 이후로 compose build를 실행하면 되는걸까요? 아니면 따로 생성하는 방법이 있을까요

  • python
  • django
  • bootstrap
  • rest-api
  • drf
그렁대 댓글 1 좋아요 1 조회수 333

전체 핀이 조회되지 않습니다.

해결됨

비전공자를 위한 풀스택 맛집지도 만들기 프로젝트!: Front, Back-end 그리고 배포까지

15개 장소db가 있는데 5개만 조회 됩니다. 코드가 잘못된 부분이 있을까요? 아무리 찾아도 잘 모르겠습니다;; function getContent(data) { // 유튜브 섬네일 id 가져오기 console.log(data); let replaceUrl = data.videoUrl; let finUrl = ""; replaceUrl = replaceUrl.replace("https://youtu.be/", ""); replaceUrl = replaceUrl.replace("https://youtube.com/embed", ""); replaceUrl = replaceUrl.replace("https://youtube.com/watch?v=", ""); finUrl = replaceUrl.split("&")[0]; // 인포윈도우 가공하기 return ` <div class="infowindow"> <div class="infowindow-img-container"> <img src="https://img.youtube.com/vi/${finUrl}/mqdefault.jpg" class="infowindow-img" /> </div> <div class="infowindow-body"> <h5 class="infowindow-title">${data.title}</h5> <p class="infowindow-address">${data.address}</p> <a href="${data.videoUrl}" class="infowindow-btn" target="_blank">영상이동</a> </div> </div> `; } // HTML 코드로 바꾸는 함수 function getContent(data) { let videoId = ""; let replaceUrl = data.videoUrl; replaceUrl = replaceUrl.replace("https://youtu.be/", ""); replaceUrl = replaceUrl.replace("https://www.youtube.com/embed/", ""); replaceUrl = replaceUrl.replace("https://www.youtube.com/watch?v=", ""); videoId = replaceUrl.split("&")[0]; const result = `<div class="infowindow"> <div class="infowindow-img-container"> <img src="https://img.youtube.com/vi/${videoId}/mqdefault.jpg" class="infowindow-img" alt="..."> </div> <div class="infowindow-body"> <h5 class="infowindow-title">${data.title}</h5> <p class="infowindow-text">${data.address}</p> <a href="https://youtu.be/${videoId}" target="_blank" class="infowindow-btn">영상이동</a> </div> </div>`; return result; } async function setMap(dataSet) { markerArray = []; infowindowArray = []; for (var i = 0; i < dataSet.length; i ++) { // 마커를 생성합니다 let coords = await getCoordsByAddress(dataSet[i].address) var marker = new kakao.maps.Marker({ map: map, // 마커를 표시할 지도 position: coords, // 마커를 표시할 위치 }); markerArray.push(marker); // 마커에 표시할 인포윈도우를 생성합니다 var infowindow = new kakao.maps.InfoWindow({ content: getContent(dataSet[i]), // 인포윈도우에 표시할 내용 }); infowindowArray.push(infowindow); // 마커에 mouseover 이벤트와 mouseout 이벤트를 등록합니다 // 이벤트 리스너로는 클로저를 만들어 등록합니다 // for문에서 클로저를 만들어 주지 않으면 마지막 마커에만 이벤트가 등록됩니다 kakao.maps.event.addListener( marker, "click", makeOverListener(map, marker, infowindow, coords)); kakao.maps.event.addListener( map, "click", makeOutListener(infowindow)); } } // 인포윈도우를 표시하는 클로저를 만드는 함수입니다W // 1. 클릭시 다른 인포윈도우 닫기 // 2. 클릭한 곳으로 지도 중심 옮기기 function makeOverListener(map, marker, infowindow, coords) { return function() { // 1. 클릭시 다른 인포윈도우 닫기 closeInfoWindow(); infowindow.open(map, marker); // 2. 클릭한 곳으로 지도 중심 옮기기 map.panTo(coords) }; } let infowindowArray = []; function closeInfoWindow(){ for (let infowindow of infowindowArray) { infowindow.close(); } } // 인포윈도우를 닫는 클로저를 만드는 함수입니다 function makeOutListener(infowindow) { return function() { infowindow.close(); }; } /* ********************************************** 5. 카테고리 분류 */ // 카테고리 const categoryMap = { korea: "한식", china: "중식", japan: "일식", america: "양식", wheat: "분식", meat: "구이", sushi: "회/초밥", etc: "기타", }; const categoryList = document.querySelector(".category-list"); categoryList.addEventListener("click", categoryHandler); async function categoryHandler(event) { const categoryId = event.target.id; const category = categoryMap[categoryId]; try { // 데이터 분류 let categorizedDataSet = await getDataSet(category); // 기존 마커 삭제 closeMarker(); // 기존 인포윈도우 닫기 closeInfoWindow(); setMap(categorizedDataSet) } catch (error) { console.error(error); } } let markerArray = []; function closeMarker() { for (marker of markerArray) { marker.setMap(null) } } async function setting() { try { const dataSet = await getDataSet(); setMap(dataSet); } catch (error) { console.error(error); } } setting();

  • HTML/CSS
  • javascript
  • aws
  • git
  • mysql
  • rest-api
  • github
파이리 댓글 1 좋아요 0 조회수 312

role 을 추가한 후 컨트롤러의 @Patch 코드에서 에러가 발생합니다.

해결됨

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. role 을 추가하자마자 다음과 같은 에러상황이 발생하였습니다. 강의순서랑 동일하게 따라가서 특별하게 더 한건 없는데요, 기존 entity 파일에서 role 생성하고 column 에서 선언해주고나서 저장하자마자 바로 이런 오류가 납니다. 혹시나 불러오기 에러인가 싶어서 강의를 꼼꼼히 보면서 동일한 위치에 따라하면서 해도 강사님쪽에서는 에러가 안나는데 제쪽에서만 에러가 나네요.. 뭐가 문제일까요? 에러내용만 보면 role 을 엔티티파일에서만 선언하고 컨트롤러 파일에서는 불러오기가 실패해서 나는 오류같기도 한데, export 할때 유저 엔티티 파일의 UserModel 안에서 했기때문에 이 에러가 나는게 좀 이상한거 같은데 왜 오류가 나는지 모르겠네요..

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
rtg1014 댓글 3 좋아요 0 조회수 400

Django Authentication 중에 로그아웃 기능이 안됩니다 ㅠㅠ

미해결

실리콘밸리 엔지니어가 가르치는 파이썬 장고 웹프로그래밍

코드를 비교해봐도 똑같습니다... 로그인은 되어잇고 그 후 로그아웃을 하려면 405 에러가 나오네요 ㅠㅠ

  • python
  • django
  • bootstrap
  • rest-api
  • drf
그렁대 댓글 1 좋아요 1 조회수 396

optional관련 질문

미해결

[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발

안녕하세요 강의 너무 잘보고 있습니다.! 단순 궁금증이 있어서요. optional로 조회하고와서 if (!userOptional.isPresent()) { throw new UserNotFoundException("id-" + id); } 위와 같이 선언ㅇ하셧는데요 isEmpty를 사용하지 않고 위와 같이 하는 이유가 궁금합니다.

  • rest-api
  • spring-boot
문수 댓글 2 좋아요 0 조회수 237

학습방식

미해결

실리콘밸리 엔지니어가 가르치는 파이썬 장고 웹프로그래밍

section 4에서 꽤 해맸지만 그래도 5까지 강의를 들었습니다. 이제 to-do-list를 만드려고 했는데 막막해져서 질문 남깁니다. 각각 강의가 전달하려는 내용은 이해한 것 같은데 들은 강의들의 내용을 모두 조합해서 하나의 서비스를 구현하려고 하니 어떻게 해야할지 잘 모르겠습니다. 이럴 경우에는 강의를 한번 다시 보는게 나을까요..? 완전 노베이스에 조금 늦게 시작해서 그런지 학습 이해력이 좀 좋지 않고 질문하는 방식이 좀 미숙한 점 죄송합니다. 완강하면 꼭 수강평 남기겠습니다!

  • python
  • django
  • bootstrap
  • rest-api
  • drf
최진욱 댓글 2 좋아요 1 조회수 380

NestJS 의존성 주입 문제

미해결

[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스

[Nest] 16188 - 2024. 03. 17. 오후 12:19:06 ERROR [ExceptionHandler] Nest can't resolve dependencies of the UsersService (?). Please make sure that the argument "UserRepository" at index [0] is available in the AuthModule context. Potential solutions: - Is AuthModule a valid NestJS module? - If "UserRepository" is a provider, is it part of the current AuthModule? - If "UserRepository" is exported from a separate @Module, is that module imported within AuthModule? @Module({ imports: [ /* the Module containing "UserRepository" */ ] }) Error: Nest can't resolve dependencies of the UsersService (?). Please make sure that the argument "UserRepository" at index [0] is available in the AuthModule context. Potential solutions: - Is AuthModule a valid NestJS module? - If "UserRepository" is a provider, is it part of the current AuthModule? - If "UserRepository" is exported from a separate @Module, is that module imported within AuthModule? @Module({ imports: [ /* the Module containing "UserRepository" */ ] }) at Injector.lookupComponentInParentModules (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:254:19) at Injector.resolveComponentInstance (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:207:33) at resolveParam (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:128:38) at async Promise.all (index 0) at Injector.resolveConstructorParams (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:143:27) at Injector.loadInstance (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:70:13) at Injector.loadProvider (D:\BackEnd\class\section11\11-02-login-authentication\node_modules\@nestjs\core\injector\injector.js:97:9) at D:\BackEn yarn start:dev 실행 시, 위와 같은 오류가 발생하여, users.module.ts 파일의 exports 부분을 아래와 같이 수정하였습니다. exports: [ TypeOrmModule, // 원래는 TypeOrmModule이 아닌 => UsersService(강의 기준) ], 이렇게 수정하니, 문제는 해결되었는데, 이렇게 수정해도 괜찮은지, 이유가 무엇인지 잘 모르겠어 여쭤봅니다.

  • javascript
  • node.js
  • docker
  • rest-api
  • nestjs
rrrrrrrrrr 댓글 1 좋아요 0 조회수 476

TypeError 관련하여 문의드립니다.

해결됨

차세대 Node.js 백엔드 서버 개발(Fastify & Prisma & Typescript와 함께하는)

안녕하세요. TypeError 관련하여 문의드립니다. 강의 회차는 Fastify 기본 설정입니다. 먼저 아래는 제가 실습하는 환경입니다. Mac OS Ventura Node Version : v18.19.1 NPM Version : 10.2.4 아래는 오류에 대한 내용입니다. TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/jiyong/Desktop/Stater-Kit/src/main.ts at new NodeError (node:internal/errors:405:5) at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:136:11) at defaultGetFormat (node:internal/modules/esm/get_format:182:36) at defaultLoad (node:internal/modules/esm/load:101:20) at nextLoad (node:internal/modules/esm/hooks:864:28) at load (/Users/jiyong/Desktop/Stater-Kit/node_modules/ts-node/dist/child/child-loader.js:19:122) at nextLoad (node:internal/modules/esm/hooks:864:28) at Hooks.load (node:internal/modules/esm/hooks:447:26) at MessagePort.handleMessage (node:internal/modules/esm/worker:196:24) at [nodejs.internal.kHybridDispatch] (node:internal/event_target:786:20) { code: 'ERR_UNKNOWN_FILE_EXTENSION' } [nodemon] app crashed - waiting for file changes before starting... 이미 커뮤니티에 해당 오류와 관련하여 질문이 있길레 강사님이 답변하신 부분을 보고 체크해봤지만 제 코드상 잘못된 부분을 못찾겠더라구요 그래서 Google Drive에 올려놓으신 fastify-init.zip 을 통하여 진행해보았지만 같은 오류가 뜹니다. 해결 방법을 알 수 있을까요 ?

  • node.js
  • typescript
  • rest-api
  • prisma
  • fastify
Syno 댓글 1 좋아요 0 조회수 360

section 10-01 실습중에 DB연결 및 생성이 안되서 질문드립니다.

해결됨

[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스

import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { GraphQLModule } from '@nestjs/graphql'; import { TypeOrmModule } from '@nestjs/typeorm'; import { BoardsModule } from './apis/boards/boards.module'; @Module({ imports: [ BoardsModule, ConfigModule.forRoot(), GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: 'src/commons/graphql/schema.gql', }), TypeOrmModule.forRoot({ type: process.env.DATABASE_TYPE as 'mysql', host: process.env.DATABASE_HOST, port: Number(process.env.DATABASE_PORT), username: process.env.DATABASE_USERNAME, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_DATABASE, // env파일에서 수정 entities: [__dirname + '/apis/**/*.entity.*'], // 수정 synchronize: true, logging: true, }), ], }) export class AppModule {} 위와같이 코드 작성했고 터미널에서 yarn start:dev 할경우 아래와 같이 오류가 떠서 작동이 되지않습니다. 어떻게하면 될까요? [Nest] 13226 - 2024. 03. 15. 오전 10:07:01 ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... MissingDriverError: Wrong driver: "undefined" given. Supported drivers are: "aurora-mysql", "aurora-postgres", "better-sqlite3", "capacitor", "cockroachdb", "cordova", "expo", "mariadb", "mongodb", "mssql", "mysql", "nativescript", "oracle", "postgres", "react-native", "sap", "sqlite", "sqljs", "spanner". at DriverFactory.create (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/src/driver/DriverFactory.ts:72:23) at new DataSource (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/src/data-source/DataSource.ts:149:43) at createTypeormDataSource (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/@nestjs/typeorm/dist/typeorm-core.module.js:164:23) at /home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/@nestjs/typeorm/dist/typeorm-core.module.js:169:36 at Observable._subscribe (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/observable/defer.ts:55:15) at Observable._trySubscribe (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/Observable.ts:244:19) at /home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/Observable.ts:234:18 at Object.errorContext (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/util/errorContext.ts:29:5) at Observable.subscribe (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/Observable.ts:220:5) at subscribeForRetryWhen (/home/seasnake/CODECAMP-BACKEND-CLASS/class/section10/10-01-mysql-relation/node_modules/rxjs/src/internal/operators/retryWhen.ts:74:25)

  • javascript
  • node.js
  • docker
  • rest-api
  • nestjs
elgh1234 댓글 2 좋아요 0 조회수 514

refresh token 관련

미해결

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

안녕하세요 강의 잘듣고 있습니다! refresh token의 재발급 로직에서 궁금한 점이 생겼는데요, accessToken과 refreshToken이 모두 만료돼었을때 (오랫만에 앱을 들어간 경우) 만료된 refreshToken을 통해서 다시 refreshToken을 재발급 받는게 맞을까요? ^ 위의 Guard가 들어가 있고 ^ Guard안에는 verifyToken이 들어 있어 accessToken을 발급받기위한 만료되지 않은 refreshToken이 들어있을땐 문제가 없지만 만료된 refreshToken이 들어가면 에러가 발생합니다. 혹시 제가 강의중 놓친것이 있다면 알려주시면 감사하겠습니다!

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
웹개발자 댓글 2 좋아요 0 조회수 424

스웨거 query parameter 전달 방법

미해결

[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발

아무리 찾아도 나오질 않아서 여기에 글 남깁니다. 스웨거 ui 에 파라미터 전달 방법에 page integer ($int64) (query) 이렇게 정의되어 있는건 이해가 되는데 cond[addr::LIKE] string ($string) (query) 이렇게 정의되어 있는건 query parameter를 어떤식으로 전달을 해야 하는가요?

  • rest-api
  • spring-boot
어려워 댓글 1 좋아요 0 조회수 495

강의 자료 ppt를 다운로드 받을 수 있을까요?

미해결

[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발

안녕하세요. 이번에 개정판을 만들어 주셔서 감사합니다. 다름이 아니라 강의 자료 ppt를 다운로드 받을 수 있을까요? 커뮤니티 게시판을 보니 github에 https://github.com/joneconsulting/my-restful-services/tree/master/pdf 확인을 해보니 존재하지 않은 경로로 나오네요.

  • rest-api
  • spring-boot
이현진 댓글 2 좋아요 0 조회수 435

docker-compose 실행시 volume 연결 문제

해결됨

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

[질문] postgres-data 연결이 안됩니다. 검색과 질문들을 통해 바인드 마운트라는 걸 알게되었습니다. 현재 상황입니다. 이전에 postgreSQL 설치를 했었던 적이 있어서, 완전 삭제 하고, 포트번호 변경, 절대경로, 폴더권한(윈도우라서 살짝만..), 재설치, 검색 등을 해보았지만, 주변지식을 얻을 수 있었지만, 해결책을 찾지는 못했습니다. 강사님 help me~ 윈도우 11 home vscode nodejs 20 docker desktop 4.28 (wsl 2) docker-compose.yaml 실행 로그 nestjs 실행 로그 폴더

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
지식쟁이 댓글 1 좋아요 0 조회수 342

debug

해결됨

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

강의중 debug 내용이 너무 좋아보여서 실행하려고 하는데, 첫 step 부터 문제가 생겼습니다. 말씀하신 대로 에서 create a launch.json file 을 클릭했는데 위 이미지 처럼 nodejs 가 나오지 않습니다. 몇시간 동안 검색을 했지만, 추가하는 방법을 찾지 못해 질문드립니다. 혹시 수강생 중에 비슷한 상황을 겪어 보신 분.. 해결방법을 아시는 분 도움을 부탁드립니다.^^ [1] node -v v20.11.0 v18.19.0 모두 테스트 해봤습니다. [2] 혹시나 해서 vscode 새로 설치도 해봤습니다.

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
지식쟁이 댓글 2 좋아요 0 조회수 393

다음 nest강의는 prisma는 사용안하실까요?

미해결

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

현업에서 typeorm 만큼이나 prisma를 많이 사용한다고 하는데 이쪽은 자료때문에 공부하기가 좀 힘들어서요

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
코딩 댓글 1 좋아요 0 조회수 408

where과 order가 적용안되는

해결됨

[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core

내림차순을 확인하려고 param에 DESC를 넣었는데 내림차순 적용 되지 않길래 디버깅하다 문제에 직면했습니다. * eslint-disable prettier/prettier */ /* eslint-disable @typescript-eslint/no-unused-vars */ import { BadRequestException, Injectable } from '@nestjs/common'; import { BasePaginationDto } from './dto/base-pagination.dto'; import { FindManyOptions, FindOptionsOrder, FindOptionsWhere, Repository, } from 'typeorm'; import { BaseModel } from './entity/base.entity'; import { FILTER_MAPPER } from './const/filter-mapper.const'; import { HOST, PROTOCOL } from './const/env.const'; @Injectable() export class CommonService { paginate<T extends BaseModel>( dto: BasePaginationDto, repository: Repository<T>, overrideFindOptions: FindManyOptions<T> = {}, path: string, // api path의 일반화를 위해 ) { if (dto.page) { return this.pagePaginate(dto, repository, overrideFindOptions); } else { return this.cursorPaginate(dto, repository, overrideFindOptions, path); } } // page기반과 cursor기반 페이지네이션 2가지 만들기 /**page기반 CommonService paginate*/ private async pagePaginate<T extends BaseModel>( dto: BasePaginationDto, repository: Repository<T>, overrideFindOptions: FindManyOptions<T> = {}, ) {} /**cursor기반 CommonService paginate*/ private async cursorPaginate<T extends BaseModel>( dto: BasePaginationDto, repository: Repository<T>, overrideFindOptions: FindManyOptions<T> = {}, path: string, ) { /** * where__likeCount__more_than * * where__title__ilike */ const findOptions = this.composeFindOptions<T>(dto); const results = await repository.find({ ...findOptions, ...overrideFindOptions, }); const lastItem = results.length > 0 && results.length === dto.take ? results[results.length - 1] : null; // 새로운 URL을 생성할 때 새로운 쿼리값을 추가하는 방법 const nextUrl = lastItem && new URL(`${PROTOCOL}://${HOST}/posts`); if (nextUrl) { // dto의 키값들을 loop /** * dto의 키값들을 루핑하면서 * 키값에 해당되는 밸류가 존재하면 * param에 그대로 붙여넣는다. * * 단, where__id_more_than 값만 lastItem의 마지막 값으로 넣어준다. */ for (const key of Object.keys(dto)) { if (dto[key]) { if ( key !== 'where__id__more_than' && key !== 'where__id__less_than' ) { nextUrl.searchParams.append(key, dto[key]); // 나머지는 변경되지 마지막 아이템과 연관없이 동일하니까 } } } // 오름차순인지 내림차순인지 체크 let key = null; if (dto.order__createdAt === 'ASC') { key = 'where__id__more_than'; } else { key = 'where__id__less_than'; } // URL에 추가하니까 string으로 nextUrl.searchParams.append(key, lastItem.id.toString()); } return { data: results, cursor: { after: lastItem?.id ?? null, }, count: results.length, next: nextUrl?.toString() ?? null, }; } private composeFindOptions<T extends BaseModel>( dto: BasePaginationDto, ): FindManyOptions<T> { /** * where, * order, * take, * skip -> page 일때만 */ /** * DTO의 현재 생긴 구조는 아래와 같다 * { * where__id__more_than: 1, * order__createdAt: 'ASC' * } * * 현재는 where__id에 해당되는 where 필터만 사용중이지만 * 나중에 likeCount에 해당되는 추가 필터를 넣고싶으면 * 모든 where 필터들을 자동으로 파싱할 수 있을만한 기능을 제작 * * 1) where로 시작한다면 필터 로직을 적용한다. * 2) order로 시작한다면 정렬 로직을 적용한다. * 3) 필터 로직을 적용한다면 '__' 기준으로 split 했을 때 * 3개의 값으로 나뉘는지 2개의 값으로 나뉘는지 확인한다. * 3-1) 3개의 값으로 나뉜다면 FILTER_MAPPER에서 해당되는 operator 함수를 찾아서 적용한다. * 3-2) 2개의 값으로 나뉜다면 정확한 값을 필터하는 것이기 때문에 operator 없이 적용한다. * 4) order의 경우 3-2와 같이 적용한다. */ let where: FindOptionsWhere<T> = {}; let order: FindOptionsOrder<T> = {}; for (const [key, value] of Object.entries(dto)) { if (key.startsWith('where__')) { where = { ...where, ...this.parseWhereFilter(key, value), }; } else if (key.startsWith('order__')) { order = { ...order, ...this.parseWhereFilter(key, value), }; } } return { where, order, take: dto.take, skip: dto.page ? dto.take * (dto.page - 1) : null, }; } private parseWhereFilter<T extends BaseModel>( key: string, value: any, ): FindOptionsWhere<T> | FindOptionsOrder<T> { const options: FindOptionsWhere<T> | FindOptionsOrder<T> = {}; /** * 예를들어 where__id__more_than * __를 기준으로 나눴을때 * * ['where', 'id', 'more_than']으로 나눌 수 있다. */ const split = key.split('__'); if (split.length !== 2 && split.length !== 3) { throw new BadRequestException( `where 필터는 '__'로 split 했을때 길이가 2 또는 3이어야합니다 - 문제되는 키값 ${key}`, ); } /** * 길이가 2일 경우는 * where__id = 3 * * FindOptionsWhere로 풀어보면 * 아래와 같다 * * { * where: { * id: 3, * } * } */ if (split.length === 2) { // [where, id] const [_, field] = split; // field => id // value => 3 /** * { * id: 3 * } */ options[field] = value; } else { /** * 길이가 3일 경우에는 Typeorm 유틸리티 적용이 필요한 경우 * * where__id_more_than의 경우 * where는 버려도 되고 두번째 값은 필터할 키값이 되고 * 세번째 값은 typeorm 유틸리티가 된다. * * FILTER_MAPPER에 미리 정의해둔 값들로 * field 값에 FILTER_MAPPER에서 해당되는 utility를 가져온 후 * 값에 적용 해준다. * */ // ['where', 'id', 'more_than'] const [_, field, operator] = split; // where__id__between = 3, 4 // 만약에 split대상 문자가 존재하지 않으면 길이가 무조건 1이다. // const values = value.toString().split(','); // field -> id // operator -> more_than // FILTER_MAPPER -> MoreThan 함수 // if (operator === 'between') { // options[field] = FILTER_MAPPER[operator](values[0], values[1]); // } else { // options[field] = FILTER_MAPPER[operator](value); // } options[field] = FILTER_MAPPER[operator](value); return options; } } } 디버깅으로 중단점 눌러가며 확인해봤는데 parseWhereFilter 메서드에서 options은 올바르게 key, value를 생성하고 반환하는데 composeFindOptions 메서드에서 밑의 코드를 중단점 확인했을 때 let where: FindOptionsWhere<T> = {}; let order: FindOptionsOrder<T> = {}; for (const [key, value] of Object.entries(dto)) { if (key.startsWith('where__')) { where = { ...where, ...this.parseWhereFilter(key, value), }; } else if (key.startsWith('order__')) { order = { ...order, ...this.parseWhereFilter(key, value), }; } } return { where, order, take: dto.take, skip: dto.page ? dto.take * (dto.page - 1) : null, }; order와 where가 빈 객체로 반환되는 것을 확인했는데 어떻게 고쳐야 할까요

  • javascript
  • typescript
  • rest-api
  • nestjs
  • backend
둘리콩콩 댓글 1 좋아요 0 조회수 358

인기 태그

인프런 TOP Writers

주간 인기글