Contents

Hur man bygger och konsumerar Mock API:er i React Apps med hjälp av Mirage.js

När man utvecklar fullstack-applikationer är en betydande del av frontend-arbetet beroende av realtidsdata från backend.

Ovanstående situation tyder på att man kan behöva skjuta upp utvecklingen av användargränssnittet tills dess att API (Application Programming Interface) har förberetts för användning. Att skjuta upp påbörjandet av frontend-utvecklingen i väntan på att API:et skall vara klart kan dock avsevärt hindra framstegen och dra ut på tiden.

En lämplig lösning på detta problem kan uppnås genom att använda låtsas-API:er. Sådana API:er möjliggör utveckling och testning av ett front-end-system med hjälp av simulerade datastrukturer, utan att behöva förlita sig på det autentiska API:et.

Kom igång med Mirage.js Mock API:er

Mirage.js är ett JavaScript-bibliotek som låter dig skapa mock API:er, komplett med en testserver som körs på klientsidan av din webbapplikation. Detta innebär att du kan testa din frontend-kod utan att behöva oroa dig för tillgängligheten eller beteendet hos ditt verkliga backend-API.

/sv/images/laptop-with-code-on-the-screen.jpg

För att kunna använda Mirage.js är det nödvändigt att skapa en uppsättning API-slutpunkter och ange motsvarande svar som dessa slutpunkter förväntas leverera. Därefter kommer Mirage.js att fånga upp varje begäran som din frontend-applikation gör till webbservern och ersätta dem med de simulerade svaren.

När ditt API (Application Programming Interface) är färdigutvecklat och testat är det enkelt att implementera det i ditt projekt genom att uppdatera konfigurationsinställningarna i Mirage.js. Denna strömlinjeformade metod möjliggör sömlös integration med minimal störning av befintlig funktionalitet eller prestanda.

Man kan hitta källkoden för detta projekt i det tillhörande GitHub-arkivet.

Skapa en mock API-server med Mirage.js

För att skapa en mock API för en React-applikation som använder Mirage.js som backend, kommer vi inledningsvis att bygga en enkel uppgiftshanteringsapplikation i React. Innan vi fortsätter med detta finns det flera preliminära steg som måste tas. För det första bör man skapa en ny React-applikation genom att använda någon av de två tillgängliga metoderna. Den första metoden innebär att man utför kommandoradsinstruktionen create-react-app , vilket är ett allmänt erkänt och konventionellt tillvägagångssätt. En alternativ väg är att skapa ett React-projekt med hjälp av Vite, en modern utvecklingsserver som har blivit populär tack vare sin snabba prestanda. När valet mellan dessa alternativ har gjorts är det absolut nödvändigt att införa de nödvändiga beroendena genom att installera Mirage.js via pakethanteraren eller npm-registret.

 npm install --save-dev miragejs 

För att skapa en Mirage.js-serverinstans som fångar upp inkommande förfrågningar och imiterar API-svar, använd metoden createServer som accepterar ett medföljande konfigurationsobjekt.

Den ovan nämnda enheten omfattar både miljökontexten och den tillhörande namngivningskonventionen för vårt API (Application Programming Interface). Specifikt anger miljöparametern den aktuella fasen i API:s livscykel, till exempel dess utvecklingsstatus, medan namnrymden fungerar som en inledande beteckning som läggs till varje API-slutpunkt och därigenom ger en unik identifierare till den.

Jag ska skapa en ny src/server.js fil och införliva det medföljande kodavsnittet i den. Det resulterande skriptet kommer att hantera förfrågningar från kunder som söker information om produkter eller tjänster som erbjuds av ditt företag. Det analyserar först den inkommande begäran för att avgöra dess typ, om det är för produktinformation eller prisinformation. Baserat på detta extraheras relevanta data från databasen med hjälp av dess primära nyckel som identifierare. Om detta lyckas skickar servern tillbaka ett svar som innehåller den begärda informationen i JSON-format. Om begäran misslyckas på grund av ogiltiga inparametrar returneras istället ett felmeddelande.

 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;
}

För att anpassa namnrymden till den specifika strukturen i ditt API:s URL har du flexibiliteten att anpassa den efter dina krav. Dessutom kan du vid behov inkludera ett versionsnummer i namnrymden för att säkerställa kompatibilitet med framtida uppdateringar eller ändringar av API:et. När ert backend-API är färdigutvecklat och i drift kommer det därför endast att krävas mindre justeringar i er kodbas för att integrera det sömlöst i ert användargränssnitt.

Dessutom kan man ange ett dataschema i serverns konfigurationsinställningar för att efterlikna processen för lagring och hämtning av information i ett simulerat sammanhang.

För att starta Mirage.js måste man importera det ovannämnda serverobjektet till antingen filen index.jsx eller filen main.jsx. Detta kan åstadkommas genom följande process:

 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>,
) 

Lägg till seed-data till Mock API

Genom att använda Mirage.js inbyggda minnesdatabas har utvecklare möjlighet att förladda sitt mock API med initial seed-data för teständamål, samt att effektivt hantera testdata som genereras av klientapplikationer. Denna funktion möjliggör sömlös lagring och hämtning av testdata i mock-databasen, som sedan kan användas i klientapplikationen.

För att införliva initiala data i mock API, bör du inkludera följande kodrader omedelbart efter “models”-objektet i “server.js”-filen.

 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.',
      });
    }, 

