Contents

Mock API's bouwen en gebruiken in React-apps met Mirage.js

Bij het ontwikkelen van full-stack applicaties is een aanzienlijk deel van het frontend werk afhankelijk van real-time gegevens van de backend.

De hierboven beschreven situatie suggereert dat het nodig kan zijn om de ontwikkeling van de gebruikersinterface uit te stellen totdat de API (Application Programming Interface) klaar is voor gebruik. Niettemin kan het uitstellen van de start van de front-end ontwikkeling in afwachting van de gereedheid van de API de voortgang aanzienlijk belemmeren en de duur van de onderneming verlengen.

Een geschikte oplossing voor dit probleem kan worden bereikt door gebruik te maken van mock API’s. Dergelijke API’s maken het ontwikkelen en testen van applicaties mogelijk. Dergelijke API’s maken het mogelijk om een front-end systeem te ontwikkelen en te testen met behulp van gesimuleerde gegevensstructuren, zonder te hoeven vertrouwen op de authentieke API.

Aan de slag met Mirage.js Mock API’s

Mirage.js is een JavaScript bibliotheek waarmee je mock API’s kunt maken, compleet met een testserver die op de client van je webapplicatie draait. Dit betekent dat je je frontend code kunt testen zonder dat je je zorgen hoeft te maken over de beschikbaarheid of het gedrag van je echte backend API.

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

Om Mirage.js te gebruiken, is het noodzakelijk om een set van mock API endpoints te maken en de corresponderende replies te specificeren die deze endpoints moeten leveren. Vervolgens vangt Mirage.js elk verzoek van je front-end applicatie aan de webserver op en vervangt deze door de gesimuleerde antwoorden.

Zodra je application programming interface (API) volledig ontwikkeld en getest is, wordt het implementeren ervan in je project een eenvoudig proces waarbij je enkel de configuratie-instellingen binnen Mirage.js moet aanpassen. Deze gestroomlijnde aanpak zorgt voor een naadloze integratie met minimale verstoring van de bestaande functionaliteit of prestaties.

De broncode van dit project vind je in de bijbehorende GitHub repository.

Een mock API-server maken met Mirage.js

Om een mock API te maken voor een React-applicatie met Mirage.js als backend, bouwen we eerst een eenvoudige taakbeheerapplicatie in React. Voordat we hiermee verder gaan, moeten we een aantal voorbereidende stappen nemen. Ten eerste moet je een nieuwe React-applicatie maken door een van de twee beschikbare methoden te gebruiken. De eerste methode bestaat uit het uitvoeren van de create-react-app opdrachtregelinstructie, wat een algemeen erkende en conventionele aanpak is. Een alternatieve methode is het opzetten van een React-project met behulp van Vite, een moderne ontwikkelserver die bekend is geworden vanwege zijn snelle prestaties.Zodra de keuze tussen deze opties is gemaakt, is het noodzakelijk om de nodige afhankelijkheden te introduceren door Mirage.js te installeren via de package manager of npm register.

 npm install --save-dev miragejs 

Om een Mirage.js server instantie op te zetten die inkomende verzoeken opvangt en API antwoorden imiteert, gebruik je de createServer methode die een bijbehorend configuratie object accepteert.

De bovengenoemde entiteit omvat zowel de omgevingscontext als de bijbehorende naamgevingsconventie voor onze application programming interface (API). Specifiek geeft de omgevingsparameter de huidige fase van de levenscyclus van de API aan, zoals de ontwikkelingsstatus, terwijl de naamruimte dient als een inleidende aanduiding die wordt toegevoegd aan elk API eindpunt, waardoor er een unieke identificatie aan wordt toegekend.

Inderdaad, ik zal een nieuw src/server.js bestand maken en het gegeven codefragment erin opnemen. Het resulterende script zal verzoeken afhandelen van klanten die informatie zoeken over producten of diensten die door uw bedrijf worden aangeboden. Het zal eerst het inkomende verzoek analyseren om het type te bepalen, of het gaat om productdetails of prijsinformatie. Op basis hiervan worden relevante gegevens uit de database gehaald, waarbij de primaire sleutel als identificatie wordt gebruikt. Als dit lukt, stuurt de server een antwoord terug met de gevraagde informatie in JSON-formaat. Als het verzoek echter mislukt vanwege ongeldige invoerparameters, wordt er een foutbericht teruggestuurd.

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

Om de namespace af te stemmen op de specifieke structuur van de URL van je API, heb je de flexibiliteit om deze aan te passen aan je eisen. Daarnaast kun je, indien nodig, een versienummer in de naamruimte opnemen om compatibiliteit met toekomstige updates of wijzigingen aan de API te garanderen. Wanneer je backend API volledig ontwikkeld en operationeel is, vereist het naadloos opnemen ervan in je gebruikersinterface slechts kleine aanpassingen in je codebase.

Bovendien kan men een gegevensschema specificeren binnen de configuratie-instellingen van de server om het proces van het opslaan en ophalen van informatie in een gesimuleerde context na te bootsen.

Inderdaad, om de werking van Mirage.js te starten, moet je het eerder genoemde server object importeren in hun index.jsx of main.jsx bestand. Dit kan worden bereikt door het volgende 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>,
) 

Seed Data toevoegen aan de Mock API

Door gebruik te maken van Mirage.js’s ingebouwde geheugen database, hebben ontwikkelaars de mogelijkheid om hun mock API vooraf te laden met initiële seed data voor testdoeleinden, evenals het effectief beheren van test data gegenereerd door client applicaties.Met deze functie kunnen testgegevens naadloos worden opgeslagen en opgehaald in de schijndatabase, die vervolgens in de clienttoepassing kan worden gebruikt.

