네스트를 활용해서 특정 파라미터를 전달받아 DB에 데이터를 조회하는 간단한 API를 추가했다.

 

분명 전달해줘야되는 데이터는 test-test... 같은 문자열이였는데 갑자기 

 

"안되는데요?!" 이러면서 찾아오는것 아닌가

 

침착하게 시도한 파라미터를 공유해달라 하면서 받았는데 이런..

 

멋진아들-sadf-1241..같은 형태가 아닌가...

 

이마를 짚으며 탄식했다.

 

 

 

URL은 아래의 3가지 이유로 여러 특수문자들을 인코딩한다

 

1. 무결성 - 특수문자들이 서버로 전달될때 무작위성의 변경이나 변질을 방지하기 위해

 

2. 보안 - 악의적인 코드가 포함된 파라미터를 전송할 경우 서버에서 예기치 못한 동작을 일으킬 수 있어서

 

3. 안정성 - 몇몇 특수문자들은 URL에서 특수한 의미를 지닌다(EX. / , ?) 그렇기에 잘못된 요청을 막아야해서

 

그런데 이것만 보면 특수문자만이라며? 이라고 의아할 수 있는데 

 

한글도 특수문자로 취급된다.

 

이는 URL의 표준 규격 RFC 3986의 규격을 준수하기 위해서인데 여기서 영어와 몇개의 규칙을 제외하곤 전부 특수문자 취급이다.

 

 

그리하여.. nest js에서는 그러한 규칙과 위의 3가지 이유로 특수문자가 포함된 URL 자원을

 

아래와 같은 메서드 2개를 활용해 변환시킨다

 

1. encodeURL

 

2. encodeURLComponent

 

왜 두개인가요? 

 

좋은 질문이에요. 

 

1번은 path 전체를 인코딩할때 사용합니다

 

예를 들어보면  / ? : @ & = + $ #  라는 문자 자체는 인코딩을 하지않아 쿼리 스트링의 시작점(? = 기호)를 알수 있어서 path 전체를 인코딩 시킬땐  사용하면된다

 

2번은 파라미터만 인코딩할때 사용합니다

 

예를 들자면 파라미터로 전달받은 문자열이 몰?루 라면 몰,?,루 전체를 인코딩해야되기 때문에 encodeURL을 써버리면 물음표 기호가 안되니 잘못된 결과이다. 

 

즉 정리하자면

 

path 전체를 인코딩해야될땐 encodeURL

 

api/param 같이 파라미터만 인코딩 해야될땐 encodeURLComponent

 

 

잘 기억하자

 

 

 

 

 

일렉트론 환경이 너무 낯설다보니 한참을 헤맸다.

 

일렉트론에서 dotenv를 쓰려면 우선 최초 렌더링 파일에서 

require('dotenv').config();

 

위와 같은 선언을 해둔다.

 

(기타 선언 내역보다 최상단에 위치시켜야한다)

 

루트 경로에 .env 파일을 생성한다

 

REACT_APP_TEST_KEY=TEST

 

여기가 중요한데 무슨 농간인지 REACT_APP_를 꼭 붙여야한다.

 

그리고 .env의 내용은 빌드 완료 이후로는 변경이 불가능하기 떄문에 키값이 변경되면 다시 재빌드 해줘야한다.

 

 

이거땜에 몇시간을 헤맸는지 원...

 

 

JPA에서 서비스에서 레파지토리를 호출하고 레파지토리가 엔티티를 호출해서 db에 조회값을 가져온다

 

일반적인 흐름인데 404 익셉션이 발목을 잡았다.

 

뭔가 개인적인 욕심은 전역핸들러가 최종 결과물을 받아 dto 안에 객체가 비었으면 404를 아니라면 200으로

 

보내는 무언가 그럴듯한 코드를 짜고 싶었는데 시간도 촉박하고 그럴만한 능력이 조금 안되기도하고

 

Optional를 써서 익셉션을 내기로 결정했다.

 

 

초기 코드는 아래와 같았다

return Optional.ofNullable(
userRepository.getUserInfo(booleanBuilder)).orElseThrow(() ->
new BusinessExcption(ErrorCode.NOTFOUNDDATA)
);

 

헌데 쓰고 나니 이러면 성능 이슈가 있지않나? 라는 생각을 했다

 

1. Optional 자체가 코스트가 비싸다.

 

