Cách xây dựng và dùng Mock API trong app React bằng Mirage.js

Bạn không có sẵn API? Không sao hết! Hãy lập trình và dùng mock API với Mirage.js.

Lập trình Mirage.js

Khi phát triển các ứng dụng full-stack, phần lớn công việc frontend đều phụ thuộc vào dữ liệu tại thời gian thực từ backend.

Điều này có nghĩa rằng bạn phải tạm dừng việc phát triển giao diện người dùng cho đến khi có sẵn API để sử dụng. Tuy nhiên, việc chờ API sẵn sàng thiết lập giao diện người dùng có thể làm giảm đáng kể năng suất và kéo dài thời gian của dự án.

Một cách giải quyết tuyệt vời cho thách thức này liên quan tới việc sử dụng mock API. Những API này cho phép bạn phát triển và kiểm tra frontend bằng dữ liệu bắt chước cấu trúc dữ liệu thật mà không cần dựa vào API thực tế.

Hướng dẫn sử dụng Mirage.js Mock API

Mirage là một thư viện JavaScript, cho phép bạn tạo mock API, hoàn thiện với một server kiểm thử đang chạy ở bên client của ứng dụng web. Điều này có nghĩa bạn có thể kiểm tra code frontend mà không cần lo ngại về tính có sẵn hay hành vi của API backend thực tế.

Lập trình mock API

Để dùng Mirage.js, đầu tiên, bạn cần tạo các endpoint mock API và xác định phản hồi mà chúng sẽ trả về. Sau đó, Mirage.js chặn tất cả các truy vấn HTTP mà code frontend của bạn thực hiện và thay vào đó trả về những phản hồi mock.

Khi API đã sẵn sàng, bạn dễ dàng chuyển sang dùng nó bằng cách chỉ thay đổi cấu hình của Mirage.js.

Tạo server Mock API với Mirage.js

Để minh họa cách thiết lập mock API, bạn sẽ xây dựng một app React cần làm đơn giản bằng backend Mirage.js. Thế nhưng đầu tiên, tạo app React bằng lệnh create-react-app. Ngoài ra, bạn có thể dùng Vite để thiết lập dự án React. Tiếp theo, cài đặt phần phụ thuộc Mirage.js.

npm install --save-dev miragejs

Giờ tạo một phiên bản server Mirage.js nhằm chặn các yêu cầu và mô phỏng phản hồi API, hãy sử dụng phương thức createServer. Phương thức này lấy một đối tượng cấu hình làm tham số.

Đối tượng này bao gồm environmentnamespace cho API. Môi trường này xác định giai đoạn phát triển của API, chẳng hạn như phát triển trong khi namespace là tiền tố được thêm vào tất cả các điểm cuối API.

Tạo file src/server.js mới và bao gồm code sau:

import { createServer, Model } from 'miragejs';

const DEFAULT_CONFIG = {
  environment: "development",
  namespace: "api",
};

export function makeServer({ environment, namespace } = 
  DEFAULT_CONFIG) {
   let server = createServer({
      environment,
      namespace,
      models: {
      Todo: Model, 
    },
  });

  return server;
}

Nếu cần, bạn có thể tùy chỉnh namespace khớp với cấu trúc URL của API thực tế, bao gồm cả việc chỉ định phiên bản. Bằng cách này, khi API của bạn đã sẵn sàng, bạn có thể dễ dàng tích hợp nó vào ứng dụng giao diện người dùng của mình với những thay đổi code tối thiểu.

Thêm vào đó, trong cấu hình phiên bản server, bạn cũng có thể xác định một mô hình dữ liệu để mô phỏng việc lưu trữ và truy xuất dữ liệu trong môi trường mock.

Cuối cùng, khởi động server Mirage.js bằng cách nhập đối tượng server trong file index.jsx hoặc main.js như sau:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { makeServer } from './server';

if ( process.env.NODE_ENV === 'development' && 
     typeof makeServer === 'function'
   ) {
  makeServer();}

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

Thêm dữ liệu mẫu vào Mock API

