๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Next.js

[๋‚ด๋ณด๋‚ด๋ฒˆ] Next.js docs - Dynamic API Routes

๋‚ด๋ณด๋‚ด๋ฒˆ(๋‚ด๊ฐ€ ๋ณด๋ ค๊ณ  ๋‚ด๊ฐ€ ๋ฒˆ์—ญํ•œ...) Next.js docs

2021๋…„ 4์›” 13์ผ ๊ธฐ์ค€ Next.js ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ–ˆ๋‹ค.

โ€ป ์˜์–ด ์ „๊ณต์ž๋„ ํ•ด์™ธ ์œ ํ•™ํŒŒ๋„ ์•„๋‹ˆ๊ธฐ์— ๋ฒˆ์—ญ์—๋Š” ์˜์—ญ, ์˜ค์—ญ, ๊ตฌ๊ธ€ ๋ฒˆ์—ญ์ด ๋ฌด์ˆ˜ํžˆ ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜ผ์ž ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•ด๊ฐ€๋ฉฐ ๋ฒˆ์—ญํ•˜๋‹ค ๋ณด๋‹ˆ ์˜คํƒ€๋„ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค. ์ •ํ™•ํ•œ ๋‚ด์šฉ์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ง์ ‘ ์‚ดํŽด๋ณด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ •๋ณด๋“ค์„ ๋” ์ฐพ์•„๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

(ํ•˜์ง€๋งŒ ๋Œ“๊ธ€ ํ”ผ๋“œ๋ฐฑ๋„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜ƒ )

Next.js ๊ณต์‹๋ฌธ์„œ ํ™•์ธํ•˜๊ธฐ>>

 

API Routes: Dynamic API Routes | Next.js

You can add the dynamic routes used for pages to API Routes too. Learn how it works here.

nextjs.org


API routes support dynamic routes, and follow the same file naming rules used for pages.
API ๋ผ์šฐํŠธ๋Š” ๋™์  ๊ฒฝ๋กœ๋ฅผ ์ง€์›ํ•˜๊ณ  ํŽ˜์ด์ง€์—์„œ๋„ ์‚ฌ์šฉ๋˜์—ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ช…๋ช… ๊ทœ์น™์„ ๋”ฐ๋ฅธ๋‹ค. 

For example, the API route pages/api/post/[pid].js has the following code:
์˜ˆ๋ฅผ ๋“ค์–ด, API ๋ผ์šฐํŠธ pages/api/post/[pid].js๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ๋‹ค: 

export default function handler(req, res) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}

Now, a request to /api/post/abc will respond with the text: Post: abc.
์ด์ œ /api/post/abc์— ๋Œ€ํ•œ ์š”์ฒญ์€ Post: abc๋ผ๋Š” ํ…์ŠคํŠธ๋กœ ์‘๋‹ต๋ฐ›๋Š”๋‹ค. 

Index routes and Dynamic API routes ์ธ๋ฑ์Šค ๋ผ์šฐํŠธ์™€ ๋™์  API ๋ผ์šฐํŠธ

A very common RESTful pattern is to set up routes like this:
๋ผ์šฐํŠธ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๋งค์šฐ ๋ณดํŽธ์ ์ธ RESTful ํŒจํ„ด์€ ์ด์™€ ๊ฐ™๋‹ค:

  • GET api/posts - gets a list of posts, probably paginated
  • GET api/posts/12345 - gets post id 12345
  • GET api/posts - ํฌ์ŠคํŠธ ๋ชฉ๋ก์„ ๋ฐ›๋Š”๋‹ค. ์•„๋งˆ๋„ ํŽ˜์ด์ง€ ๋งค๊น€์ด ๋˜์–ด์žˆ๋Š”
  • GET api/posts/12345 - id๊ฐ€ 12345์ธ ํฌ์ŠคํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค

We can model this in two ways:
์ด๊ฒƒ์„ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ชจ๋ธํ•  ์ˆ˜ ์žˆ๋‹ค: 

  • Option 1:
    • /api/posts.js
    • /api/posts/[postId].js
  • Option 2:
    • /api/posts/index.js
    • /api/posts/[postId].js

Both are equivalent. A third option of only using /api/posts/[postId].js is not valid because Dynamic Routes (including Catch-all routes - see below) do not have an undefined state and GET api/posts will not match /api/posts/[postId].js under any circumstances.
๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๊ฐ™๋‹ค. ๋‹จ /api/posts/[postId].js๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์„ธ ๋ฒˆ์งธ ์˜ต์…˜์€ ๋™์  ๊ฒฝ๋กœ(๋ชจ๋“  ๋ผ์šฐํŠธ ํฌ์ฐฉ(Catch-all routes)์„ ํฌํ•จํ•ด์„œ - ํ•˜๋‹จ ๋‚ด์šฉ ์ฐธ์กฐ)๊ฐ€ undefined ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๊ณ  GET api/posts๊ฐ€ /api/posts/[postId].js ์™€๋Š” ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๋งค์น˜๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด ์˜ต์…˜์€ ์œ ํšจํ•˜์ง€ ์•Š๋‹ค. 

Catch all API routes ๋ชจ๋“  API ๋ผ์šฐํŠธ ํฌ์ฐฉ

API Routes can be extended to catch all paths by adding three dots (...) inside the brackets. For example:
API ๋ผ์šฐํŠธ๋Š” ์  ์„ธ ๊ฐœ(...)๋ฅผ ๊ด„ํ˜ธ ์•ˆ์— ์ถ”๊ฐ€ํ•จ์œผ๋กœ ๋ชจ๋“  ๋ผ์šฐํŠธ๋ฅผ ํฌ์ฐฉํ•˜๊ธฐ ์œ„ํ•ด ํ™•์žฅ๋  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด:

  • pages/api/post/[...slug].js matches /api/post/a, but also /api/post/a/b, /api/post/a/b/c and so on.
  • pages/api/post/[...slug].js ๋Š” /api/post/a์™€ ๋งค์น˜๋˜์ง€๋งŒ /api/post/a/b, /api/post/a/b/c ๋“ฑ์˜ ๊ฒฝ๋กœ์™€๋„ ๋งค์น˜๋œ๋‹ค. 
๋…ธํŠธ: slug๋ง๊ณ  [...param] ๊ฐ™์ด ๋‹ค๋ฅธ ์ด๋ฆ„๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

Matched parameters will be sent as a query parameter (slug in the example) to the page, and it will always be an array, so, the path /api/post/a will have the following query object:
๋งค์น˜๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ(์˜ˆ์‹œ์˜ slug)๋กœ ํŽ˜์ด์ง€์— ๋ณด๋‚ด์ง„๋‹ค. ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ•ญ์ƒ ๋ฐฐ์—ด์ด๋ฉฐ, /api/post/a ๊ฒฝ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ ๊ฐ์ฒด๋ฅผ ๊ฐ–๋Š”๋‹ค: 

{ "slug": ["a"] }

And in the case of /api/post/a/b, and any other matching path, new parameters will be added to the array, like so:
๊ทธ๋ฆฌ๊ณ  /api/post/a/b์˜ ๊ฒฝ์šฐ์™€ ๊ฒฝ๋กœ๊ฐ€ ๋งค์น˜๋˜๋Š” ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋„ ์ƒˆ๋กœ์šด ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์ด ๋ฐฐ์—ด์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”๊ฐ€๋œ๋‹ค:

{ "slug": ["a", "b"] }

An API route for pages/api/post/[...slug].js could look like this:
pages/api/post/[...slug].js๋ฅผ ์œ„ํ•œ API ๋ผ์šฐํŠธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค: 

export default function handler(req, res) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}

