连假最後一天!分享了一些关於 Next.js 这个框架,虽然他是 React 的框架,可是你们知道吗?Next.js 也可以同时实作後端喔!没错,前後端全包~ 怎麽做呢?今天来看看 Next.js 的 API Routes,看完应该会有想法怎麽实作,不过看这篇文章之前,可以先看看上一篇关於 Next.js 的 routing 喔!
Next.js 的 API routes 也采用 file-based routing,意思是每个档案代表一个 route,而档案名称 (file name) 会变成 route 的 path name (路径名称)。Next.js 会把 pages/api
资料夹 / 目录里面的所有档案看成 route (路径) 的一部分:
pages/api/index.js
代表 /
API routepages/api/user.js
代表 /user
API routeAPI routes 里的所有程序码是属於後端的部分,所以只会跑在服务器端。这代表我们写的 API 不会让我们前端的 bundle size 变大,不会影响网页的下载时间!也是因为是跑在服务器端,我们可以实作各种後端的功能,例如操作资料库~
每个 pages/api
里的档案需要 export 一个 default function (函式) 作为 API 的 request handler (处理请求的函式),然後每个 handler 会有两个 parameters:
req
:request 物件,是一种 http.IncomingMessage,还有包含一些内建的 middlewares
res
:response 物件,是个 http.ServerResponse,加上一些 helper functions
像 Next.js 的 routing 一样,API routes 也支援 dynamic (动态) routing。如果我们对 pages/api/posts/[pid]/comments/[cid].js
路径发个 /api/posts/world/comments/hello
的请求:
export default function handler(req, res) {
const { pid, cid } = req.query
res.end(`Comment #${cid} for post #${pid}`)
}
上面的 API 会回传 Comment #hello for post #world
。
每个 index 档案代表根目录,所以
pages/api/posts.js
代表 /api/posts
API routepages/api/posts/index.js
也代表 /api/posts
API route注意:
pages/api/posts/[pid].js
并不代表/api/posts
只代表/api/posts/1
,/api/posts/2
等
属於 dynamic API routes 的一种,不过 catch all 的意思是不需要一个一个定义动态的部分,把所有动态的资讯抓起来,让 route 比较弹性,写法跟其余参数(rest parameter)一样。
pages/api/posts/[...slug].js
可以代表 /api/posts/a
也可以是 /api/posts/a/b
,/api/posts/a/b/c
等slug
可以是 param
或是其他东西都可以,这些动态资讯也会出现在 query
物件里面,例如 /api/posts/a/b/c
的 query
会是:
{ "slug": ["a", "b", "c"] }
跟 pages 的 optional catch all routes 一样,只要把 catch all 的 [...slug]
改成 [[...slug]]
就会变成 optional catch all。意思是 slug
这个 array (阵列) 可以是不存在的,
pages/posts/[[...slug]].js
可以代表 /posts/a
也可以是 /posts/a/b
,/posts/a/b/c
等,不过也可以代表 /posts
所以当我们发请求到 /api/posts
,query
物件会是空物件
{ } // GET `/api/post` (空物件)
{ "slug": ["a"] } // `GET /api/post/a`
{ "slug": ["a", "b"] } // `GET /api/post/a/b`
Next.js 有提供内建的 middlewares 塞进去 req
物件里,除了内建的之外,我们还可以用其他 Connect / Express 相容的 middlewares。
req.cookies
:请求的 cookies,预设为 {}
req.query
:请求的 query string,预设为 {}
req.body
:已经被 parse 的请求 body,会根据 content-type
做 parse,当没有 body 时会回传 null
。如果不想要 body 被 parse,可以在 API route 档案里加 config
:
export const config = {
api: {
bodyParser: false,
},
}
除了 body parser 的 config 以外,还有更多 API 相关的 config 可以看这里喔~
想要在我们的 API routes 增加其他 middlewares 也可以!直接在 handler function 里执行该 middleware 再继续跑 API 本身的 code,像:
import Cors from 'cors'
// initialize cors middleware
const cors = Cors({
methods: ['GET', 'HEAD'],
})
// helper method 去执行 middleware,结束後才继续跑下去
// 发生错误时跳 error
function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
// fn 为 middleware
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}
return resolve(result)
})
})
}
async function handler(req, res) {
// 先跑 middleware
await runMiddleware(req, res, cors)
// API 本身的逻辑
res.json({ message: 'Hello Everyone!' })
}
export default handler
虽然 API routes 不是 Express.js,可是 Next.js 有提供一些类似的 helper functions 来帮助我们开发而提升 DX (开发者体验):
res.status(code)
:设定 response 的 status code (要符合 HTTP status code)res.json(body)
:回传 JSON 为 response 给浏览器 (客户端)res.send(body)
:回传 HTTP response,body 可以是 string
,object
,或是 Buffer
res.redirect([status,] path)
:导页,把浏览器导到别 path 或 URL,status
是 HTTP status code,是个非必须的 parameter,预设为 307
(Temporary redirect
).我们看完 API routes 之後,可以开始做一些全端专案了(误
大家会想用 API routes 做哪些事呢?有了这个真的让前後端开发简单一些~
祝大家明天上班上课愉快!
晚安 <3
前一章我们提到了daemonset 建立出来的pod,不在deafult的Namespaces内,所...
简介 useReducer 简单来说就是 useState 进阶用法。而且写法上其实跟 Redux ...
今天是陪了我们两天的刚体的最後一集,是不是开始有点想念它了呢? 那没关系,好好珍惜我们今天跟刚体相处...
本节将接续上节,调整了一下request message中的ExpireDate 正确的respon...
今天我们会实作两支程序,第一支程序要做让使用者输入两个数,若这两个数相起来是100,则显示a,是20...