上一篇已經介紹route
,接著以實際專案會用到的api來繼續實作
1.文章資料API規劃
2.取得單一文章資料API開發
3.錯誤處理(Error Handling)
以下為目前文章相關的API
route | verb | description |
---|---|---|
/posts | POST |
新增文章 |
/posts | GET |
取得所有文章 |
/posts/:postId | PUT |
更新文章 |
/posts/:postId | DELETE |
刪除文章 |
/posts/:postId | GET |
取得單一文章內容 |
我們將以上api都建立在routes/posts-routes.js
裡面
🔸這篇只有提到取得文章api的邏輯,其他api會在後面篇章補充。
//posts-routes.js
const express = require('express');
const router = express.Router();
//@router POST /api/posts
//@desc 新增文章
//@access Public
router.post("/", (req,res,next)=>{
res.json({message: 'It works!'});
});
//@router GET api/posts
//@desc 取得所有文章
//@access Public
router.get("/",(req,res,next)=>{
console.log('GET Request');
res.json({message: 'It works!'});
});
//@router GET api/posts/:postId
//@desc 取得文章資訊(單一)
//@access Public
router.get("/:postId",(req,res,next)=>{
console.log('GET Request');
res.json({message: 'It works!'});
});
//@router PUT /api/posts/:postId
//@desc 更新文章
//@access Public
router.put("/:postId", (req,res,next)=>{
res.json({message: 'It works!'});
});
//@router DELETE api/posts
//@desc 刪除文章
//@access Public*/
router.delete("/:postId", (req,res,next)=>{
res.json({message: 'It works!'});
});
module.exports = router;
postId
取得文章資料看到上面的程式,其中編輯、刪除、取得都有一個postId
,這個postId
就是文章的uid(唯一標識符Unique_identifier),就像身分證是我們國民的uid,不會跟別人重複。
現在我們要修改取得文章資訊的handle function,要透過postId
把文章資料取回來。
因為現在沒有連接資料庫,所以在檔案裡面先做一個mock data。
//posts-routes.js
const MOCK_POSTS = [
{
id: 'p1',
title: '文章1',
tags:['chatGPT'],
content:'ChatGPT'
},
{
id: 'p2',
title: '文章2',
tags:['frontend'],
content:'Micro frontend'
}
]
...(略)
接著我們修改get 的回傳內容,透過以下的寫法就能取得URL裡面的router parameters
//posts-routes.js
//@router GET api/posts/:postId
//@desc 取得文章資訊(單一).
//@access Public
router.get("/:postId",(req,res,next)=>{
//透過req.params取得URL的parameters
const postId = req.params.postId;
//透過postId在我們的假資料尋找對應的文章內容
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//將找到的文章資料回傳
res.json({post}); //{post:post}的簡寫
});
關於get parameters的使用方式請參考:Get parameter in Express.js
這時我們在瀏覽器輸入https://localhost:5000/api/post/p1
就可以看到取回來的資料了
剛剛已經成功取回資料了,那當我們輸入不存在的id時會怎麼樣呢?
可以看到會回傳一個空值也就是沒回傳任何東西,但這種不明確的回應會客戶端不曉得是哪裡出了問題。
所以我們要在Get api/posts/:postId
裡面加上錯誤處理
//posts-routes.js
//@router GET api/posts/:postId
//@desc 取得文章資訊(單一).
//@access Public
router.get("/:postId",(req,res,next)=>{
//透過req.params取得URL的parameters
const postId = req.params.postId;
//透過postId在我們的假資料尋找對應的文章內容
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//若文章不存在於假資料(資料庫)
if(!post){
return res.status(404).json({ message: '此id的文章不存在'})
}
//將找到的文章資料回傳
res.json({post}); //{post:post}的簡寫
});
此時我們在https://localhost:5000/api/post/p3
(不存在的文章),就會看到錯誤訊息了。
使用error handling middleware
,可以集中處理和管理錯誤,提高程式的可維護性,不需要在每個路由處理程式中都處理相同的錯誤情況(例如:原本可能要在每個route裡面加入console.error()來查看錯誤訊息)
//server.js
const express = require('express');
const app = express();
const port = 5000;
const postRoutes = require('./routes/posts-routes');
app.use('/api/posts',postRoutes);
app.use((err, req, res, next) => {
//將錯誤的堆疊訊息(stack trace)輸出到控制台,以方便進行偵錯
console.error(err.stack);
res.status(err.status || 500);
res.json({
error: {
message: err.message || 'Internal Server Error'
}
});
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
});
然後我們再回去調整posts-routes.js
//posts-routes.js
//@router GET api/posts/:postId
//@desc 取得文章資訊(單一).
//@access Public
router.get("/:postId",(req,res,next)=>{
//透過req.params取得URL的parameters
const postId = req.params.postId;
//透過postId在我們的假資料尋找對應的文章內容
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//若文章不存在於假資料(資料庫)
if(!post){
const error = new Error('此id的文章不存在');
error.status = 404;
return next(error); //會觸發error middleware
}
//將找到的文章資料回傳
res.json({post});
});
雖然顯示的是相同的錯誤訊息,但這樣作法能讓錯誤處理更乾淨和容易維護~
什麼是RESTful API
Express.js Error Handling
Express.js get parameter