Funktionen seeds fyller en Mirage.js-server med tre att göra-objekt, vart och ett med en titel och beskrivning. Istället för att hårdkoda testdata kan du integrera ett bibliotek som Faker.js för att generera de testdata som krävs.

Definiera Mock API-rutterna

För att implementera ett funktionellt mock API är det nödvändigt att upprätta flera API-slutpunkter som kan hantera GET-, POST- och DELETE-förfrågningar. Dessa rutter kommer att fungera som grunden för vårt mock-API:s funktionalitet, så att vi kan simulera olika interaktioner med servern och testa olika scenarier. Genom att definiera dessa rutter kan vi effektivt emulera en faktisk API-slutpunkt och validera dess beteende under olika förhållanden.

Under den ursprungliga datauppsättningen, införliva den medföljande koden enligt följande:

 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();
       });
    } 

Bygg en React-klient

När vårt mock-API har upprättats ska vi fortsätta med att bygga en React-klient som kommer att gränssnitt med och använda API-slutpunkterna. Du har tillåtelse att använda det bibliotek för användargränssnittskomponenter som du föredrar, men för tydlighetens skull kommer denna handledning att använda Chakra UI för att berika applikationens utseende.

Installera först dessa beroenden:

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

Låt oss nu generera en ny instans av filen TodoList.jsx, som innehåller följande kodblock:

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

Med tanke på den aktuella uppgiften skulle det vara klokt att utveckla en funktionell komponent som innehåller de nödvändiga elementen för att återge användargränssnittet för att göra-listan, inklusive inmatningsfält som underlättar tillägg av nya uppgifter, samt en uppräkning av aktuella uppgifter.

 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>
  );
} 

en för att lägga till ett objekt i listan (ADD\_ITEM) och en annan för att ta bort ett objekt från listan (REMOVE\_ITEM). Dessa åtgärder ska skickas av motsvarande hanterare som svar på användarens inmatning eller andra relevanta händelser. För att hantera applikationens tillstånd kommer vi att använda useReducer-kroken tillsammans med lämplig reduceringsfunktion. Detta tillvägagångssätt gör det möjligt för oss att upprätthålla ett konsekvent tillståndsträd över alla komponenter samtidigt som vår kod hålls ren och organiserad.

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

När programmet initieras i en webbläsare är det nödvändigt att implementera en mekanism för att hämta och visa seed-data som lagras i en databas i minnet. För att uppnå detta mål kan vi använda kroken useEffect som tillhandahålls av React och kapsla in funktionsanropet fetch inom dess scope. Detta säkerställer att seed-data hämtas och visas när applikationen laddas.

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

Inkluderingen av renderKey state inom ramen för useEffect hook tjänar till att underlätta återaktiveringen av all nyligen införlivad information som finns i vår lokala, operativa databas när värdsystemet fungerar korrekt.

När en användare lägger in ny att göra-information i Mirage.js-arkivet kommer komponenten att genomgå en regenereringsprocess för att återspegla de ändrade uppgifterna visuellt.

Lägga till data i API

För att underlätta tillägg av data via HTTP POST-förfrågningar är det viktigt att implementera en logisk struktur i applikationens programmeringsgränssnitt (API). Omedelbart efter användningen av useEffect kroken, införliva följande implementering.

 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);
     });
}; 

När användaren anger data i det angivna inmatningsfältet och klickar på knappen “Add Todo” uppdaterar systemet den aktuella statusen för “newTodo” med den angivna informationen. Därefter skickas en simulerad HTTP POST-begäran till API:et som innehåller en instans av den uppdaterade datastrukturen i sin begäran för lagring i minnesdatabasen.

Efter en lyckad POST-begäran uppdaterar koden rutinmässigt “todos”-matrisen genom att lägga till det nyskapade uppgiftsobjektet till den. Därefter uppmanas React-funktionskomponenten att genomgå en ny utvärdering, vilket visuellt presenterar det uppdaterade att göra-objektet i listan på sidan.

Mock API DELETE-förfrågningar

För att kunna radera data via DELETE mock API-förfrågningar är det nödvändigt att skapa ett logiskt ramverk för denna process. I huvudsak innebär detta att man sänder en DELETE-begäran som syftar till att radera den givna uppgiften från den temporära databasen. Om åtgärden visar sig vara effektiv är det följaktligen nödvändigt att ändra både listan över utestående uppgifter och laddningsindikatorn för att visa att borttagningsförfarandet har utförts framgångsrikt.

 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);
      });
  }; 

Tänk på att denna metod endast kan radera de data som nyligen har lagts till och inte det ursprungliga datasetet.

Införliva komponenten TodoList i filen App.jsx , så att den visas i Document Object Model (DOM).

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

När man startar utvecklingsservern kan man hämta den ursprungliga datamängden och interaktivt modifiera det simulerade API:et i sin React-applikation genom att både lägga till och ta bort data.

Använda mock-API:er för att snabba upp utvecklingen

Att använda mock-API:er är en effektiv metod för att främja frontend-utveckling, både när arbetet utförs självständigt eller i en samarbetsmiljö. Genom att använda mock-API:er kan man snabbt konstruera användargränssnitt och utvärdera tillhörande kod, utan att behöva vänta på att back-end är klar.