При работе с приложениями с полным стеком нам часто приходится ждать, пока внутренние API-интерфейсы создадут необходимые конечные точки, что влияет на производительность и сроки проекта. Mocking API решит эту проблему, и мы сможем создавать полные интерфейсные функции, даже если API не существует.
В этом руководстве мы создадим простое React-приложение «телефонная книга», чтобы показать, как мы работаем с фиктивным API Mirage.
Что такое Мираж?
Mirage — это библиотека для имитации API, которая позволяет создавать серверные API с начальными данными.
В отличие от других фиктивных библиотек, Mirage позволяет воссоздавать динамические сценарии, которые возможны только на рабочем сервере.
Mirage создает поддельный сервер, который запускается в клиенте и может использоваться как для разработки, так и для тестирования (модульное и сквозное).
Некоторые из лучших функций Mirage включает
- Маршруты для обработки HTTP-запросов
- База данных и модели для хранения данных и определения отношений
- Фабрики и приспособления для заглушки данных, и
- Сериализаторы для форматирования ответов HTTP
Хорошо, теперь у нас есть некоторое представление о том, что такое Mirage и о его функциях, давайте создадим простое приложение, чтобы увидеть все в действии.
Создание нашего React-приложения
Создайте новую папку phone_book
и откройте ее в редакторе VSCode.
mkdir phone_book
После открытия папки phone_book
теперь откройте терминал и запустите,
npx create-react-app .
Приведенная выше команда создаст приложение реакции в той же папке.
Теперь у нас есть готовая базовая настройка, давайте настроим Mirage.
Создание нашего сервера Mirage
Mirage — это сторонняя библиотека, поэтому нам придется установить ее в нашем приложении либо npm
, либо yarn
.
# Using npm npm install --save-dev miragejs # Using Yarn yarn add --dev miragejs
Мы успешно установили Mirage в наше приложение; теперь нам нужно создать сервер, который будет обрабатывать маршрутизацию наших конечных точек API.
Создайте файл server.js
в папке src
. В этом файле будут все коды для нашего Mock API.
# src/server.js touch src/server.js
Mirage предоставляет метод createServer
для создания поддельного сервера. Он принимает кучу конфигов для создания фейкового сервера. В этом уроке мы будем использовать некоторые из них.
- среда
- пространство имен
- маршруты
- семена
- модели
Здесь мы создаем поддельный сервер со средой development
и пространством имен api
. Мы также добавляем одну модель, contact,
, которая будет иметь структуру данных контактов телефонной книги.
Mirage позволяет создавать серверы в разных средах, поэтому, если вы находитесь в режиме разработки, вы можете передать среду как development
, чтобы загрузить на сервер некоторые начальные данные.
Вы можете передать среду как test
для тестирования, чтобы она не загружала исходные данные в тестах. Вы можете создавать данные в соответствии с вашим тестовым примером.
Хорошо, у нас есть базовая настройка сервера. Следующим шагом является создание семян и маршрутов.
Создание маршрутов API и начальных данных
Мы будем использовать пакет fakerjs для создания семян. Установите его, запустив:
npm install @faker-js/faker --save-dev #OR yarn add @faker-js/faker --dev
Нашему приложению телефонной книги потребуются следующие маршруты:
- GET
/api/contacts
для получения всех записей контактов - GET
/api/contacts/:id
для получения одной записи контакта - POST
/api/contacts
для создания новой записи контакта - PATCH
/api/contacts/:id
для обновления существующей записи контакта - УДАЛИТЕ
/api/contacts/:id
, чтобы удалить существующую запись контакта.
После добавления семян и маршрутов server.js
будет таким.
# src/server.js import { createServer, Model } from 'miragejs'; import { faker } from '@faker-js/faker'; const DEFAULT_CONFIG = { environment: 'development', namespace: 'api', }; export const makeServer = ({ environment, namespace } = DEFAULT_CONFIG) => { return createServer({ environment, namespace, models: { contact: Model, }, seeds(server) { const LIST_LENGTH = 5; // loop to create a seed data for (let index = 1; index <= LIST_LENGTH; index++) { server.create('contact', { name: faker.name.fullName(), number: faker.phone.number(), }); } }, routes() { // fetch all contacts records this.get('/contacts', (schema) => { return schema.contacts.all(); }); // fetch a single contact record this.get('/contacts/:id', (schema, request) => { const id = request.params.id; return schema.contacts.find(id); }); // create a new contact record this.post('/contacts', (schema, request) => { const attrs = JSON.parse(request.requestBody); return schema.contacts.create(attrs); }); // update an existing contact record this.patch('/contacts/:id', (schema, request) => { const newAttrs = JSON.parse(request.requestBody); const id = request.params.id; const contact = schema.contacts.find(id); return contact.update(newAttrs); }); // remove an existing contact record this.delete('/contacts/:id', (schema, request) => { const id = request.params.id; return schema.contacts.find(id).destroy(); }); }, }); };
Поздравляем, наш фиктивный сервер готов с исходными данными и маршрутами. Давайте вызовем функцию makeServer
в index.js
, чтобы инициировать сервер.
Обновите index.js
с помощью приведенного ниже кода.
# src/index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import { makeServer } from './server'; if ( process.env.NODE_ENV === 'development' && typeof makeServer === 'function' ) { makeServer(); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
Здесь мы проверяем, является ли окружение development
и makeServer
типом функции; только тогда мы будем вызывать функцию makeServer
.
Хорошо, у нас есть сервер. В следующем разделе мы настроим внешний интерфейс и получим доступ к фиктивным API.
Повтор сеанса с открытым исходным кодом
OpenReplay – это пакет для воспроизведения сеансов с открытым исходным кодом, который позволяет вам видеть, что пользователи делают в вашем веб-приложении, помогая вам быстрее устранять неполадки. OpenReplay размещается на собственном сервере для полного контроля над вашими данными.
Начните получать удовольствие от отладки — начните использовать OpenReplay бесплатно.
Настройка внешнего интерфейса
Для внешнего интерфейса мы будем использовать пакет Chakra UI. Chakra UI — это простая, модульная и доступная библиотека компонентов, которая дает вам строительные блоки, необходимые для создания ваших приложений React.
Установите Chakra UI и его зависимости, запустив
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion # OR yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
Запустите сервер, запустив
npm start # OR yarn start
Затем посетите http://localhost:3000/, чтобы просмотреть изменения.
Наше приложение телефонной книги будет иметь следующие функции:
- Пользователи могут просматривать список контактов
- Пользователи могут создать новый контакт
- Пользователи могут редактировать контакт
- Пользователи могут удалить контакт
Список всех контактов
Здесь в App.jsx мы извлекаем список контактов из конечной точки /api/contacts
и сохраняем его в состоянии contacts
.
... const fetchContacts = useCallback(async () => { try { setIsLoading(true); const response = await fetch('/api/contacts'); const contactList = await response.json(); setContacts(contactList.contacts); } catch (error) { toast({ title: 'Error while fetching contacts', description: error, status: 'error', duration: 9000, isClosable: true, }); } finally { setIsLoading(false); } }, [toast]); ...
У нас также есть состояние isLoading
, и мы покажем загрузчик при выборке данных; после получения данных будет отображен ContactList. Теперь запустите сервер, и вы увидите что-то вроде этого.
Отлично, наше представление списка готово. На следующем шаге мы создадим пользовательский интерфейс для добавления новых контактов.
Мы создадим компонент ContactModal, и он будет обрабатывать поток создания контактов.
ContactModal получит две пропсы isOpen
и onClose
, isOpen будет отвечать за отображение/скрытие модального окна, а onClose будет отвечать за закрытие модального окна, когда пользователь нажимает кнопку отмены или после создания контакта.
... const handleCreateContact = async (e) => { e.preventDefault(); const isValid = Object.values(contactErrors).every( (value) => value === false ); if (isValid) { try { const response = await fetch('/api/contacts', { method: 'POST', body: JSON.stringify(contactData), }); await response.json(); } catch (error) { toast({ title: 'Error while creating contact', description: error, status: 'error', duration: 9000, isClosable: true, }); } finally { onClose(); } } else { toast({ title: 'Invalid data', description: 'Name or Number is invalid', status: 'error', duration: 9000, isClosable: true, }); } }; ...
Давайте попробуем создать контакт, нажмите кнопку Add Contact
, заполните данные и нажмите кнопку «Создать», чтобы создать контакт.
Мы будем использовать тот же модал для обновления контакта, поэтому обновленный компонент ContactModal будет выглядеть так.
Здесь мы добавили еще один реквизит, selectedContact
, и на его основе мы покажем обновленный вид для контакта.
handleUpdateContact
будет отвечать за обновление контакта. В этом методе мы использовали опцию PATCH
для обновления контакта.
... const handleUpdateContact = async (e) => { e.preventDefault(); const isValid = Object.values(contactErrors).every( (value) => value === false ); if (isValid) { try { const response = await fetch(`/api/contacts/${selectedContact.id}`, { method: 'PATCH', body: JSON.stringify(contactData), }); await response.json(); } catch (error) { toast({ title: 'Error while updating contact', description: error, status: 'error', duration: 9000, isClosable: true, }); } finally { onClose(); } } else { toast({ title: 'Invalid data', description: 'Name or Number is invalid', status: 'error', duration: 9000, isClosable: true, }); } }; ...
Теперь перейдите в браузер и попробуйте поток обновления.
Чтобы построить поток удаления, нам нужно будет выбрать идентификатор контакта, чтобы взять этот идентификатор и сделать запрос на удаление, чтобы удалить контакт.
Последний шаг — передать необходимые реквизиты из компонента приложения дочерним компонентам, а также отобразить DeleteContactModal при выборе идентификатора контакта.
И это все для этой темы. Спасибо за чтение!
Краткое содержание
- Мы обсудили, что такое Mirage, его особенности и какие проблемы решает Mirage.
- Мы создали фиктивный сервер с маршрутами API и начальными данными.
- Мы создали приложение
phone_book
и использовали Mock API.
Ресурсы
СОВЕТ ОТ РЕДАКТОРА. Чтобы узнать о другом способе имитации API для тестирования, ознакомьтесь с нашей статьей Forever Functional: Injecting For Purity.
Первоначально опубликовано на https://blog.openreplay.com.