Naar de hoofdinhoud gaan

Client voor HTTP-services en REST API

Introductie​

In het technologische ecosysteem van Netuno worden enkele modules op NPM geleverd, zoals:

Zie ook de GIT-repository van de Service Client.

Deze module dient om integraties uit te voeren met de services die in Netuno zijn ontwikkeld, dat wil zeggen, de endpoints van de REST API die in de backend van Netuno zijn ontwikkeld, binnen de map server/services in de Netuno-applicaties.

Het is gebruikelijk bij de ontwikkeling van services om programma's te gebruiken zoals:

om HTTP-verzoeken naar de services te testen.

In de frontendcode zouden we om deze services te integreren fetch, requests, AXIOS en zoveel andere kunnen gebruiken.

Netuno levert echter zijn eigen client, die werkt bij de ontwikkeling van JavaScript-frontend en ook in de NodeJS-backend.

De reden waarom Netuno zijn eigen implementatie van een HTTP-client voor de services heeft, is om meer praktisch gemak te bieden, de implementatie van de code te vereenvoudigen en meer snelheid in de ontwikkeling te garanderen.

Installatie​

De installatie van de service-client is zoals het installeren van elke andere module.

Waar we het bestand package.json hebben, voeren we het installatiecommando uit:

bun add @netuno/service-client

Importeren​

Om de service-client te importeren in moderne JavaScript-ontwikkeling:

import _service from '@netuno/service-client';

Om de service-client te importeren in klassieke JavaScript-ontwikkeling:

const _service = require('@netuno/service-client');

Merk op dat de interne naam in de code _service is.

Standaard gebruikt Netuno de _ als prefix om aan te geven dat iets intern of specifiek is, zoals een hulpmiddel of een tool uit zijn ecosysteem.

Daarom moeten we, om de standaard te volgen, altijd de naam _service gebruiken.

Configuratie​

De configuratie wordt globaal uitgevoerd: de configuratie wordt één keer gedefinieerd en kan het beste op een beginpunt van de algemene code worden uitgevoerd.

Dit zal de minimale configuratie zijn:

_service.config({
prefix: 'http://localhost:9000/services/'
});

Dat wil zeggen, definieert de prefix van de adressen van de services, dit voorkomt de noodzaak om altijd de volledige URL te plaatsen, zodat we bij de aanroepen naar de services alleen de rest van de URL hoeven aan te geven.

Volledige configuratie​

We kunnen standaardwaarden configureren voor alle aanroepen van services, waarbij we bij de aanroep van elke service deze waarden kunnen overschrijven.

Zie alle parameters die we kunnen configureren:

_service.config({
prefix: '',
url: '',
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
start: () => { },
success: (data) => { },
fail: (data) => {},
end: () => { }
});

prefix​

Is de globale prefix van de URL's.

url​

Is het deel van de URL dat aan de prefix wordt toegevoegd, het specifieke adres van de service.

method​

HTTP-methode die gebruikt wordt in het HTTP-verzoek, standaard is dit GET.

credentials​

Definieert het gedrag van de inloggegevens bij de HTTP-aanroepen:

  • omit - Verzendt en ontvangt nooit inloggegevens.
  • same-origin - Verzendt en voegt alleen inloggegevens toe wanneer het verzoeken binnen hetzelfde domein betreft.
  • include - Moet altijd de inloggegevens opnemen, zelfs als het domein verschilt.

Standaard is de waarde include, omdat dit het meest logisch is in standaardontwikkeling; de backend kan zich al dan niet in hetzelfde domein bevinden, afhankelijk van de architectuur, en bij lokale ontwikkeling verschilt dit soms van productie, daarom raden we aan om include te gebruiken om verrassingen te voorkomen.

headers​

In de headers kunnen we sleutels en waarden in de HTTP-header definiëren.

Standaard is gedefinieerd dat gegevens in JSON-formaat worden verzonden en ontvangen.

start​

callback-functie die wordt uitgevoerd wanneer het HTTP-verzoek gaat beginnen.

succes​

callback-functie die wordt uitgevoerd wanneer het HTTP-verzoek met succes is uitgevoerd op de backend-server.

De inhoud van het antwoord wordt verkregen via het eerste argument van de functie.

fail​

callback-functie die wordt uitgevoerd wanneer het HTTP-verzoek een fout heeft veroorzaakt.

De details van de fout worden verkregen via het eerste argument van de functie.

end​

