아랄라랄라
R 스토리
아랄라랄라
전체 방문자
오늘
어제
  • All (208)
    • Web (153)
      • Markup | WEB (9)
      • Styles (45)
      • javascript (32)
      • jquery (28)
      • vue (16)
      • react (18)
      • more (5)
    • IT (32)
      • CS (3)
      • git hub (5)
      • UI | UX (18)
      • more (6)
    • ETC (23)
      • 이슈노트 (13)
      • 스터디 (10)
      • 아랄라 ☞☜ (0)
      • JOB🛠 (0)

인기 글

반응형
hELLO · Designed By 정상우.
아랄라랄라

R 스토리

ETC/이슈노트

Next.js App Router DELETE API 404 해결기

2026. 5. 14. 10:17

Next.js App Router DELETE API 404 해결기

“GET은 되는데 DELETE만 404 나는 이유”

최근 Next.js + TypeScript + App Router 기반으로 관리자 페이지 CRUD를 만들다가 꽤 헷갈리는 이슈를 만났다.

상황은 단순했다.

  • /api/ads/1 GET 요청은 정상
  • 그런데 DELETE 요청만 404
  • route.ts 안의 console.log도 실행되지 않음

처음에는:

  • fetch 문제인가?
  • API 경로 문제인가?
  • use client 문제인가?
  • Turbopack 문제인가?

엄청 헷갈렸는데, 원인은 의외로 params 구조였다.

 

 

 

 


 

문제 상황

route.ts

import { NextResponse } from "next/server";
import { ads } from "@/lib/dummy-data";

export async function DELETE(
    req: Request,
    { params }: { params: { id: string } }
) {
    const id = Number(params.id);

    const index = ads.findIndex((a) => a.id === id);

    if (index === -1) {
        return NextResponse.json(
            { message: "not found" },
            { status: 404 }
        );
    }

    ads.splice(index, 1);

    return NextResponse.json({
        message: "deleted",
    });
}

 

 

DeleteModal.tsx

const response = await fetch(`/api/ads/${adId}`, {
    method: "DELETE",
});

 

 

 

 

발생한 에러

DELETE http://localhost:3000/api/ads/1 404 (Not Found)

 

그리고 route.ts 안의:

console.log("DELETE 들어옴");

조차 실행되지 않았다.

 

 

이상했던 점

브라우저에서 직접:

http://localhost:3000/api/ads/1

접속하면:

405 Method Not Allowed

이 나왔다.

 

이 의미는:

라우트 자체는 존재함
하지만 해당 HTTP Method를 처리 못함

 

즉:

  • API 경로 자체는 정상
  • route.ts도 인식 중
  • 그런데 DELETE handler만 정상 실행 안 되는 상태

 

 

 

 

 

 

 

진짜 원인

문제는 params 타입이었다.

현재 프로젝트 환경:

  • Next.js 16
  • App Router
  • React 19
  • Turbopack

이 조합에서는 route handler의 params가 Promise 형태로 전달될 수 있다.

 

 

잘못된 코드

{ params }: { params: { id: string } }

이건 동기 객체라고 가정한 코드였다.

 

하지만 실제 runtime에서는:

params = Promise

형태로 전달되고 있었다.

 

 

해결 방법

수정 후

import { NextResponse } from "next/server";
import { ads } from "@/lib/dummy-data";

export async function DELETE(
    req: Request,
    { params }: { params: Promise<{ id: string }> }
) {
    const { id } = await params;

    const adId = Number(id);

    const index = ads.findIndex((a) => a.id === adId);

    if (index === -1) {
        return NextResponse.json(
            { message: "not found" },
            { status: 404 }
        );
    }

    ads.splice(index, 1);

    return NextResponse.json({
        message: "deleted",
    });
}

 

 

왜 이게 중요할까?

App Router의 핵심 특징 중 하나는:

페이지와 API를 비동기 기반으로 통합 처리한다는 것

 

특히 최신 Next.js에서는:

  • page.tsx
  • layout.tsx
  • route.ts

모두 async 기반 흐름으로 통합되는 방향이다.

그래서 route.ts에서도 params가 Promise 형태로 전달될 수 있다.

 

 

내가 헷갈렸던 포인트

page.tsx에서는 이미 이렇게 쓰고 있었다

const { id } = await params;

 

그런데 route.ts에서는 예전 방식처럼:

params.id

로 사용하고 있었다.

 

즉:

  • page.tsx는 최신 async 방식
  • route.ts는 예전 sync 방식

이 섞여 있었던 것.

 

 

 

이번에 이해한 핵심

App Router에서 params는 “항상 일반 객체”라고 생각하면 안 된다.

환경/버전에 따라:

params: Promise<{ id: string }>

형태일 수 있다.

 

 

정리

DELETE만 안 되었던 이유

route.ts에서 params를 동기 객체처럼 사용했기 때문

 

 

 

해결 방법

const { id } = await params;

 

 

 

느낀 점

이번 이슈로:

  • Server Component
  • Route Handler
  • App Router의 async 구조
  • params 처리 방식

이 어떻게 연결되는지 조금 더 이해하게 됐다.

특히 App Router는 “비동기 기반 프레임워크”라는 걸 체감한 디버깅이었다 😄

728x90
저작자표시 (새창열림)

'ETC > 이슈노트' 카테고리의 다른 글

[이슈노트] iOS 이슈 모음 #10 (video 자동 재생, line 이슈)  (1) 2025.04.11
[이슈노트] iOS 이슈 모음 #9 (15 이하에서 mask 이슈)  (2) 2024.10.25
[이슈노트] iOS 이슈 모음 #8 (14 이하에서 gap 이슈)  (0) 2024.04.19
[이슈노트] iOS 이슈 모음 #7 (구버전에서 swiper 터치 슬라이드 이슈)  (0) 2023.04.10
[이슈노트] iOS 이슈 모음 #6 (letter-spacing, position: sticky, label 텍스트 줄바꿈)  (0) 2022.11.17

티스토리툴바