2. orElseThrow은 isPresent()의 메서드를 내부적으로 호출하기 때문에 추가적인 비용이 또 든다

(100원짜리 물건샀는데 부가세로 30원 더 내라고 하면 빡치잖아요..)

 

3. 람다 표현식은 실행될떄 마다 새로운 익명 클래스 인스턴스를 만들기 떄문에 오버헤드가 발생한다.

 

 

그런데 늘 프로그래밍 관점에서 일정 부분의 trade-off가 있는것이 이렇게 씀으로써 얻을 수 있는 이점이 있다.

 

1. 가독성이 좋아진다. 

 

2. 유지 보수성이 좋다

 

 

즉 장점 1,2번을 포기하고 오버헤드를 줄이고자 한다면 우리는 내부 동작을 어느정도 이해하기 떄문에 몇가지 대안을 만들 수 있다.

 

대안1. Optional을 쓰되 isPresent을 직접 호출하고 람다 표현식을 제거한다. 

Optional<userInfo> userInfoOpt = Optional.ofNullable(memberRepository.getUserInfo(booleanBuilder));
if (userInfoOpt.isPresent()) {
    return userInfoOpt.get();
} else {
    throw new BusinessException(Error.NOTFOUNDDATA);
}

 

 

대안2. Optional을 쓰지 않고 null 비교를 직접한다.

userInfo userInfo = memberepository.getUserInfo(booleanBuilder);
if (userInfo != null) {
    return userInfo;
} else {
    throw new BusinessException(ErrorCode.NOTFOUNDDATA);
}

 

 

물론 무엇을 쓰는지는 서비스의 호출 횟수,서버의 규모 등등 고려할 상황이 많지만 코드 블럭에 든 3가지의 경우가 어떤 경우에 쓰이는지만

 

알면 내 환경에 적용하여 충분히 작성할 수 있을것이다.

 

 

+ 참조 1. 아래는 옵셔널을 만든 개발자가 스택오버플로우에 남긴 글이다 총평하자면 자신이 그걸 만든 의도와는 사람들이 다르게 쓰고 있다. 그래서 올바르게 쓰는 방법은 이렇고 의도는 이렇다 라는 글이다

 

https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type/26328555#26328555

 

Should Java 8 getters return optional type?

Optional type introduced in Java 8 is a new thing for many developers. Is a getter method returning Optional<Foo> type in place of the classic Foo a good practice? Assume that the value can be

stackoverflow.com

 

구글 번역 켜놓고 읽어보면 예상외로 재밌다 ㅋㅋㅋ 

 

+ 참조 2. 옵셔널이 왜 비싼가는 벤치마크의 결과가 처참하다. 아래 링크를 보면 실제 글 저자가 여러가지 방법으로 실제 성능 비교를 

해보는데 옵셔널은 성적이 처참하다 못해 이정도라고? 라고 생각이 들 정도로 황당하니 한번 보자 왜 그런지에 대한 이유도 친절하게 알려준다.

https://pkolaczk.github.io/overhead-of-optional/

 

Overhead of Returning Optional Values in Java and Rust | Piotr Kołaczkowski

October 16, 2021 Some programming languages like Java or Scala offer more than one way to express a concept of “lack of value”. Traditionally, a special null value is used to denote references that don’t reference any value at all. However, over time

pkolaczk.github.io

 

도움이 되었길!

'개발 > java' 카테고리의 다른 글

리눅스 crontab으로 쉘 스크립트 실행 등록하기  (2) 2024.12.04
queryDsl의 Q클래스 객체 사용하기  (1) 2024.12.02
JPA QUERYDSL의 LIKE 구현  (0) 2024.03.22
java 탭을 신설했다.  (0) 2023.06.01

첫글로 뭘 쓸까하다가 jpa를 처음 접했을때 당황했던것

 

 

testTable.like(userName) 이라고 쓰고 테스트를 돌렸는데 username이 .eq 처럼 작동하는것이다

 

뭐지? 와일드카드 규칙이 잘못됬나? 싶어서 확인해보니 

 

querydsl에서는 "%" + username + "%" 을 써야하더라 그것을 보고 허참 씨 이럴꺼면 마이바티스 쿼리문 쓰지!

 

했는데 더 당혹스러웠던건 

 

옆에 있던 리드 개발자가 

 