callback-functie die wordt uitgevoerd wanneer het HTTP-verzoek is voltooid.

Wordt altijd uitgevoerd, ongeacht of er succes of een fout was.

Gebruik​

Om een service uit te voeren met een HTTP-verzoek definiëren we de waarden van de parameters die de vereisten van de service configureren.

In de sleutel data verzenden we de gegevens zelf, dat wil zeggen, alle gegevensparameters die we naar de backend-service gaan verzenden.

Zie het basisvoorbeeld van een verzoek:

import _service from '@netuno/service-client';

_service({
url: "mijn-service",
data: { id: 1, voorbeeld: "Hallo backend." },
start: () => {
console.log("Het verzoek gaat beginnen.");
},
success: (response) => {
if (response.text) {
console.info("Antwoordde in tekst:", response.text);
}
if (response.json) {
console.info("Antwoordde in JSON:", response.json);
}
},
fail: (error) => {
console.error("Mislukt met de fout:", error);
},
end: () => {
console.log("Het verzoek is voltooid.");
}
});

De uiteindelijke URL houdt rekening met de prefix die globaal is gedefinieerd in de algemene configuratie.

Omdat de HTTP-methode niet is gedefinieerd, wordt verzonden met de standaardmethode die in de algemene configuratie is gedefinieerd, die standaard GET is.

Eenvoudig​

Eenvoudig voorbeeld van hoe een verzoek van het type POST uit te voeren:

import _service from '@netuno/service-client';

_service({
method: "POST",
url: "product",
data: { naam: "Strohoed", aantal: 20 },
success: ({json}) => {
console.info("Product succesvol aangemaakt:", json);
},
fail: (error) => {
console.error("Fout bij aanmaken product:", error);
}
});

Formulier​

Wanneer we formulieren gebruiken, kunnen we de klasse FormData laden met de inhoud van het formulier, zie het voorbeeld:

import _service from '@netuno/service-client';

const formData = new FormData(document.getElementById("formulier"));
_service({
method: "PUT",
url: "klant",
data: formData,
success: ({json}) => {
if (json.result === true) {
alert("Klant succesvol bijgewerkt.");
} else {
alert("Ongeldig antwoord.");
}
},
fail: (e) => {
console.log("Fout", e);
}
});

Upload​

Eenvoudig voorbeeld van hoe bestanden te uploaden met de klasse FormData:

import _service from '@netuno/service-client';

const formData = new FormData();
formData.append('uid', 'c476964a-eb8b-40d1-8907-4fee2e1532fb');
formData.append('bestand', document.getElementById("bestandVeld").files[0]);
formData.append('anderVeld', 'waarde...');
_service({
method: "PUT",
url: "/upload",
data: formData,
success: ({json}) => {
alert('Bestand succesvol geüpload.');
},
fail: (e) => {
console.log("Fout in antwoord", e);
}
});

Download​

We kunnen bestanden die dynamisch door services worden gegenereerd, downloaden op een geïntegreerde manier in de context van de pagina.

BLOB - Binair Groot Object​

Om binaire antwoorden te downloaden, moeten we blob met de waarde true instellen in de basisparameters, en we verkrijgen de gegenereerde bytes in de blob van het antwoord.

import _service from '@netuno/service-client';

_service({
url: "/download",
method: 'POST',
data: { uid: "98e25c93-d662-4b5c-8b89-d19b42e2c998", type: "pdf" },
blob: true, // Geeft aan dat het antwoord binair is.
success: ({blob}) => {
if (blob) {
const file = window.URL.createObjectURL(blob);
window.location.assign(file);
} else {
alert("Ongeldig antwoord.");
}
},
fail: (e) => {
console.log("Fout", e);
}
});

Aangepast bestand​

De naam en het type van het bestand kunnen in de frontend worden aangepast; de afhankelijkheid DownloadJS is zeer nuttig in dit proces.

Installeer de afhankelijkheid DownloadJS:

bun add downloadjs

In de code kan het als volgt worden gebruikt:

import _service from '@netuno/service-client';
import download from 'downloadjs';

