Jak tworzyć i wykorzystywać makiety API w aplikacjach reactowych przy użyciu Mirage.js
Podczas tworzenia aplikacji typu full-stack, znaczna część pracy frontendowej opiera się na danych w czasie rzeczywistym z backendu.
Powyższa sytuacja sugeruje, że konieczne może być odroczenie rozwoju interfejsu użytkownika do czasu przygotowania interfejsu programowania aplikacji (API) do wykorzystania. Niemniej jednak, opóźnianie rozpoczęcia rozwoju front-endu w oczekiwaniu na gotowość API może znacznie utrudnić postęp i wydłużyć czas trwania przedsięwzięcia.
Odpowiednim rozwiązaniem tego problemu może być zastosowanie pozorowanych interfejsów API. Takie interfejsy API umożliwiają tworzenie i testowanie systemu front-end przy użyciu symulowanych struktur danych, bez konieczności polegania na autentycznym interfejsie API.
Rozpoczęcie pracy z Mirage.js Mock APIs
Mirage.js to biblioteka JavaScript, która umożliwia tworzenie pozorowanych interfejsów API, wraz z serwerem testowym działającym po stronie klienta aplikacji internetowej. Oznacza to, że możesz testować swój kod frontendowy bez konieczności martwienia się o dostępność lub zachowanie prawdziwego backendowego API.
Aby wykorzystać Mirage.js, konieczne jest utworzenie zestawu pozorowanych punktów końcowych API i określenie odpowiednich odpowiedzi, które te punkty końcowe mają dostarczyć. Następnie Mirage.js przechwyci każde żądanie wykonane przez aplikację front-end do serwera WWW i zastąpi je symulowanymi odpowiedziami.
Gdy interfejs programowania aplikacji (API) zostanie w pełni opracowany i przetestowany, wdrożenie go w projekcie staje się prostym procesem, który wymaga jedynie aktualizacji ustawień konfiguracyjnych w Mirage.js. To usprawnione podejście pozwala na płynną integrację przy minimalnym zakłóceniu istniejącej funkcjonalności lub wydajności.
Kod źródłowy tego projektu można znaleźć w powiązanym repozytorium GitHub.
Tworzenie pozorowanego serwera API za pomocą Mirage.js
Aby utworzyć pozorowane API dla aplikacji React wykorzystującej Mirage.js jako backend, początkowo stworzymy prostą aplikację do zarządzania zadaniami w React. Przed przystąpieniem do tego przedsięwzięcia należy wykonać kilka wstępnych kroków. Po pierwsze, należy utworzyć nową aplikację React, korzystając z jednej z dwóch dostępnych metod. Pierwsza metoda polega na wykonaniu instrukcji wiersza poleceń create-react-app
, co jest powszechnie uznanym i konwencjonalnym podejściem. Alternatywna ścieżka zakłada natomiast utworzenie projektu React poprzez implementację Vite, nowoczesnego serwera deweloperskiego, który zyskał popularność dzięki swojej szybkości działania.Po dokonaniu wyboru między tymi opcjami, konieczne jest wprowadzenie niezbędnych zależności poprzez instalację Mirage.js za pośrednictwem menedżera pakietów lub rejestru npm.
npm install --save-dev miragejs
Aby utworzyć instancję serwera Mirage.js, która przechwytuje przychodzące żądania i imituje odpowiedzi API, należy skorzystać z metody createServer
, która akceptuje towarzyszący obiekt konfiguracyjny.
Wspomniana jednostka obejmuje zarówno kontekst środowiskowy, jak i powiązaną konwencję nazewnictwa dla naszego interfejsu programowania aplikacji (API). W szczególności parametr środowiska oznacza bieżącą fazę cyklu życia API, taką jak jego stan rozwoju, podczas gdy przestrzeń nazw służy jako wstępne oznaczenie dołączone do każdego punktu końcowego API, nadając mu w ten sposób unikalny identyfikator.
Rzeczywiście, utworzę nowy plik src/server.js
i włączę do niego dostarczony fragment kodu. Wynikowy skrypt będzie obsługiwał żądania klientów szukających informacji o produktach lub usługach oferowanych przez Twoją firmę. Najpierw przeanalizuje przychodzące żądanie, aby określić jego typ, czy chodzi o szczegóły produktu, czy informacje o cenach. W oparciu o to ustalenie, wyodrębni odpowiednie dane z bazy danych, używając klucza głównego jako identyfikatora. Jeśli się powiedzie, serwer odeśle odpowiedź zawierającą żądane informacje w formacie JSON. Jeśli jednak żądanie nie powiedzie się z powodu nieprawidłowych parametrów wejściowych, zamiast tego zostanie zwrócony komunikat o błędzie.
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;
}
Aby dostosować przestrzeń nazw do konkretnej struktury adresu URL interfejsu API, można ją elastycznie spersonalizować zgodnie z własnymi wymaganiami. Dodatkowo, w razie potrzeby, można umieścić numer wersji w przestrzeni nazw, aby zapewnić zgodność z przyszłymi aktualizacjami lub modyfikacjami interfejsu API. W ten sposób, gdy interfejs API zaplecza jest w pełni rozwinięty i operacyjny, włączenie go płynnie do interfejsu użytkownika będzie wymagało jedynie niewielkich zmian w bazie kodu.
Co więcej, można określić schemat danych w ustawieniach konfiguracyjnych serwera, aby naśladować proces przechowywania i pobierania informacji w symulowanym kontekście.
Aby zainicjować działanie Mirage.js, należy zaimportować wspomniany obiekt serwera do pliku index.jsx lub main.jsx. Można to osiągnąć poprzez następujący proces:
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>,
)
Add Seed Data to the Mock API
Wykorzystując wbudowaną w Mirage.js bazę pamięci, deweloperzy mają możliwość wstępnego załadowania swojego mock API początkowymi danymi seed do celów testowych, a także efektywnego zarządzania danymi testowymi generowanymi przez aplikacje klienckie.Funkcja ta pozwala na bezproblemowe przechowywanie i pobieranie danych testowych w bazie danych mock, które mogą być następnie wykorzystane w aplikacji klienckiej.
Aby włączyć początkowe dane do mock API, należy dołączyć następujące linie kodu bezpośrednio po obiekcie “models” w pliku “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.',
});
},
Funkcja seeds wypełnia serwer Mirage.js trzema elementami do zrobienia, każdy z tytułem i opisem. Opcjonalnie, zamiast twardego kodowania danych testowych, można zintegrować bibliotekę taką jak Faker.js , aby wygenerować wymagane dane testowe.
Zdefiniuj trasy Mock API
Aby zaimplementować funkcjonalny mock API, konieczne jest ustanowienie kilku punktów końcowych API, które mogą obsługiwać żądania GET, POST i DELETE. Trasy te będą służyć jako podstawa funkcjonalności naszego mock API, pozwalając nam symulować różne interakcje z serwerem i testować różne scenariusze. Definiując te trasy, możemy skutecznie emulować rzeczywisty punkt końcowy API i sprawdzać jego zachowanie w różnych warunkach.
Poniżej początkowego zestawu danych, włącz dostarczony kod w następujący sposób:
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();
});
}
Zbuduj klienta React
Po ustanowieniu naszego mock API, przejdziemy do skonstruowania klienta React, który będzie łączył się z punktami końcowymi API i wykorzystywał je. Otrzymujesz pozwolenie na wykorzystanie dowolnej biblioteki komponentów interfejsu użytkownika; jednak dla jasności, w tym samouczku wykorzystamy Chakra UI, aby wzbogacić wygląd aplikacji.
Najpierw zainstaluj następujące zależności:
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion
Rzeczywiście, przejdźmy do wygenerowania nowej instancji pliku TodoList.jsx, obejmującego kolejny blok kodu:
import React, { useState, useEffect } from 'react';
import {
Button,
Box,
Container,
Text,
Input,
FormControl,
Flex,
} from '@chakra-ui/react';
Biorąc pod uwagę zadanie, które mamy do wykonania, rozsądnie byłoby opracować funkcjonalny komponent, który zawiera elementy niezbędne do renderowania interfejsu użytkownika listy rzeczy do zrobienia, w tym pola wejściowe ułatwiające dodawanie nowych zadań, a także wyliczanie bieżących zadań.
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>
);
}
jedna do dodawania pozycji do listy (ADD\_ITEM) i druga do usuwania pozycji z listy (REMOVE\_ITEM). Akcje te powinny być wysyłane przez odpowiednie programy obsługi w odpowiedzi na dane wejściowe użytkownika lub inne istotne zdarzenia. Aby zarządzać stanem aplikacji, użyjemy haka useReducer wraz z odpowiednią funkcją reduktora. Takie podejście pozwala nam utrzymać spójne drzewo stanów we wszystkich komponentach, jednocześnie utrzymując nasz kod w czystości i porządku.
const [todos, setTodos] = useState([]);
const [newTodo, setNewTodo] = useState({ title: '', body: '' });
const [loading, setLoading] = useState(true);
const [renderKey, setRenderKey] = useState(0);
Podczas inicjalizacji aplikacji w przeglądarce internetowej konieczne jest zaimplementowanie mechanizmu pobierania i wyświetlania danych początkowych przechowywanych w bazie danych w pamięci. Aby osiągnąć ten cel, możemy wykorzystać hak useEffect
dostarczany przez React, hermetyzując wywołanie funkcji fetch
w jego zakresie. Zapewni to, że dane seed zostaną pobrane i wyświetlone po załadowaniu aplikacji.
useEffect(() => {
fetch('/api/todos')
.then((response) => response.json())
.then((data) => {
setTodos(data.todos);
setLoading(false);
});
}, [renderKey]);
Włączenie stanu renderKey
w zakres haka useEffect
służy ułatwieniu reaktywacji wszelkich nowo włączonych informacji obecnych w naszej lokalnej, operacyjnej bazie danych, gdy system hostingowy działa poprawnie.
Zasadniczo, za każdym razem, gdy użytkownik wprowadzi nowe informacje o zadaniach do wykonania w repozytorium Mirage.js, komponent zostanie poddany procesowi regeneracji w celu wizualnego odzwierciedlenia zmienionych danych.
Dodawanie danych do API
Aby ułatwić dodawanie danych za pośrednictwem żądań HTTP POST, konieczne jest zaimplementowanie logicznej struktury w interfejsie programowania aplikacji (API). Natychmiast po wykorzystaniu haka useEffect
należy wdrożyć następującą implementację.
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);
});
};
Po wprowadzeniu danych w wyznaczonym polu wejściowym i kliknięciu przycisku “Add Todo” przez użytkownika, system aktualizuje bieżący stan “newTodo” o dostarczone informacje. Następnie do interfejsu API wysyłane jest symulowane żądanie HTTP POST zawierające instancję zaktualizowanej struktury danych w treści żądania w celu przechowywania w bazie danych w pamięci.
Po udanym żądaniu POST kod proceduralnie aktualizuje tablicę “todos”, dołączając do niej nowo utworzony obiekt zadania. Następnie monituje komponent funkcjonalny React o ponowną ocenę, tym samym wizualnie prezentując zaktualizowany element do zrobienia na liście na stronie.
Mock API DELETE Requests
Aby usunąć dane za pomocą żądań DELETE mock API, konieczne jest ustanowienie logicznych ram dla tego procesu. Zasadniczo wiąże się to z przesłaniem żądania DELETE mającego na celu usunięcie danego zadania z tymczasowej bazy danych. W związku z tym, jeśli operacja okaże się skuteczna, konieczne jest zmodyfikowanie zarówno listy zaległych zadań, jak i wskaźnika ładowania, aby oznaczyć, że procedura usuwania została wykonana pomyślnie.
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);
});
};
Należy pamiętać, że ta metoda jest w stanie usunąć tylko ostatnio dodane dane, a nie początkowy zestaw danych.
Włączenie komponentu TodoList
do pliku App.jsx
w celu wyświetlenia go w obiektowym modelu dokumentu (DOM).
import TodoList from './components/TodoList';
//code ...
<TodoList />
Rzeczywiście, po zainicjowaniu serwera deweloperskiego można pobrać początkowy zestaw danych i interaktywnie modyfikować symulowane API w swojej aplikacji React, zarówno dodając, jak i usuwając dane.
Wykorzystanie makiet API do przyspieszenia rozwoju
Wykorzystanie makiet API stanowi skuteczną metodę przyspieszenia rozwoju front-endu, zarówno podczas samodzielnej pracy, jak i w ramach współpracy. Dzięki zastosowaniu makiet API można szybko konstruować interfejsy użytkownika i oceniać powiązany kod, bez konieczności oczekiwania na ukończenie back-endu.