"간단한 검색인데 LIKE보단 contains가 낫지않겠어요?" 라고 하는게 아닌가

 

아래 예시를 보자

testTable.like("%"+userName+"%")
tsetTable.contains(username)

 

 

1. 와일드카드

 

일반적인 오라클 쿼리문에서 와일드 카드는 사용자가 직접 할당한다.

 

글자 앞이나 뒤 혹은 앞뒤 전부, 하지만 contains는 따로 개발자가 와일드카드 규칙을 정하지 않아도 앞뒤로 넣어준다

 

2. 성능

 

contains는 사용자가 할당하지 않으므로 실제 쿼리문으로 작동할땐 문자열을 전부 분해해서 검색한다 이 말이 무슨말이고 하니..

 

username이 malgu일때 아래와 같은 방법으로 작동한다

 

where username like "%m%" or username like "%a%" 이후 u까지 반복

 

이로인해 성능을 크게 잡아먹는다

 

반면 like 는 문자열을 분해하는 과정도 없으며 문자열을 길이만큼 호출하지도 않는다 그리고 인덱스도 활용가능하다!

 

3. 그래서 뭐쓰라구요

 

정리하자면

 

  contains like
문자열 분해  O X
인덱스 활용 여부 X O
반복 호출 여부 O X

 

인덱스를 사용가능하고 성능에 신경쓴다면 like 구문으로 와일드카드를 직접 할당하는게 좋다

 

인덱스 사용이 어렵고 간단한 기능이라 성능에 크게 신경쓰지 않는다면 contains를 쓰면된다

 

 

 

그냥 하는 소리긴한데, 어지간하면 like 쓰자..

 

find와 grep은 목적은 특정 파일을 찾는데 그 의의가 있는 명령어다

 

그렇다면 왜 굳이 이거 두개가 분리되어있을까?

 

find는 어떠한 기준을 제시하여 거기에 맞는 파일을 출력해준다

 

예시는 이렇다

 

find . -size +100M 라고 제시하면 리눅스에서는 "현재" 디렉토리에서 100메가 이상의 파일을 찾아준다

 

grep의 예시는 이렇다

 

grep "test" . 라고 실행하면 리눅스에서는 "현재" 디렉토리에서 test라는 문자열을 가진 파일을 전부 검색해준다

 

 

Q. 그렇다면 find로는 문자열 패턴을 검색 할 수 없나요

 

A.

 

이렇게 예시를 갈라두면 혹시나 처음보는 사람이 엥? 되는데? 라고 생각할 수 있으니 사족을 붙이자면 find와 grep을 혼용하여

 

사용하면된다는것이다

 

find . -exec grep -l "test" {} + 라고 치면 test라는 문자열을 가진 파일을 출력해준다.

 

Q. 엥 그러면 grep "test"와 ind . -exec grep -l "test" {} + 의 차이점은 뭐죠?

 

A. 출력되는 내용이 다릅니다.

 

우선 아래와 같은 파일이 있다고 가정해봅시다.

 

memo1.txt

test 메세지 입니다.

 

memo2.txt

test 코드입니다.

 

memo3.txt

text 파일입니다.

 

find . -exec grep -l "test" {} + 을 실행하면

 

memo1.txt

memo2.txt

 

grep "test"라고 검색하면 

 

test 메세지 입니다.

test 코드입니다.

 

두개의 차이점이 확느껴지지않는가?

 

 

 

뭐 2개가 합쳐진거지만 사소한 찐빠는 넘어가도록 하자

 

'개발 > CS' 카테고리의 다른 글

SQL 에서 IS NULL 과 = NULL의 차이  (1) 2023.11.20
객체지향 그 잡힐듯 잡히지 않는 무언가  (0) 2023.04.10
SSR과 CSR의 차이  (0) 2023.04.10
1. HTTP1.1 / 2.0 그 심오한 차이  (0) 2023.04.09

nest(전글에도 이야기했지만 파이썬의 nest가 아니다 편의상 nestjs를 nest로 쓰는것뿐이다)에는 미들웨어도 적용 시킬 수 있고

 

인터셉터도 만들 수 있다. 특이점이라면 두개 다 글로벌로 만들 수 있다는것

 

궁금점은 여기서 생기는데 그러면 미들웨어 인터셉터 뭐가 더 우선 순위인가? 라는 것이다. 

 

늘 그렇듯 우선 결론은 

 

글로벌 미들웨어 -> 글로벌 인터셉터 순이다 명확하게 하자면 미들웨어가 우선순위가 높다라는것만 기억하면 될거같다

 

보통의 경우 미들웨어만 함수로 나머지의 경우 클래스로 작성하는것이 일반적이다.

 

 

글로벌 미들웨어와 일반(레귤러라 호칭하는거같다) 미들웨어는 코드단에서 차이가 나는데

 

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { GlobalMiddleware } from './global.middleware';

@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(GlobalMiddleware).forRoutes('*');
  }
}

 

 

위 함수에서는 중간에 이벤트 체이닝을 통해 글로벌 미들웨어라 정의되며 작동할 경로를 모두로 선언했음을 알 수 있다.

 

이를 통해 어떤 경로를 통해 들어오건 글로벌 미들웨어가 우선 작동되며 이를 통해 개발자가 필요한 로직을 집어넣을 수 있다.

 

아래는 일반 미들웨어 코드단이다

import { Controller, Get, Middleware } from '@nestjs/common';

@Controller('login')
export class MyController {
  @Get()
  @Middleware(myMiddleware)
  getData() {
    return '로그인 성공!';
  }
}

function myMiddleware(req, res, next) {
  console.log('미들웨어가 정상 작동 중 입니다.');
  next();
}

 

중간에 특정 라우터에 미들웨어 의존성을 주입하여 특정 함수를 작동시키는데 이를 통해 개발자는 특정 라우터가 실행되기 이전 시점에

 

원하는 로직을 집어넣고 이 후 라우터에 대한 기능을 작동 시킬 수 있다.

 

두개의 차이점은 작성하는 파일도 다른데 글로벌은 app.module 파일에 일반 미들웨어는 컨트롤러단에서 작성하는게 일반적

 

 

막상 써보니 너무 어려운데 차근차근 알아가야할거같다.

 

다음편 인터셉터 쓰고 자주쓰는 데코레이터를 정리하는 편을 진행할 예정

'개발 > Nodejs' 카테고리의 다른 글

nest js - encodeURIComponent  (0) 2024.04.17
Nestjs 데코레이터,어노테이션 무엇이 맞을까?  (0) 2023.12.27
신규 카테고리 node js!  (0) 2023.12.27

 

nest(js안 붙이는게 더 편하니깐 안붙이겠다)는 클래스 코드에 @~ 같은 형식을 본적이 있을텐데

 

이를 nest에선 데코레이터라고 부른다. 하지만 나도 좀 의아한게 보통 이런걸 어노테이션이라고 불렀는데

 

왜 이놈은 데코레이터라 부르는걸까?

 

(실제로 스택오버플로우를 검색해보니 종종 혼용하고 있는 케이스도 있는거같다)

 

결론 부터 이야기하자면 Typescript에서 사용하는것은 데코레이터다.

 

 

데코레이터는 객체지향 디자인패턴에서 영감을 받아 만들어진 존재로

 

좀 더 유연한 연결과 개방/폐쇄원칙을 지키기 훨씬 더 수월해진다. 

 

본디 데코레이터가 하는 일은 메타데이터,기능 추가 뭐 이런것들이 있지만 nest에서 어노테이션과 데코레이터의 용어를 좀 헷갈려서

 

그걸 확립하고자 글을 썼다

 

그런고로 앞으로 이 카테고리에서 어노테이션은 데코레이터라 불러야겠다

 

 

 

 

 

'개발 > Nodejs' 카테고리의 다른 글

nest js - encodeURIComponent  (0) 2024.04.17
nestjs의 Middleware,interseptor <미들웨어편>  (1) 2023.12.28
신규 카테고리 node js!  (0) 2023.12.27

자바스크립트로 쓰게되는건 결국 자바스크립트로 쓰게된다

 

당신이 옳았습니다

 

Node js를 알게되고 쓰게 된지는 제법됬지만 요 근래 회사 기술스택이 Nest로 통합되며 쓸일이 많아졌다.

 

원랜 뭐 할줄아는건 express를 기반으로 하는 미들웨어였는데...

 

nest 같이 복잡한 그리고 본디 자바와 같은 구조를 가진게 어색해서 기억나는거 몇개를 좀 남겨야할거같다

 

무난하게 배울수 있길

 

+ Recent posts