Om initiële data op te nemen in de mock API, moet je de volgende regels code opnemen direct na het ‘models’ object in het ‘server.js’ bestand.

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

De seeds functie vult een Mirage.js server met drie to-do items, elk met een titel en beschrijving. Optioneel kun je, in plaats van de testgegevens hard te coderen, een bibliotheek zoals Faker.js integreren om de benodigde testgegevens te genereren.

Definieer de Mock API Routes

Om een functionele mock API te implementeren, is het noodzakelijk om verschillende API endpoints in te stellen die GET, POST en DELETE verzoeken kunnen verwerken. Deze routes dienen als basis voor de functionaliteit van onze mock API, waardoor we verschillende interacties met de server kunnen simuleren en verschillende scenario’s kunnen testen. Door deze routes te definiëren, kunnen we effectief een echt API eindpunt emuleren en het gedrag ervan valideren onder verschillende omstandigheden.

Neem onder de initiële dataset de meegeleverde code als volgt op:

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

Bouw een React-client

Zodra onze mock API is opgesteld, gaan we verder met het bouwen van een React-client die zal interfacen met en gebruik zal maken van de API-eindpunten. Je mag zelf kiezen welke user interface component library je wilt gebruiken, maar voor de duidelijkheid maken we in deze tutorial gebruik van Chakra UI om het uiterlijk van de applicatie te verrijken.

Installeer eerst deze afhankelijkheden:

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

Laten we een nieuw exemplaar van het bestand TodoList.jsx genereren, met daarin het volgende codeblok:

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

Gezien de taak die voor ons ligt, is het verstandig om een functioneel component te ontwikkelen dat de noodzakelijke elementen bevat voor het renderen van de gebruikersinterface van de takenlijst, inclusief invoervelden waarmee nieuwe taken kunnen worden toegevoegd en een opsomming van huidige taken.

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

een voor het toevoegen van een item aan de lijst (ADD\_ITEM) en een andere voor het verwijderen van een item uit de lijst (REMOVE\_ITEM). Deze acties moeten worden uitgevoerd door de corresponderende handlers als reactie op gebruikersinvoer of andere relevante gebeurtenissen. Om de staat van de applicatie te beheren, gebruiken we de useReducer haak samen met de juiste reducer functie. Met deze aanpak kunnen we een consistente statusboom over alle componenten onderhouden en tegelijkertijd onze code schoon en georganiseerd houden.

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

Bij het initialiseren van de applicatie in een webbrowser is het noodzakelijk om een mechanisme te implementeren voor het ophalen en weergeven van de zaadgegevens die zijn opgeslagen in een in-memory database. Om dit doel te bereiken, kunnen we gebruik maken van de useEffect hook van React, waarbij de fetch functieaanroep binnen zijn bereik wordt ingekapseld. Dit zorgt ervoor dat de zaadgegevens worden opgehaald en weergegeven bij het laden van de applicatie.

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

De opname van de renderKey status binnen het bereik van de useEffect hook dient om de reactivering van alle nieuw opgenomen informatie die aanwezig is in onze lokale, operationele database te vergemakkelijken wanneer het hostingsysteem goed functioneert.

In essentie, wanneer een gebruiker nieuwe to-do informatie invoert in de Mirage.js repository, zal het component een regeneratie proces ondergaan om de gewijzigde data visueel weer te geven.

Data toevoegen aan de API

Om het toevoegen van data via HTTP POST requests te vergemakkelijken, is het essentieel om een logische structuur te implementeren binnen de application programming interface (API). Onmiddellijk na het gebruik van de haak useEffect moet de volgende implementatie worden opgenomen.

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

Nadat de gebruiker gegevens heeft ingevoerd in het daarvoor bestemde invoerveld en op de knop “Todo toevoegen” heeft geklikt, werkt het systeem de huidige status van “newTodo” bij met de verstrekte informatie. Vervolgens wordt er een gesimuleerd HTTP POST-verzoek naar de API gestuurd met een instantie van de bijgewerkte gegevensstructuur in de verzoektekst voor opslag in de in-memory database.

Na een succesvol POST-verzoek werkt de code de “todo’s”-array procedureel bij door het nieuw aangemaakte taakobject eraan toe te voegen. Vervolgens wordt het functionele React-onderdeel gevraagd om een herevaluatie uit te voeren, waarbij het bijgewerkte todo-item visueel wordt weergegeven in de lijst op de pagina.

Mock API DELETE Requests

Om gegevens te verwijderen via DELETE mock API requests, moet er een logisch kader voor dit proces worden opgezet. In essentie komt dit neer op het verzenden van een DELETE verzoek gericht op het verwijderen van de gegeven taak uit de tijdelijke database. Als de operatie effectief blijkt, is het dus essentieel om zowel de lijst met uitstaande taken als de laadindicator te wijzigen om aan te geven dat de verwijderingsprocedure succesvol is uitgevoerd.

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

Houd er rekening mee dat deze methode alleen de gegevens kan verwijderen die onlangs zijn toegevoegd en niet de oorspronkelijke dataset.

Neem het TodoList component op in het App.jsx bestand, zodat het wordt weergegeven in het Document Object Model (DOM).

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

Na het starten van de ontwikkelserver kan men inderdaad de initiële dataset ophalen en de gesimuleerde API interactief wijzigen binnen hun React-applicatie door zowel gegevens toe te voegen als te verwijderen.

Mock API’s gebruiken om ontwikkeling te versnellen

Het gebruik van mocking API’s is een efficiënte methode om front-end ontwikkeling te bevorderen, zowel bij zelfstandig werken als bij samenwerken. Door gebruik te maken van mock API’s kan men snel gebruikersinterfaces bouwen en de bijbehorende code beoordelen, zonder te hoeven wachten op de voltooiing van de back-end.