iT邦幫忙

2023 iThome 鐵人賽

DAY 5
1

上一篇已經介紹route,接著以實際專案會用到的api來繼續實作

大綱

1.文章資料API規劃
2.取得單一文章資料API開發
3.錯誤處理(Error Handling)


1. 文章資料API規劃

以下為目前文章相關的API

route verb description
/posts POST 新增文章
/posts GET 取得所有文章
/posts/:postId PUT 更新文章
/posts/:postId DELETE 刪除文章
/posts/:postId GET 取得單一文章內容

補充:什麼是RESTful API

我們將以上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;

2.取得單一文章資料API開發

透過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 就可以看到取回來的資料了
https://ithelp.ithome.com.tw/upload/images/20230920/201365580khQjLX2Pi.jpg

3. 錯誤處理

剛剛已經成功取回資料了,那當我們輸入不存在的id時會怎麼樣呢?
https://ithelp.ithome.com.tw/upload/images/20230920/20136558dnsoK6GjnO.jpg
可以看到會回傳一個空值也就是沒回傳任何東西,但這種不明確的回應會客戶端不曉得是哪裡出了問題。
所以我們要在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(不存在的文章),就會看到錯誤訊息了。
https://ithelp.ithome.com.tw/upload/images/20230920/20136558F6wRddVEM5.jpg

新增錯誤處理中介軟體(error handling middleware)

使用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}); 
});

https://ithelp.ithome.com.tw/upload/images/20230920/20136558ibqBAVqNXE.jpg
雖然顯示的是相同的錯誤訊息,但這樣作法能讓錯誤處理更乾淨和容易維護~

參考資料:

什麼是RESTful API
Express.js Error Handling
Express.js get parameter


上一篇
[Day4]實作開始-設定後端專案和Express路由
下一篇
[Day6] 使用MVC架構:建立Controller和ErrorModel
系列文
初探全端之旅: 以MERN技術建立個人部落格31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言