จัดการกับ XMLHttpRequest โดยใช้ miragejs

ในการพัฒนา Front-end นั้น บางกรณี เช่น ในขั้นตอนการพัฒนาแอพต้นแบบ นักพัฒนาอาจมีความจำเป็นจะต้องเรียกใช้ข้อมูลจาก Back-end API หลายคนอาจเลือกใช้ jsonserver เพื่อจำลองเป็น Back-end API ในขณะที่ Backend-API ตัวจริง ยังพัฒนาไม่แล้วเสร็จ แต่ jsonserver เองก็อาจจะสามารถตอบโจทย์การเรียกใช้ข้อมูลแบบง่ายได้เท่านั้น อีกครั้งยังไม่สามารถรองรับการทำ Authentication, JWT, Authorization ซึ่งเราสามารถแก้ปัญหาเหล่านี้ได้โดยใช้ไลบรารี่ที่ชื่อว่า miragejs

ทำความรู้จักกับไลบรารี่ miragejs

การทำงานของ miragejs จะใช้การ Intercept การส่ง XMLHttpRequest ทั้งหมดของบราวเซอร์ เพื่อให้เราสามารถเขียน Process หรือ Response ได้ตามที่เราต้องการ ซึ่งเราสามารถใช้ miragejs กับไลบรารี่ Front-end ที่พัฒนาบนภาษา JavaScript เช่น React.js, Vue.js และ อื่นๆ ได้ทุกตัว

การติดตั้งไลบรารี่ miragejs

Terminal

yarn add miragejs

การใช้งานไลบรารี่ miragejs

โค้ดในส่วนนี้จะเป็นเสมือนการจำลองการ Response ของ Back-end API โดยเราจะกำหนด Route ตามที่แอพของเราต้องการจะเรียกใช้

Code

import { Server } from 'miragejs'

new Server({
    routes() {
        this.get('/users', () => {
            return [
                { id: 1, name: 'Luke' },
                { id: 2, name: 'Leah' },
                { id: 3, name: 'Anakin' }
            ]
        })
    }
})

ใน Vue.js เราจะเขียนโค้ดส่วนนี้ไว้ที่ไฟล์ src/main.js, และ ที่ไฟล์ src/index.js ในกรณีของ React.js

สำหรับโค้ดในส่วนของ Front-end ก็จะการเขียนเพื่อเรียกใช้ XMLHttpRequest ปกติเหมือบกับในกรณีที่เป็นการเรียกข้อมูลจาก Back-end API จริง

Component

async function getUsers() {
    const res = await axios.get('/users')

    console.log(res.data)
}

img

เมื่อมีการส่ง XMLHttpRequest จากภายในแอพ บราวเซอร์ก็จะถูก Intercept โดย miragejs

การตั้งค่า NODE_ENV

เราอาจจะตั้งค่าให้กับ NODE_ENV สำหรับใช้ใน Development และ Production ตามตัวอย่างด้านล่าง

env.development

REACT_APP_API=
VUE_APP_API=

env.production

REACT_APP_API=https://jsonplaceholder.typicode.com
VUE_APP_API=https://jsonplaceholder.typicode.com

Code

if (process.env.NODE_ENV === 'development') {
    new Server({
        ...
    })
}

โดยปกติเราน่าจะมีการใช้งาน miragejs เฉพาะในขั้นตอน Development เท่านั้น

Component

async function getUsers() {
    const res = await axios.get(`${ REACT_APP_API }/users`)

    console.log(res.data)
}

การเขียนโค้ดเพื่อส่ง XMLHttpRequest ก็จะใช้ตัวแปรตาม NODE_ENV

Delay Responses

เราสามารถกำหนดให้ miragejs ทำการ Response โดยมีการหน่วงเวลาเพื่อสะดวกในการทดสอบ เช่น กรณีของการใช้งาน Spinner

Code

new Server({
    routes() {
        this.get('/users', () => {
            return [...]
        }, { timing: 4000 })
    }
})

ReSTful Routes

ตัวอย่างการเขียนโค้ดเพื่อจำลองการทำงานของ ReSTful Back-end API

Code

new Server({
    routes() {
        this.get('/users', () => {
            ...
        })

        this.post('/users', () => {
            ...
        })

        this.patch('/users/:id', () => {
            ...
        })

        this.del('/users/:id', () => {
            ...
        })
    }
})

Parameterized Route

miragejs สามารถรองรับ Parameterized Route ได้เช่นกัน ตามตัวอย่างโค้ดด้านล่าง

Code

new Server({
    routes() {
        this.get('/users/:id', (schema, request) => {
            const { id } = request.params

            return { id }
        })
    }
})

Request's Body

ตัวอย่างโค้ดในการอ่านค่าจาก Request Body

Code

new Server({
    routes() {
        this.post('/users', (schema, request) => {
            const user = JSON.parse(request.requestBody) // parsing is required

            return user
        })
    }
})

Custom Response

miragejs สามารถทำ Custom Response เช่น การกำหนด Custom HTTP Status Code ได้เช่นกันตามตัวอย่างโค้ดด้านล่าง

Code

import { Response } from 'miragejs'

new Server({
    routes() {
        this.post('/users', (schema, request) => {
            const user = request.requestBody

            return new Response(
                201,
                { 'x-custom-header': 'foo/bar' },
                user // object or array
            )
        })
    }
})

schema

เราสามารถใช้ schema เพื่อเป็นเสมือนฐานข้อมูลของ miragejs รองรับ Data Manipulation เช่น การทำ CRUD เป็นต้น

Code

new Server({
    seeds(server) {
        server.db.loadData({
            users: [
                { name: 'Steve' }, // id will be added automatically
                { name: 'John' }
            ]
        })
    },

    routes() {
        this.get('/users', schema => {
            return schema.db.users
        })

        this.get('/users', (schema, request) => {
            const { id } = request.params

            return schema.db.users.find(id) // schema's method
        })

        this.post('/users', (schema, request) => {
            const user = JSON.parse(request.requestBody) // parsing is required

            return schema.db.users.insert(user)
        })
    }
})

Authorization

ตัวอย่างโค้ดในการทำ Authorization โดยใช้การอ่านค่า authorization จาก Header ของ Request

Code

new Server({
    routes() {
        this.get('/users', (schema, request) => {
            const header = request.requestHeaders
            const authorization = header['authorization']

            if (!authorization) {
                return new Response(
                    401,
                    {},
                    { message: '401 Unauthorized' }
                )
            }

            return schema.db.users
        })
    }
})

つづく