3 middleware hữu ích khi sử dụng express rest api

Expressjs giờ đây không còn quá xa lạ với những anh em làm web hay sử dụng expressjs rest api với môi trường node nữa rồi. Nhưng hẳn nhiều trường hợp trong khi làm rest api khi check data thì chỉ có anh em làm nhiều mới biết, null, length, underfined... 

Nhưng ... 

"Thật tình cờ, tình cờ biết đến nhau từ bao giờ" như ca sĩ hà oikio hát trong bài "nếu như" thì tình cờ tôi cố đi tìm cho mình một middleware để check data trước khi save dữ liệu xuống database thì vô tình đọc được một bài post "Three useful Express middleware" post by "zellwk.com' .

Bài viết liên quan tới express:

1 - async await error handling in express

2 - Ví dụ về NodeJS Session sử dụng Express Session

Nay tôi xin share lại và giải thích kỹ hơn về 3 middleware này. Trong đó tôi có làm một ví dụ đầy đủ về bài học này. Sau khi các bạn đọc xong thì có thể download code trên github về máy của mình. Nhớ đọc xong rồi mới lấy về.

Three useful Express middleware

Middleware morgan

Thật ra morgan thì hầu như bạn nào cũng sử dụng để ghi log rồi, và tôi cũng đã sử dụng từ lâu rồi chứ không phải tới bây giờ mới dùng. Hơn nữa do repush lại nên tôi cũng cần phải giải thích lại cho các bạn kỹ hơn. middleware morgan dùng để request logger. Nó cho bạn biết một số điều khi máy chủ của bạn nhận được yêu cầu. Và cho chúng ta nhiều thông tin hơn về client chẳng hạn như: 

  1. Date 
  2. HTTP version 
  3. Method 
  4. Referrer 
  5. Remote 
  6. Address 
  7. Remote 
  8. User 
  9. Request header 
  10. Response headers 
  11. Response time 
  12. Status code 
  13. Url of the request 
  14. User Agent

Morgan đi kèm với 5 format được xác định để ghi log trước để bạn lựa chọn: 

  1. Combined 
  2. Common 
  3. Short 
  4. Dev 
  5. Tiny

Tương ứng với 5 định dạng khi chúng ta gọi http://localhost:3000 như trong ví dụ trên github

Combined:

::1 - - [23/Nov/2019:09:45:16 +0000] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36 OPR/65.0.3467.48"
::1 - - [23/Nov/2019:09:45:16 +0000] "GET /favicon.ico HTTP/1.1" 404 150 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36 OPR/65.0.3467.48"
::1 - - [23/Nov/2019:09:45:16 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36 OPR/65.0.3467.48"
::1 - - [23/Nov/2019:09:45:16 +0000] "GET /favicon.ico HTTP/1.1" 404 150 "http://localhost:3000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36 OPR/65.0.3467.48"

Common

::1 - - [23/Nov/2019:09:46:12 +0000] "GET / HTTP/1.1" 304 -

Short

::1 - GET / HTTP/1.1 304 - - 5.275 ms

Dev

GET / 304 4.764 ms - -

Tiny

GET / 304 - - 4.793 ms

Bổ sung thêm cho bài viết chính là Ngoài ra chúng ta có thể định nghĩa riêng của chúng ta thông qua cú pháp sau:

morgan(':method :url :status :res[content-length] - :response-time ms')

Cách sử dụng middleware morgan

const morgan = require('morgan');
app.use(morgan('tiny'))

như vậy là xong phần middleware morgan

Middleware camelcase-keys

camelcase-keys nhiệm vụ của middleware này là convert tất cả các thuộc tính trên form trước khi xống backend để get value. 

Ví dụ : Trong form submit ta có

  input name="first-name"

Thậm chí còn dev còn đặt name="First-Name" or "first_name", "first-name", or "FirstName". Nếu điều đó xảy ra thì ông nào làm rest api thì check mệt mỏi luôn, do đó camelcase-keys chính là một middleware để xử lý việc này:

Cách sử dụng middleware camelcase-keys

const camelcaseKeys = require('camelcase-keys')

const camelcase = () => {
  return function (req, res, next) {
    req.body = camelcaseKeys(req.body, { deep: true })
    req.params = camelcaseKeys(req.params)
    req.query = camelcaseKeys(req.query)
    next()
  }
}
app.use(camelcase())

Và cho dù ai có đặt name gì đi nữa thì về dưới backend chúng ta convert thành firstName

app.post('/example-camelcase', (req, res) => {
    console.log(req.body)
    res.status(200).json({elements: req.body.firstName})
})

Quá hay, ông nào nghĩ ta cái này hay hết :D

Cuối cùng là middleware omit-empty

ở bài viết gốc thì install omitEmpty nhưn tôi check thì nó bị falied. Có thể ông ghi sai Tập trung nè, nó có nhiệm vụ chỉ lấy giá trị tồn tại và đồng thời có giá trị ví dụ:

const object = {
  null: null, 
  undefined: undefined,
  emptyString: '',
  emptyArray: [],
  emptyObject: {},
  filled: 'yay'
}

console.log(omitEmpty(object))
// {
//   filled: 'yay' // nó chỉ lấy thằng này thôi
// }

Điều đó giúp cho ta trong những trường hợp sau đây. Vì dụ trên form gửi xuống một array skills chẳng hạn:

fetch('/endpoint', {
  method: 'post',
  headers: { 'Content-Type': 'application/json' }
  body: JSON.stringify({
    name: 'Zell',
    skills: ['coding', 'designing', 'writing']
  })
}

Dưới thằng làm rest api đương nhiên phải check

if(skills.length){
    //add database
}

Đúng, chuẩn nhưng lỡ khi thằng nào nó ba gai nó thấy length = 0 thì nó không bỏ luôn nghĩa là :

fetch('/endpoint', {
  method: 'post',
  headers: { 'Content-Type': 'application/json' }
  body: JSON.stringify({
    name: 'Zell'
  })
}

Nó chơi vậy, mình nhận được một error liền: "Cannot read property 'length' of undefined ". Rồi xong qua múc nó, xxx xxxxx bal blaaa... Để hoà giải trong trường hợp này thì omitEmpty là hữu ích, và tôi đánh giá nó rất hay

Cách sử dụng middlewware omit-empty

const omitEmpty = require('omit-empty')

const removeEmptyProperties = () => {
  return function (req, res, next) {
    req.body = omitEmpty(req.body)
    req.params = omitEmpty(req.params)
    req.query = omitEmpty(req.query)
    next()
  }
}
app.use(removeEmptyProperties())

Lúc đó mình chỉ cần sử dụng nó như:

app.post('/example-omitempty', (req, res) => {
    const { skills } = req.body
  
    if (skills) {
        // Add skills to database

        return res.json('add database')
    }
    return res.json('skills not avaibale')
})

Xong rồi đó, mấy ông chưa hiểu thì download source github để về check xem có đúng không. Với lại để áp dụng vào cho nó cool. 

Repush: https://zellwk.com/blog/express-middlewares/