Mirage.js có cơ sở dữ liệu trong bộ nhớ mà bạn có thể sử dụng để điền trước mock API với dữ liệu gốc ban đầu và quản lý dữ liệu thử nghiệm từ ứng dụng khách của mình. Điều này có nghĩa là bạn có thể lưu trữ và tìm nạp dữ liệu thử nghiệm từ cơ sở dữ liệu mô phỏng và sử dụng nó trong ứng dụng khách.

Để thêm dữ liệu mẫu vào Mock API, thêm code sau trong file server.js ngay bên dưới đối tượng models.

seeds(server) {
      server.create('Todo', {
        title: 'item no 1',
        body:
          'Do something nice for someone I care about',
      });
      server.create('Todo', {
        title: 'item no 2',
        body:
          'Memorize the fifty states and their capitals.',
      });
      server.create('Todo', {
        title: 'item no 3',
        body:
          'Watch a classic movie.',
      });
    },

Hàm seeds cung cấp cho máy chủ Mirage.js ba mục việc cần làm, mỗi mục đều có tiêu đề và mô tả riêng. Theo tùy chọn, thay vì mã hóa cứng dữ liệu thử nghiệm, bạn có thể tích hợp thư viện như Faker.js để tạo dữ liệu thử nghiệm cần thiết.

Xác định lộ trình Mock API

Giờ xác định một số lộ trình API cho mock API. Trong trường hợp này, xác định lộ trình xử lý các truy vấn mock API GET, POST, và DELETE.

Ngay bên dưới dữ liệu mẫu, thêm code:

routes() {
      this.namespace = 'api/todos'; 
      
      this.get('/', (schema, request) => {
        return schema.all('Todo'); 
      });

      this.post('/', (schema, request) => {
        let attrs = JSON.parse(request.requestBody);
        return schema.create('Todo', attrs); 
      });

      this.delete('/:id', (schema, request) => {
        let id = request.params.id;
        return schema.find('Todo', id).destroy(); 
      });
    }

Xây dựng client React

Sau khi thiết lập xong mock API, hãy xây dựng một client React để tương tác và sử dụng các endpoint API. Bạn thoải mái dùng bất kỳ thư viện thành phần UI yêu thích, nhưng hướng dẫn này sẽ dùng Chakra UI để tạo kiểu cho app.

Đầu tiên, cài đặt những thành phần phụ thuộc:

npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion

Tiếp theo, tạo file src/components/TodoList.jsx mới, và bao gồm code sau:

import React, { useState, useEffect } from 'react';
import {
  Button,
  Box,
  Container,
  Text,
  Input,
  FormControl,
  Flex,
} from '@chakra-ui/react';

Giờ xác định một thành phần chức năng để hiện UI danh sách cần làm, bao gồm các trường nhập để thêm tác vụ mới và một danh sách nhiệm vụ hiện tại.

export default function TodoList() {
  return (
    <Container>
      <Text fontSize="xl" mb={4}>Todo List</Text>
      <FormControl mb={4}>
        <Input
          type="text"
          name="body"
          value={newTodo.body}
          onChange={handleInputChange}
        />
      </FormControl>
      <Button colorScheme="teal" onClick={handleAddTodo}> Add Todo</Button>
      {loading ? ( <Text>Loading...</Text> ) : (
        todos.map((todo) => (
          <Box key={todo.id} mb={2} p={2} borderWidth="1px">
            <Flex align="center">
              <Text flex="1">{todo.body}</Text>
              <Button
                colorScheme="red"
                size="sm"
                onClick={() => handleDelete(todo.id)}>Delete 
              </Button>
            </Flex>
          </Box>
        ))
      )}
    </Container>
  );
}

Giờ xác định các hàm xử lý để thêm và xóa các hoạt động. Thế nhưng, trước tiên, thêm những trạng thái này. Ngoài ra, bạn có thể dùng useReducer để xác định logic quản lý trạng thái cho app lên danh sách việc cần làm.