_service({
url: "/services/rapport/excel",
blob: true,
success: ({ blob }) => {
if (blob) {
download(blob, "rapport.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
},
fail: (e) => {
console.log("Fout", e);
}
});

_service({
url: "/services/rapport/pdf",
blob: true,
success: ({ blob }) => {
if (blob) {
download(blob, "rapport.pdf", "application/pdf");
}
},
fail: (e) => {
console.log("Fout", e);
}
});

URL voor services​

Er zijn situaties waarin we de URL van services moeten genereren, bijvoorbeeld wanneer er services zijn die hulpmiddelen leveren die in de HTML of CSS moeten worden geïntegreerd.

Een duidelijk voorbeeld is de Avatar: de gebruiker definieert zijn avatarafbeelding en om deze te presenteren kunnen we de uiteindelijke URL als volgt genereren:

const avatarUrl = _service.url(`/profile/avatar?uid=${user.uid}`)

De gegenereerde URL kan in de HTML of in een CSS-eigenschap, zoals de background, worden geïnjecteerd.

React & Ant.Design​

Omdat we veel React en Ant.Design gebruiken, volgen hier enkele nuttige tips.

De klassieke imports:

import React, {useState} from "react";
import { Form, notification } from 'antd';
import _service from '@netuno/service-client';

De verwerkingsstatus definiëren:

const [laden, setLaden] = useState(false);

Implementatie van de gebeurtenis om een formulier op te slaan, dat het object met de ingevulde waarden in JSON-formaat verzendt:

const onFinish = (waarden) => {
const bijFout = () => {
notification.error({
title: 'Fout',
description: 'Kon de gegevens niet opslaan.'
});
};
_service({
url: '/services/klant',
method: 'POST',
data: waarden,
start: () => {
setLaden(true);
},
success: ({json}) => {
if (json.result === true) {
notification.success({
title: 'Succes',
description: 'De gegevens zijn succesvol opgeslagen.'
});
return;
}
bijFout();
},
fail: (e) => {
console.error("Service mislukt.", e);
bijFout();
},
end: () => {
setLaden(false);
},
});
};

In de formuliercomponent van Ant.Design definieert men de eigenschap van de actie die de gegevens verzendt met de eerder geïmplementeerde gebeurtenis, bijvoorbeeld:

<Form onFinish={onFinish}>
...
</Form>

Upload​

Hier is een volledig voorbeeld van hoe bestanden te uploaden met een formulier in Ant.Design en met de FormData:

import {useState} from 'react';
import _service from '@netuno/service-client';
import {Button, Form, Input, Upload, notification} from 'antd';
import { PlusOutlined } from '@ant-design/icons';

function UploadFormulier() {
const [laden, setLaden] = useState(false);
const onFinish = (waarden)=> {
const formData = new FormData();
formData.append("titel", waarden.titel);
formData.append("bestand", waarden.bestand.fileList[0].originFileObj);
_service({
method: "POST",
url: "bestand/opslaan",
data: formData,
start: () => {
setLaden(true);
},
success: () => {
notification.success({
title: 'Formulier',
description: 'Uw gegevens zijn succesvol opgeslagen.'
});
},
fail: (e) => {
console.error("Uploadformulier mislukt", e);
notification.error({
title: 'Formulier',
description: 'Kon uw gegevens niet opslaan.'
});
},
end: () => {
setLaden(false);
}
});
};
return (
<Form onFinish={onFinish} layout="vertical">
<Form.Item label="Titel" name="titel"
rules={[{ required: true, message: 'Voer de titel in.' }]}
>
<Input />
</Form.Item>
<Form.Item label="Bestand" name="bestand"
rules={[{ required: true, message: 'Voer het bestand in.' }]}
>
<Upload listType="text" maxCount={1}>
<button type="button" style={{color: 'inherit', cursor: 'inherit', border: 0, background: 'inherit'}}>
<PlusOutlined />
<div style={{marginTop: 8}}>Uploaden</div>
</button>
</Upload>
</Form.Item>
<Form.Item label={null}>
<Button type="primary" htmlType="submit" loading={laden}>
Opslaan
</Button>
</Form.Item>
</Form>
);
}

export default UploadFormulier;

Conclusie​

De Service Client versnelt de integratie met de backend om gegevens en bestanden op te halen en te verzenden.

Het is mogelijk om elke andere native methode of andere afhankelijkheid te gebruiken om deze bewerkingen uit te voeren, maar de Service Client is ontwikkeld om integraties te vergemakkelijken en te versnellen, en is flexibel en zeer intuïtief.

Het belangrijkste doel van Netuno om de Service Client in zijn ecosysteem te leveren, is garanderen dat de ontwikkeling duidelijk en snel is.

Als u bij het gebruik van de Service Client een probleem tegenkomt, meld dit dan in de Issues van het project.

⭐ Vergeet niet een ster te geven aan de GitHub van het project: