Javascript

Express.js 5.0.0 정식 출시!

드리프트2 2025. 3. 31. 19:41

 

Express.js 5.0.0 정식 출시!

노드제이에스(Node.js) 애플리케이션 개발에서 가장 인기 있는 웹 프레임워크로 손꼽히는 Express.js가 마침내 버전 5.0.0을 공식 출시했습니다.

첫 메이저 버전이 나온 2014년부터 꼬박 10년이 지난 시점인데요.

그동안 Express.js는 수많은 버전업과 최적화를 거듭해 왔고, 이번 5.0.0 버전에서는 특히 더 강력해진 새로운 기능들과 개선점들이 추가되어 개발자들에게 전혀 다른 경험을 선사합니다.

1. 이번 버전 출시의 핵심 목표

Express.js 5.0.0의 출시에서 가장 중점을 둔 두 가지는 바로 안정성보안성입니다.

이 버전은 개발자들이 더욱 견고한 노드제이에스(Node.js) 애플리케이션을 구축할 수 있도록 돕고, 현대 웹 개발의 든든한 토대가 되는 것을 목표로 합니다.

요즘처럼 기술이 빠르게 발전하는 시대에는 애플리케이션의 안정성과 보안성이 사용자 경험과 데이터 보호와 직접적으로 연결되어 있잖아요?

그래서 Express.js 팀의 이번 결정은 매우 의미심장한 변화입니다.

2. 노드제이에스 버전 지원 정책의 변화

Express 5에서는 과감하게 오래된 노드제이에스 버전들에 대한 지원을 중단했습니다.

공식 릴리즈 노트에 명확히 명시된 대로, 이번 버전부터는 노드제이에스 v18 미만 버전은 더 이상 지원하지 않습니다.

이 변화가 단순해 보일 수 있지만, 사실 굉장히 큰 파급효과를 가집니다.

과거 노드제이에스의 구버전을 지원하다 보니, Express.js는 성능과 유지보수성 면에서 큰 개선을 이루지 못했거든요.

예를 들어 설명해 볼까요?

옛날 버전의 노드제이에스는 성능 병목 현상이 있거나, 최신 하드웨어 기능이나 최적화 알고리즘을 온전히 활용할 수 없었습니다.

그 결과, 높은 동시성 환경에서 Express 애플리케이션의 성능이 떨어질 수밖에 없었죠.

그런데 구버전 지원이 끊기면서, Express.js는 지속적 통합(CI, Continuous Integration) 프로세스를 훨씬 더 안정적이고 관리하기 쉽게 만들 수 있게 됐습니다.

더불어 새로운 언어 기능이나 최신 런타임 환경의 이점을 온전히 누릴 수 있게 됐고, 불필요한 의존성(dependency)도 과감히 버림으로써 전체적인 성능까지 한층 끌어올렸습니다.

3. 보안 관련 대폭 개선

보안 부분에서는 아주 중요한 변경사항들이 여럿 있는데요, 하나씩 알아볼까요?

(1) 경로 라우팅 매칭 방식 변

Express.js 팀은 종합적인 보안 감사를 진행한 뒤, 경로 라우팅 매칭 로직을 아주 핵심적으로 수정했습니다.

바로 정규 표현식 서비스 거부 공격(ReDoS, Regular expression Denial of Service)을 효과적으로 방어하기 위해서죠.

Express 5부터는 정규 표현식 안에 서브-표현식 (예: /(\d+))을 사용하는 것을 더 이상 지원하지 않습니다.

무슨 얘기냐면요, Express 4 시절에는 아래처럼 코드를 쓸 수 있었어요.

app.get('/:id(\\d+)', (req, res) => res.send(`ID: ${req.params.id}`));

 

특정 형식의 경로 파라미터를 매칭하려고요.

하지만 Express 5에서는 이런 식의 접근이 이제 안 됩니다.

왜 그랬냐면요, 정규 표현식이 특정 상황에서 엄청난 성능 리스크를 불러올 수 있기 때문인데요.

예를 하나 들어볼게요.

Express.js 기술위원회 멤버인 블레이크 엠브리(Blake Embrey)가 제시한 정규 표현식 예시가 하나 있습니다.

/^\/flights\/([^\/]+?)-([^\/]+?)\/?$/i 같은 거였는데요, 이걸 /flights/ + '-'.repeat(16_000) + /x와 매칭하면 실제로 300밀리초나 걸렸답니다.

정상 상황이라면 1밀리초 미만으로 끝나야 정상인데 말이죠.

이렇게 어마어마한 시간 차이가 나는 건 정규 표현식이 특정 케이스에서 얼마나 위험할 수 있는지 보여주는 아주 좋은 예시입니다.

그래서 Express 팀은 애플리케이션 보안을 위해서 개발자들에게 강력한 입력 값 검증 라이브러리 (예: joi)를 사용해서 입력 데이터를 엄격하게 검증하고, 악성 공격을 원천 차단하라고 권고합니다.

(2) 정규 표현식 내 와일드카드 사용 규칙 강화

Express 5에서는 정규 표현식 내 와일드카드 사용에도 명확한 규칙을 적용했습니다.

이제 와일드카드는 반드시 명시적으로 이름을 붙이거나 (.*)로 대체해야 합니다.

이러면 라우트 매칭의 명확성과 예측 가능성이 훨씬 높아지죠.

예를 들어, 기존에 /foo* 같은 경로는 이제 /foo(.*)로 바꿔 써야 합니다.

이렇게 하면 개발자가 라우트 매칭 규칙을 훨씬 더 명확히 이해하고, 불명확한 규칙 때문에 생기는 잠재적 문제도 피할 수 있겠죠?

(3) 라우트 내 선택적 파라미터 문법 변경

라우트에서 선택적 파라미터를 표기하는 방식도 상당히 많이 바뀌었습니다.

Express 4에서는 :name? 식으로 선택적 파라미터를 표시했어요.

예시를 보시죠.

app.get('/user/:id?', (req, res) => res.send(req.params.id || 'No ID'));

 

그런데 Express 5에서는 이게 {/:name} 형태로 바뀌었습니다.

아래처럼요.

app.get('/user{/:id}', (req, res) => res.send(req.params.id || 'No ID'));

문법이 좀 달라져서 기존 코드를 조금 수정해야 하지만, 오히려 이게 라우트 규칙을 더 직관적이고 알기 쉽게 만들어 줍니다.

(4) 정규 캡처 그룹 파라미터 접근 방식 변경

정규 캡처 그룹 안에서, 이제는 이름 없는 파라미터를 인덱스로 접근하는 게 안 됩니다.

반드시 파라미터에 이름을 붙여야 해요.

Express 4에서는 이렇게 썼잖아요?

app.get('/user(s?)', (req, res) => res.send(req.params[0])); // 여기서 0은 's'를 리턴함

 

근데 Express 5에서는 꼭 이름을 명시해야 합니다.

app.get('/user:plural?', (req, res) => res.send(req.params.plural));

 

이렇게 하면 인덱스 헷갈려서 생기는 실수를 막을 수 있고, 코드의 가독성과 유지보수성도 확 올라갑니다.

(5) HTTP 상태 코드 유효성 검사 강화

Express 5에서는 HTTP 상태 코드의 유효성을 엄격하게 검사합니다.

이는 조용히 실패하는 걸 막고, 개발자가 디버깅 난관에 빠지지 않게 하려는 중요한 방어 장치인데요.

Express 4에서는 아래처럼 코드를 썼어도

res.status(978).send('Invalid status');

 

상태 코드 978이 유효하지 않음에도 에러가 나지 않고 그냥 조용히 실패해 버렸어요.

이러면 문제 생겼을 때 찾기가 너무 힘들잖아요?

하지만 Express 5에서는 똑같은 코드를 쓰면 직접 에러를 던집니다.

개발자가 문제점을 바로 발견하고 고치게끔 말이죠.

덕분에 개발 효율도 올라가고 애플리케이션 안정성도 훨씬 높아집니다.

4. 비동기 미들웨어와 라우트에서의 에러 핸들링 대폭 간소화

Express.js 5의 가장 큰 변화 중 하나는 바로 비동기 미들웨어와 라우트에서 에러를 다루는 방식이 훨씬 더 간결하고 효율적으로 바뀌었다는 점입니다.

이제는 거부된 프로미스(rejected promise)가 자동으로 에러 핸들링 미들웨어로 전달되거든요.

개발자가 더 이상 일일이 try/catch 블록을 쓸 필요가 없어졌습니다.

Express 4에서는 비동기 요청을 처리할 때 보통 이렇게 썼잖아요?

app.get('/data', async (req, res, next) => {
    try {
        const result = await fetchData();
        res.send(result);
    } catch (err) {
        next(err);
    }
});

 

근데 Express 5에서는 이렇게 간단하게 끝납니다.

app.get('/data', async (req, res) => {
    const result = await fetchData();
    res.send(result);
});

 

이 개선 덕분에 코드 양도 확 줄고, 구조도 훨씬 선명해졌으며 에러 발생 확률도 낮아졌습니다.

5. 업그레이드 관련 주의사항

Express 팀은 기존 기능 망가지는 것(브레이킹 체인지, breaking change)을 최소화하려고 정말 노력했지만, 그래도 기존 코드를 새 버전으로 올리실 분들은 매우 조심해야 합니다.

업그레이드 과정에서 다양한 호환성 문제들이 나타날 수 있어요.

위에서 말씀드린 문법 변경이라든지 노드제이에스 버전 요구 사항 같은 것들 말이죠.

그러니 개발자분들은 반드시 공식 마이그레이션 가이드(Migration Guide)를 샅샅이 살펴보시고, 가이드에 나온 단계대로 차근차근 업그레이드를 진행하셔야 애플리케이션이 문제없이 잘 옮겨집니다.

Express.js는 오픈제이에스 재단(OpenJS Foundation, At-Large 카테고리)의 중요한 프로젝트로서, 언제나 노드제이에스 개발자들을 든든하게 뒷받침해 왔습니다.

개발자 여러분은 완전한 릴리즈 노트(release notes)를 읽어보시면 더 많은 기술적 세부사항과 예시들을 깊이 이해할 수 있을 거고요, 그러면 Express.js 5.0.0의 새로운 기능들을 십분 활용해서 훨씬 더 좋은 노드제이에스 애플리케이션을 만들 수 있을 겁니다.

분명 Express.js 5.0.0의 도움으로 노드제이에스 개발 생태계는 한 단계 더 도약할 것입니다.