Now, a request to /api/post/a/b/c will respond with the text: Post: a, b, c.
์ด์ œ /api/post/a/b/c์— ๋Œ€ํ•œ ์š”์ฒญ์€ `Post: a, b, c` ํ…์ŠคํŠธ๋กœ ์‘๋‹ต๋ฐ›์„ ๊ฒƒ์ด๋‹ค. 

Optional catch all API routes ์„ ํƒ์  API ๋ผ์šฐํŠธ ํฌ์ฐฉ

Catch all routes can be made optional by including the parameter in double brackets ([[...slug]]).
์ด์ค‘ ๋Œ€๊ด„ํ˜ธ ์•ˆ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํฌํ•จํ•˜์—ฌ ๋ชจ๋“  ๋ผ์šฐํŠธ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ํฌ์ฐฉ(catch)ํ•  ์ˆ˜ ์žˆ๋‹ค. ([[...slug]])

For example, pages/api/post/[[...slug]].js will match /api/post, /api/post/a, /api/post/a/b, and so on.
์˜ˆ๋ฅผ ๋“ค๋ฉด, pages/api/post/[[...slug]].js๋Š” /api/post, /api/post, /api/post/a, /api/post/a/b ๋“ฑ๊ณผ๋„ ๋งค์น˜๋œ๋‹ค. 

The main difference between catch all and optional catch all routes is that with optional, the route without the parameter is also matched (/api/post in the example above).
๋ชจ๋“  ๋ผ์šฐํŠธ๋ฅผ ํฌ์ฐฉํ•˜๋Š” ๊ฒƒ(Catch-all routes)๊ณผ ๋ชจ๋“  ๋ผ์šฐํŠธ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ํฌ์ฐฉํ•˜๋Š” ๊ฒƒ์˜ ์ฃผ์š” ์ฐจ์ด์ ์€ ์„ ํƒ์ ์ธ ํฌ์ฐฉ์˜ ๊ฒฝ์šฐ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์–ด๋„ ๋งค์น˜๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. (์œ„์˜ ์˜ˆ์ œ์—์„œ /api/post)

The query objects are as follows:
์ฟผ๋ฆฌ ๊ฐ์ฒด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค: 

{ } // GET `/api/post` (empty object)
{ "slug": ["a"] } // `GET /api/post/a` (single-element array)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (multi-element array)

Caveats ์ฃผ์˜์‚ฌํ•ญ

  • Predefined API routes take precedence over dynamic API routes, and dynamic API routes over catch all API routes. Take a look at the following examples:
    ๋ฏธ๋ฆฌ ์ •์˜๋œ API ๋ผ์šฐํŠธ๋Š” ๋™์  API ๋ผ์šฐํŠธ๋ณด๋‹ค ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’๊ณ  ๋™์  API ๋ผ์šฐํŠธ๋Š” ๋ชจ๋“  API ๋ผ์šฐํŠธ ํฌ์ฐฉ๋ณด๋‹ค ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋“ค์„ ๋ณด์ž:
    • pages/api/post/create.js - Will match /api/post/create
      pages/api/post/create.js๋Š” /api/post/create์™€ ๋งค์น˜๋œ๋‹ค. 
    • pages/api/post/[pid].js - Will match /api/post/1, /api/post/abc, etc. But not /api/post/create
      pages/api/post/[pid].js๋Š” /api/post/1, /api/post/abc ๋“ฑ๊ณผ ๋งค์น˜ ๋˜์ง€๋งŒ /api/post/create์—๋Š” ๋งค์น˜๋˜์ง€ ์•Š๋Š”๋‹ค.
    • pages/api/post/[...slug].js - Will match /api/post/1/2, /api/post/a/b/c, etc. But not /api/post/create, /api/post/abc
      pages/api/post/[...slug].js๋Š” /api/post/1/2, /api/post/a/b/c ๋“ฑ๊ณผ ๋งค์น˜ ๋˜์ง€๋งŒ /api/post/create, /api/post/abc์™€๋Š” ๋งค์น˜๋˜์ง€ ์•Š๋Š”๋‹ค.