const [todos, setTodos] = useState([]);
const [newTodo, setNewTodo] = useState({ title: '', body: '' });
const [loading, setLoading] = useState(true);
const [renderKey, setRenderKey] = useState(0);

Giờ xác định logic để truy xuất và hiện dữ liệu mẫu trong database bộ nhớ khi ứng dụng đầu tiên tải trong trình duyệt bằng cách bao gồm phương thức fetch trong hook useEffect.

 useEffect(() => {
    fetch('/api/todos') 
      .then((response) => response.json())
      .then((data) => {
        setTodos(data.todos);
        setLoading(false);
      });
  }, [renderKey]);

Trạng thái renderKey cũng bao gồm trong useEffect để đảm bảo rằng code này kích hoạt kết xuất lại dữ liệu được bổ sung mới trong database bộ nhớ khi server đang chạy.

Hiểu đơn giản, bất cứ khi nào người dùng thêm dữ liệu cần làm mới vào database Mirage.js - thành phần này sẽ kết xuất lại để hiện dữ liệu được cập nhật.

Thêm dữ liệu vào API

Giờ xác định logic thêm dữ liệu vào API qua các truy vấn POST. Ngay bên dưới hook useEffect, bao gồm code sau:

const handleInputChange = (e) => {
  const { name, value } = e.target;
  setNewTodo((prevTodo) => ({ ...prevTodo, [name]: value }));
};

const handleAddTodo = () => {
  setLoading(true);
  fetch('/api/todos', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(newTodo),
  }).then((response) => response.json()).then((createdTodo) => {
      setTodos((prevTodos) => [createdTodo, ...prevTodos]);
      setNewTodo({ title: '', body: '' });
      setRenderKey((prevKey) => prevKey + 1); 
      setLoading(false); 
    }).catch((error) => {
      console.error('Error adding todo:', error);
      setLoading(false); 
    });
};

Khi người dùng nhập dữ liệu vào trong trường đầu vào việc cần làm và click nút Add Todo, code update trạng thái newTodo với đầu vào của người dùng. Sau đó, nó gửi truy vấn POST mẫu tới API bằng đối tượng dữ liệu mới trong phần nội dung truy vấn để lưu nó vào database bộ nhớ.

Nếu truy vấn POST thành công, code này thêm mục mới vào mảng todos, và cuối cùng, kích hoạt hiển thị lại thành phần này để hiện mục to-do mới.

Truy vấn Mock API DELETE

Giờ, xác định logic để xóa dữ liệu qua các truy vấn API mẫu DELTE. Quá trình này liên quan tới việc gửi truy vấn DELETE đẻ loại bỏ mục cần làm từ cơ sở dữ liệu trong bộ nhớ. Nếu thành công, update cả hai trạng thái todo loading để thể hiện quá trình xóa.

const handleDelete = (id) => { 
    let deleteInProgress = true;
    fetch(`/api/todos/${id}`, {
      method: 'DELETE',
    }).then((response) => {
        if (response.status === 204) {
          return null;
        } else {
          return response.json();
        }
      }) .then((data) => {
        if (data && data.error) {
          console.error('Error deleting todo:', data.error);
        } else { 
          setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
          setRenderKey((prevKey) => prevKey + 1);
        }
        deleteInProgress = false;
      }).catch((error) => {
        console.error('Error deleting todo:', error);
        deleteInProgress = false;
      }) .finally(() => {
        setLoading(deleteInProgress);
      });
  };

Nhớ rằng quá trình này chỉ có thể xóa dữ liệu được thêm mới, không phải dữ liệu mẫu.

Cuối cùng nhập thành phần TodoList trong file App.jsx để hiện nó trong DOM.

import TodoList from './components/TodoList';
//code ...
<TodoList /> 

Thế là xong! Khi bạn khởi động server lập trình, bạn có thể tìm nạp dữ liệu mẫu, thêm & xóa dữ liệu mới từ API mẫu trong app React.

Thứ Sáu, 13/10/2023 16:55
31 👨 222
0 Bình luận
Sắp xếp theo