Cách xây dựng và sử dụng API mô phỏng trong ứng dụng React bằng Mirage.js
Khi phát triển các ứng dụng full-stack, phần lớn công việc ở giao diện người dùng phụ thuộc vào dữ liệu thời gian thực từ phần phụ trợ.
Tình trạng khó khăn nói trên cho thấy rằng người ta có thể cần phải trì hoãn việc phát triển giao diện người dùng cho đến khi giao diện lập trình ứng dụng (API) đã được chuẩn bị để sử dụng. Tuy nhiên, việc trì hoãn việc bắt đầu phát triển giao diện người dùng để dự đoán tính sẵn sàng của API có thể cản trở đáng kể tiến độ và kéo dài thời gian thực hiện.
Có thể đạt được giải pháp phù hợp cho vấn đề này bằng cách sử dụng API giả. Các API như vậy cho phép phát triển và thử nghiệm hệ thống giao diện người dùng bằng cách sử dụng cấu trúc dữ liệu mô phỏng mà không cần phải dựa vào API xác thực.
Bắt đầu với API mô phỏng Mirage.js
Mirage.js là một thư viện JavaScript cho phép bạn tạo các API mô phỏng, hoàn chỉnh với một máy chủ thử nghiệm chạy ở phía máy khách của ứng dụng web của bạn. Điều này có nghĩa là bạn có thể kiểm tra mã giao diện người dùng của mình mà không cần phải lo lắng về tính khả dụng hoặc hoạt động của API phụ trợ thực sự của bạn.
Để sử dụng Mirage.js, cần thiết lập một tập hợp các điểm cuối API mô phỏng và chỉ định các câu trả lời tương ứng mà các điểm cuối này dự kiến sẽ cung cấp. Sau đó, Mirage.js sẽ nắm bắt mọi yêu cầu do ứng dụng giao diện người dùng của bạn gửi tới máy chủ web và thay thế chúng bằng các phản hồi mô phỏng.
Khi giao diện lập trình ứng dụng (API) của bạn đã được phát triển và thử nghiệm đầy đủ, việc triển khai nó trong dự án của bạn sẽ trở thành một quy trình đơn giản, chỉ cần cập nhật cài đặt cấu hình trong Mirage.js. Cách tiếp cận hợp lý này cho phép tích hợp liền mạch với sự gián đoạn tối thiểu đối với chức năng hoặc hiệu suất hiện có.
Người ta có thể định vị mã nguồn của dự án này trong kho GitHub được liên kết.
Tạo máy chủ API mô phỏng với Mirage.js
Để thiết lập API mô phỏng cho ứng dụng React sử dụng Mirage.js làm phụ trợ, ban đầu chúng tôi sẽ xây dựng một ứng dụng quản lý tác vụ đơn giản trong React. Trước khi tiến hành nỗ lực này, có một số bước sơ bộ phải được thực hiện. Đầu tiên, người ta nên tạo một ứng dụng React mới bằng cách sử dụng một trong hai phương pháp có sẵn. Phương thức ban đầu liên quan đến việc thực thi lệnh dòng lệnh create-react-app
, đây là một cách tiếp cận thông thường và được công nhận rộng rãi. Ngược lại, một con đường thay thế đòi hỏi phải thiết lập một dự án React thông qua việc triển khai Vite, một máy chủ phát triển hiện đại đã trở nên nổi tiếng nhờ hiệu suất nhanh chóng. Sau khi lựa chọn giữa các tùy chọn này đã được thực hiện, bắt buộc phải đưa ra các phụ thuộc cần thiết bằng cách cài đặt Mirage.js thông qua trình quản lý gói hoặc sổ đăng ký npm.
npm install --save-dev miragejs
Để thiết lập một phiên bản máy chủ Mirage.js nắm bắt các yêu cầu đến và bắt chước các câu trả lời API, hãy sử dụng phương thức createServer
chấp nhận một đối tượng cấu hình đi kèm.
Thực thể nói trên bao gồm cả bối cảnh môi trường và quy ước đặt tên liên quan cho giao diện lập trình ứng dụng (API) của chúng tôi. Cụ thể, tham số môi trường biểu thị giai đoạn hiện tại trong vòng đời của API, chẳng hạn như trạng thái phát triển của nó, trong khi không gian tên đóng vai trò là chỉ định mở đầu được thêm vào mỗi điểm cuối API, từ đó cung cấp mã định danh duy nhất cho đó.
Thật vậy, tôi sẽ tạo một tệp src/server.js
mới và kết hợp đoạn mã được cung cấp trong đó. Tập lệnh kết quả sẽ xử lý các yêu cầu từ khách hàng đang tìm kiếm thông tin về sản phẩm hoặc dịch vụ do công ty bạn cung cấp. Trước tiên, nó sẽ phân tích yêu cầu đến để xác định loại của nó, cho dù đó là chi tiết sản phẩm hay thông tin về giá. Dựa trên xác định này, nó sẽ trích xuất dữ liệu liên quan từ cơ sở dữ liệu bằng cách sử dụng khóa chính làm mã định danh. Nếu thành công, máy chủ sẽ gửi lại phản hồi chứa thông tin được yêu cầu ở định dạng JSON. Tuy nhiên, nếu yêu cầu không thành công do tham số đầu vào không hợp lệ, thay vào đó, một thông báo lỗi sẽ được trả về.
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;
}
Để căn chỉnh không gian tên với cấu trúc cụ thể của URL API, bạn có thể linh hoạt cá nhân hóa nó theo yêu cầu của mình. Ngoài ra, nếu cần, bạn có thể đưa số phiên bản vào không gian tên để đảm bảo khả năng tương thích với các bản cập nhật hoặc sửa đổi trong tương lai đối với API. Bằng cách đó, khi API phụ trợ của bạn được phát triển và vận hành đầy đủ, việc kết hợp nó một cách liền mạch vào giao diện người dùng sẽ chỉ yêu cầu những điều chỉnh nhỏ đối với cơ sở mã của bạn.
Hơn nữa, người ta có thể chỉ định lược đồ dữ liệu trong cài đặt cấu hình của máy chủ để bắt chước quá trình lưu trữ và truy xuất thông tin trong bối cảnh mô phỏng.
Thật vậy, để bắt đầu hoạt động của Mirage.js, người ta phải nhập đối tượng máy chủ nói trên vào tệp index.jsx hoặc main.jsx của chúng. Điều này có thể đạt được thông qua quá trì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 hạt giống vào API mô phỏng
Bằng cách sử dụng cơ sở dữ liệu bộ nhớ tích hợp của Mirage.js, các nhà phát triển có khả năng tải trước API mô phỏng của họ với dữ liệu gốc ban đầu cho mục đích thử nghiệm cũng như quản lý hiệu quả dữ liệu thử nghiệm do ứng dụng khách tạo ra. Tính năng này cho phép lưu trữ và truy xuất liền mạch dữ liệu thử nghiệm trong cơ sở dữ liệu mô phỏng, sau đó có thể được sử dụng trong ứng dụng khách.
Để kết hợp dữ liệu ban đầu vào API mô phỏng, bạn nên bao gồm các dòng mã sau ngay sau đối tượng’models’trong tệp’server.js'.
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 hạt giống cung cấp cho máy chủ Mirage.js ba mục việc cần làm, mỗi mục có tiêu đề và mô tả. 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 các tuyến API mô phỏng
Để triển khai API mô phỏng chức năng, cần thiết lập một số điểm cuối API có thể đáp ứng các yêu cầu GET, POST và DELETE. Các tuyến này sẽ đóng vai trò là nền tảng cho chức năng API mô phỏng của chúng tôi, cho phép chúng tôi mô phỏng các tương tác khác nhau với máy chủ và thử nghiệm các tình huống khác nhau. Bằng cách xác định các tuyến đường này, chúng tôi có thể mô phỏng hiệu quả điểm cuối API thực tế và xác thực hành vi của nó trong các điều kiện khác nhau.
Bên dưới tập dữ liệu ban đầu, kết hợp mã được cung cấp như sau:
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 ứng dụng khách React
Khi API mô phỏng của chúng tôi đã được thiết lập, chúng tôi sẽ tiến hành xây dựng ứng dụng khách React sẽ giao tiếp và sử dụng các điểm cuối API. Bạn được cấp quyền sử dụng bất kỳ thư viện thành phần giao diện người dùng nào bạn thích; tuy nhiên, để rõ ràng, hướng dẫn này sẽ sử dụng Chakra UI để làm phong phú thêm giao diện của ứng dụng.
Đầu tiên, cài đặt các phụ thuộc này:
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion
Thật vậy, chúng ta hãy tiến hành tạo một phiên bản mới của tệp TodoList.jsx, bao gồm khối mã tiếp theo:
import React, { useState, useEffect } from 'react';
import {
Button,
Box,
Container,
Text,
Input,
FormControl,
Flex,
} from '@chakra-ui/react';
Xem xét nhiệm vụ hiện tại, sẽ là khôn ngoan khi phát triển một thành phần chức năng bao gồm các yếu tố cần thiết để hiển thị giao diện người dùng danh sách việc cần làm, bao gồm các trường đầu vào hỗ trợ việc bổ sung các nhiệm vụ mới cũng như liệt kê các 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>
);
}
một để thêm một mục vào danh sách (ADD\_ITEM) và một để xóa một mục khỏi danh sách (REMOVE\_ITEM). Những hành động này phải được gửi bởi trình xử lý tương ứng để phản hồi thông tin đầu vào của người dùng hoặc các sự kiện liên quan khác. Để quản lý trạng thái của ứng dụng, chúng ta sẽ sử dụng hook useReducer cùng với chức năng giảm tốc thích hợp. Cách tiếp cận này cho phép chúng tôi duy trì một cây trạng thái nhất quán trên tất cả các thành phần trong khi vẫn giữ cho mã của chúng tôi sạch sẽ và có tổ chức.
const [todos, setTodos] = useState([]);
const [newTodo, setNewTodo] = useState({ title: '', body: '' });
const [loading, setLoading] = useState(true);
const [renderKey, setRenderKey] = useState(0);
Khi khởi tạo ứng dụng trong trình duyệt web, cần triển khai cơ chế truy xuất và hiển thị dữ liệu gốc được lưu trữ trong cơ sở dữ liệu trong bộ nhớ. Để đạt được mục tiêu này, chúng ta có thể sử dụng hook useEffect
do React cung cấp, gói gọn lệnh gọi hàm fetch
trong phạm vi của nó. Điều này sẽ đảm bảo rằng dữ liệu gốc được truy xuất và hiển thị khi tải ứng dụng.
useEffect(() => {
fetch('/api/todos')
.then((response) => response.json())
.then((data) => {
setTodos(data.todos);
setLoading(false);
});
}, [renderKey]);
Việc bao gồm trạng thái renderKey
trong phạm vi của hook useEffect
nhằm tạo điều kiện thuận lợi cho việc kích hoạt lại bất kỳ thông tin mới được tích hợp nào có trong cơ sở dữ liệu hoạt động, cục bộ của chúng tôi bất cứ khi nào hệ thống lưu trữ hoạt động bình thường.
Về bản chất, bất cứ khi nào người dùng giới thiệu thông tin việc cần làm mới trong kho lưu trữ Mirage.js, thành phần này sẽ trải qua quá trình tái tạo để phản ánh trực quan dữ liệu đã sửa đổi.
Thêm dữ liệu vào API
Để tạo điều kiện thuận lợi cho việc bổ sung dữ liệu thông qua các yêu cầu HTTP POST, điều cần thiết là phải triển khai cấu trúc logic trong giao diện lập trình ứng dụng (API). Ngay sau khi sử dụng hook useEffect
, hãy kết hợp cách triển khai 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 nhập dữ liệu trong trường nhập được chỉ định và người dùng nhấp vào nút “Thêm Todo”, hệ thống sẽ cập nhật trạng thái hiện tại của “newTodo” với thông tin được cung cấp. Sau đó, một yêu cầu HTTP POST mô phỏng được gửi đến API chứa phiên bản của cấu trúc dữ liệu được cập nhật trong nội dung yêu cầu của nó để lưu trữ trong cơ sở dữ liệu trong bộ nhớ.
Sau khi yêu cầu POST thành công, mã sẽ cập nhật theo thủ tục mảng “todos” bằng cách thêm đối tượng tác vụ mới được tạo vào đó. Sau đó, nó nhắc thành phần chức năng React trải qua quá trình đánh giá lại, từ đó trình bày trực quan mục việc cần làm được cập nhật trong danh sách trên trang.
API giả XÓA yêu cầu
Để xóa dữ liệu thông qua các yêu cầu API giả DELETE, cần thiết lập khung logic cho quy trình này. Về cơ bản, điều này đòi hỏi phải truyền một yêu cầu XÓA nhằm mục đích xóa tác vụ đã cho khỏi cơ sở dữ liệu tạm thời. Do đó, nếu hoạt động tỏ ra hiệu quả thì điều cần thiết là phải sửa đổi cả danh sách các nhiệm vụ còn tồn đọng cũng như chỉ báo tải để biểu thị rằng quy trình loại bỏ đã được thực hiện thành công.
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);
});
};
Xin lưu ý rằng phương pháp này chỉ có khả năng xóa dữ liệu đã được thêm gần đây chứ không phải dữ liệu ban đầu.
Kết hợp thành phần TodoList
trong tệp App.jsx
, để hiển thị nó trong Mô hình đối tượng tài liệu (DOM).
import TodoList from './components/TodoList';
//code ...
<TodoList />
Thật vậy, khi khởi tạo máy chủ phát triển, người ta có thể truy xuất tập dữ liệu ban đầu và sửa đổi tương tác API mô phỏng trong ứng dụng React của họ bằng cách thêm và xóa dữ liệu.
Sử dụng API mô phỏng để tăng tốc độ phát triển
Việc sử dụng các API mô phỏng mang lại một phương pháp hiệu quả để thúc đẩy quá trình phát triển giao diện người dùng, cả khi tiến hành công việc độc lập hoặc trong môi trường cộng tác. Thông qua việc sử dụng các API mô phỏng, người ta có thể nhanh chóng xây dựng giao diện người dùng và đánh giá mã liên quan mà không cần phải chờ hoàn thành phần back-end.