Hoe maak je een geweldige API: een gids voor iedereen die geïnteresseerd is
Waarom API’s maken, het belang van API’s
Een API (Application Programming Interface) fungeert als een menu voor software, waarin de beschikbare functies worden beschreven en hoe deze kunnen interageren. Het is essentieel om verschillende softwaresystemen soepel en efficiënt te laten communiceren. Een goed ontworpen API kan de functionaliteit en waarde van softwaretoepassingen aanzienlijk verbeteren door ze in staat te stellen naadloos gebruik te maken van externe diensten of gegevens.
Ben je klaar om je eigen API te maken, maar weet je niet waar je moet beginnen? Maak je geen zorgen! We staan voor je klaar met enkele eenvoudige stappen en voorbeelden om je te helpen een fantastische API te bouwen die veilig, snel en gebruiksvriendelijk is, zodat deze op de juiste manier kan worden ontwikkeld en getest.
Stap 1: Uw API functioneel plannen
- Consistentie: uw API moet gemakkelijk te lezen en te begrijpen zijn. Gebruik duidelijke naamgevingsconventies en zorg voor een consistente indeling in je API om verwarring te voorkomen.
- Passende acties: Gebruik HTTP-werkwoorden (GET, POST, PUT) op de juiste manier om de functionaliteit van uw API logisch te organiseren.
- Uitgebreide dekking: zorg ervoor dat uw API alle acties omvat die gebruikers mogelijk nodig hebben, zodat deze echt nuttig is.
- Gegevensintegriteit en beveiliging: Wees duidelijk en consistent in de gegevens die je API nodig heeft en levert, en zorg ervoor dat je gevoelige informatie niet onnodig blootstelt.
- Duidelijke reacties: zorg ervoor dat je API duidelijke feedback geeft, zodat gebruikers weten wat het resultaat is van hun verzoeken of waarom een verzoek is mislukt. Voorbeeld: OpenAPI-specificatie
Toont een basisconfiguratie met behulp van de OpenAPI-standaard, die gemakkelijk te begrijpen is en ervoor zorgt dat uw API goed gedocumenteerd en testbaar is.
Een api-configuratie kan worden gegenereerd in de openapi-standaard, zodat deze gemakkelijk leesbaar en goed te begrijpen is
openapi: 3.0.3
info:
title: SAP Accounts Payable API
description: API for managing accounts payable, including vendor details and invoice entries.
version: 1.0.0
servers:
- url: http://sap.example.com/api/v1
paths:
/vendors/{vendorId}:
get:
summary: Get vendor details
operationId: getVendorById
parameters:
- name: vendorId
in: path
required: true
description: Unique identifier of the vendor
schema:
type: string
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Vendor'
'404':
description: Vendor not found
/invoices:
post:
summary: Create a new invoice entry
operationId: createInvoice
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewInvoice'
responses:
'201':
description: Invoice created successfully
'400':
description: Invalid input
components:
schemas:
Vendor:
type: object
properties:
vendorId:
type: string
description: Unique identifier of the vendor
name:
type: string
description: Name of the vendor
email:
type: string
description: Email address of the vendor
NewInvoice:
type: object
properties:
vendorId:
type: string
description: Vendor associated with the invoice
amount:
type: number
format: double
description: Total amount of the invoice
dueDate:
type: string
format: date
description: Due date for the invoice payment
Dit voorbeeld bevat een standaard OpenAPI-specificatie voor een SAP Accounts Payable API, die bewerkingen omvat voor het beheren van leveranciersinformatie en factuurboekingen. De voorbeelden van contracttests laten zien hoe de functionaliteit van de API kan worden gevalideerd door middel van positieve en negatieve tests, waarbij ervoor wordt gezorgd dat de API zich onder verschillende omstandigheden gedraagt zoals verwacht. Deze aanpak helpt de betrouwbaarheid en integriteit van de API te behouden, wat cruciaal is voor financiële transacties zoals crediteurenbeheer.
Voorzichtig bijwerken: Als je wijzigingen aanbrengt in je API, doe dat dan op een manier die de API niet kapot maakt voor gebruikers. U hebt mogelijk verschillende versies (zoals v1, v2) voor grote wijzigingen, u kunt pact gebruiken voor schijncontroles om te voorkomen dat wijzigingen in de productie worden doorbroken. Pact heb ik uitgelegd in een andere blog op mijn website
Geef nuttige fouten: Als er iets misgaat, moet je API op een eenvoudige manier uitleggen wat er is gebeurd. Dit helpt gebruikers bij het oplossen van hun verzoeken.
Hoe kun je die functionele controles instellen? Door de documentatie zorgvuldig te documenteren en impliciet te valideren, zouden die fouten er functioneel uit moeten zien als
- Validatiefouten
Wanneer de gebruiker gegevens verstrekt die niet voldoen aan de validatiecriteria (er ontbreekt bijvoorbeeld een verplicht veld of een waarde valt buiten het toegestane bereik).
- Ongeldig foutbericht: „Validatie mislukt.”
- Goede foutmelding: „Validatiefout: het veld ’e-mail’ is verplicht en moet een geldig e-mailadres zijn.”
- Verificatie- en autorisatiefouten
Wanneer een gebruiker niet is geverifieerd (aangemeld) of geen toestemming heeft om toegang te krijgen tot een bepaalde bron of een bepaalde actie uit te voeren.
- Ongeldig foutbericht: „Toegang geweigerd.”
- Goede foutmelding: „Authenticatiefout: u moet aangemeld zijn om toegang te krijgen tot deze bron.” of „Autorisatiefout: u hebt geen toestemming om deze actie uit te voeren.”
- Bron niet gevonden
Wanneer de gevraagde bron (bijvoorbeeld een specifiek item of eindpunt) niet bestaat.
- Ongeldig foutbericht: „Niet gevonden.”
- Goede foutmelding: „Het gevraagde item met ID 12345 is niet gevonden. Controleer of de ID juist is en probeer het opnieuw.”
- Snelheidsbeperking
Wanneer een gebruiker in korte tijd te veel aanvragen heeft gedaan.
- Ongeldig foutbericht: „Verzoeklimiet overschreden”.
- Goede foutmelding: „Je hebt je aanvraaglimiet van 100 verzoeken per uur overschreden. Wacht alstublieft even voordat u nieuwe aanvragen indient.”
- Interne serverfouten
Als er iets misgaat aan de serverzijde dat de gebruiker niet direct kan herstellen.
- Ongeldig foutbericht: „Interne serverfout”.
- Goede foutmelding: „Er is een onverwachte fout opgetreden aan onze kant. We zijn op de hoogte gebracht en werken aan een oplossing. Probeer het later opnieuw.”
- Afhankelijkheidsfouten
Wanneer uw API afhankelijk is van externe services of systemen die momenteel niet beschikbaar zijn of niet werken.
- Ongeldig foutbericht: „Service niet beschikbaar.”
- Goede foutmelding: „Onze service voor het omrekenen van valuta is momenteel niet beschikbaar. We zijn op de hoogte van het probleem en werken eraan om de service zo snel mogelijk te herstellen. Probeer het later opnieuw.”
- Fouten in de gegevensindeling
Wanneer het formaat van de verstrekte gegevens (bijvoorbeeld JSON, XML) onjuist of onjuist is.
-
Ongeldig foutbericht: „Ongeldig verzoek.”
-
Goede foutmelding: „De hoofdtekst van uw aanvraag bevat ongeldige JSON. Corrigeer dit en probeer het opnieuw.” Voor elk type fout is het belangrijk om:
-
Geef duidelijk aan wat het probleem is.
-
Geef indien mogelijk begeleiding of suggesties om het probleem op te lossen.
-
Gebruik een beleefde en constructieve toon. .
Stap 2: Uw API zo snel veilig en krachtig maken (NFR-testen)
Beveiligingspraktijk 1) Keep It Safe: Uw API moet controleren wie de API probeert te gebruiken. Je kunt wachtwoorden, tokens (zoals een geheime sleutel) of andere methoden gebruiken om ervoor te zorgen dat alleen de juiste mensen toegang hebben.
components:
securitySchemes:
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://sap.finance.com/oauth2/authorize
tokenUrl: https://sap.finance.com/oauth2/token
scopes:
read:invoices: "Read access to invoices"
write:invoices: "Write access to invoices"
Of gebruik basisauth (tegenwoordig niet de voorkeursoplossing in prod maar om goed te testen)
RequestBody en reacties vind je hier
import requests
from requests.auth import HTTPBasicAuth
# SAP service URL
url = 'http://sap.example.com/api/v1/invoices'
# Your credentials
username = 'your_username'
password = 'your_password'
# Make a GET request with Basic Authentication
response = requests.get(url, auth=HTTPBasicAuth(username, password))
# Check if the request was successful
if response.status_code == 200:
# Process the response data (assuming JSON response)
data = response.json()
print(data)
else:
print(f'Failed to retrieve data. Status code: {response.status_code}')
import requests
# The URL of the API you're calling
url = 'http://example.com/api/data'
# Your API key
api_key = 'your_api_key_here'
# The header where the API key is expected (commonly 'Authorization' or 'X-API-Key')
headers = {
'Authorization': f'Bearer {api_key}',
# or if the API expects a custom header, it might look like
# 'X-API-Key': api_key
}
# Make the request
response = requests.get(url, headers=headers)
# Check if the request was successful
if response.status_code == 200:
# Process the response data (assuming JSON response)
data = response.json()
print(data)
else:
print(f'Failed to retrieve data. Status code: {response.status_code}')
Voorkom overbelasting: Stel limieten in voor hoe vaak iemand je API om iets kan vragen. Dit helpt je API soepel te laten werken zonder te crashen.
from flask import Flask, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
# Initialize Flask app
app = Flask(__name__)
# Initialize Limiter
limiter = Limiter(
app,
key_func=get_remote_address, # Use the remote address of the client as the rate limiting key
default_limits=["100 per hour", "20 per minute"] # Global rate limits
)
# Apply rate limits to specific routes
@app.route("/api/data")
@limiter.limit("10 per minute") # More restrictive rate limit for this endpoint
def get_data():
return jsonify({"message": "This is rate limited API data."})
if __name__ == "__main__":
app.run(debug=True)
Prestatiepraktijk 1) Strategie voor snelheidslimieten: De snelheidslimieten die u instelt („100 per uur”, „20 per minuut”) moeten gebaseerd zijn op de capaciteit van uw server en het verwachte gebruikspatroon van uw API. Mogelijk moet u deze waarden aanpassen op basis van gebruiksgegevens uit de echte wereld. Het is mogelijk om tarieflimieten aan te passen: U kunt tarieflimieten instellen die globaal, per route of zelfs dynamisch van toepassing zijn op basis van het type gebruiker dat de aanvraag doet. Overschrijding van de verwerkingssnelheid: Wanneer een klant de snelheidslimiet overschrijdt, wordt gewoonlijk een antwoord van 429 Too Many Requests geretourneerd.
Beveiligingspraktijk 2) Beveiliging en eerlijkheid: Hoewel snelheidsbeperking cruciaal is voor de bescherming van uw API, moet u ervoor zorgen dat deze eerlijk wordt geïmplementeerd en legitieme gebruikers niet onbedoeld de toegang tot uw service blokkeert. Overweeg om geavanceerdere snelheidsbeperkingen in te voeren op basis van gebruikersaccounts of API-sleutels voor een betere controle. Dus gebruiker b kan 200 aanvragen, een seconde aanvragen, enz., of de geolocatie-instellingen gebruiken.
Prestatiepraktijk 2) Caching: Overweeg om bepaalde gegevens tijdelijk op te slaan, zodat je API sneller antwoorden kan geven. Dit maakt je API efficiënter. Hieronder een voorbeeld aan de klantzijde
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caching with localStorage</title>
</head>
<body>
<button id="fetchDataBtn">Fetch Data</button>
<div id="dataDisplay"></div>
<script>
const fetchDataBtn = document.getElementById('fetchDataBtn');
const dataDisplay = document.getElementById('dataDisplay');
const fetchData = async () => {
const cacheKey = 'apiData';
const cacheTimeKey = 'apiDataTime';
const cacheDuration = 60000; // Cache duration in milliseconds (e.g., 60000ms = 1 minute)
// Check if we have cached data and it's within our cache duration
const cachedData = localStorage.getItem(cacheKey);
const cachedTime = localStorage.getItem(cacheTimeKey);
if (cachedData && cachedTime && new Date().getTime() - cachedTime < cacheDuration) {
console.log('Using cached data');
displayData(JSON.parse(cachedData));
return;
}
console.log('Fetching new data');
// Replace 'https://jsonplaceholder.typicode.com/posts' with the actual API URL
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const data = await response.json();
// Update cache with new data
localStorage.setItem(cacheKey, JSON.stringify(data));
localStorage.setItem(cacheTimeKey, new Date().getTime());
displayData(data);
};
const displayData = (data) => {
// Just display the first item for demonstration
if (data && data.length > 0) {
dataDisplay.innerText = `Post #1: ${data[0].title}`;
} else {
dataDisplay.innerText = 'No data found';
}
};
fetchDataBtn.addEventListener('click', fetchData);
</script>
</body>
</html>
Beveiligingspraktijk 3) Voorbeeld van SQL-injectie
from flask import Flask, request
import sqlite3
app = Flask(__name__)
@app.route('/api/search', methods=['GET'])
def search():
keyword = request.args.get('keyword') # User-provided search keyword
# Dangerous: Constructing SQL directly from user input
query = f"SELECT * FROM products WHERE name LIKE '%{keyword}%'"
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute(query)
results = cursor.fetchall()
return {'results': results}
if __name__ == '__main__':
app.run()
Het beveiligingslek misbruiken:
Een aanvaller kan de zoekfunctie gebruiken om SQL-opdrachten te injecteren door een speciaal ontworpen sleutelwoord op te geven:
%'; DROP TABLE products; --
Wanneer deze wordt opgenomen in de API-aanvraag, wordt de geconstrueerde SQL-query:
SELECT * FROM products WHERE name LIKE '%%'; DROP TABLE products
katten; –%'
Welke tools kun je gebruiken om de functionaliteit, prestaties en beveiliging van API’s te testen?
Functionaliteitstesten
- Postman: Postman is een van de meest populaire API-testtools en is geweldig voor handmatige en geautomatiseerde tests. Het maakt het mogelijk om eenvoudig API-tests te maken, te delen en uit te voeren en ondersteunt verschillende soorten API-verzoeken, omgevingen en authenticatiemethoden.
- SoapUI: Hoewel het aanvankelijk gericht was op SOAP-services, ondersteunt SoapUI nu ook RESTful API’s. Het is geschikt voor functionele tests en biedt ook functies voor beveiligings- en prestatietests. SoapUI maakt testautomatisering mogelijk en kan worden geïntegreerd in CI/CD-pijplijnen.
- Katalon Studio: een uitgebreide tool die zowel API- als UI-testen ondersteunt. Katalon Studio is ontworpen voor testers van alle niveaus en kan worden geïntegreerd met andere tools en frameworks zoals JIRA, QTest, Kobiton en Jenkins voor CI/CD-pipelines.
- Jest is een geweldig JavaScript-testraamwerk met een focus op eenvoud, dat taken ondersteunt zoals het testen van eenheden, en in combinatie met Supertest wordt het een krachtig hulpmiddel voor het testen van HTTP API’s.
- Rest Assured is een Java DSL voor het vereenvoudigen van het testen van op REST gebaseerde services. Het ondersteunt de notatie van de gegeven/wanneer/dan-test, die zeer leesbaar is en aansluit bij moderne testpraktijken.
Prestatietesten
- JMeter: een open-source tool die is ontworpen voor het testen van belastingen en het meten van prestaties. Oorspronkelijk ontwikkeld voor webtoepassingen, kan JMeter ook RESTful- en SOAP-API’s testen. Het ondersteunt een breed scala aan tests, waaronder belasting-, stress- en spike-tests.
- Gatling: Gatling is een andere open-source tool gericht op het testen van belastingen. Het staat bekend om zijn hoge prestaties en is ontworpen voor gebruiksgemak. Gatling biedt gedetailleerde prestatierapporten en ondersteunt integratie met CI/CD-tools.
- LoadRunner: een uitgebreide tool voor het testen van belastingen van Micro Focus die een breed scala aan technologieën ondersteunt die verder gaan dan API’s, waaronder web- en mobiele apps. LoadRunner simuleert duizenden gebruikers om de prestaties van API’s onder zware belasting te testen en biedt gedetailleerde analyses.
- Locust; Een open source-tool voor Python, waarvoor ik op grote schaal een kleine cdk-setup heb gemaakt
Beveiligingstests
- OWASP ZAP (Zed Attack Proxy): een open-source beveiligingstool die speciaal is ontworpen voor het testen van de beveiliging van webapplicaties, die kan worden uitgebreid om API’s te testen op kwetsbaarheden zoals SQL Injection, Cross-Site Scripting (XSS) en meer.
- Burp Suite: een populaire tool voor het testen van de beveiliging van webapplicaties, ook effectief voor het testen van de beveiliging van web-API’s. Het biedt geautomatiseerde scans en hulpmiddelen voor handmatige penetratietesters om beveiligingsproblemen te identificeren en te exploiteren.
- Postman: Naast functionele tests kan Postman worden gebruikt voor basisbeveiligingstests, zoals het controleren op de juiste authenticatie, versleuteling en SQL-injectiekwetsbaarheden door kwaadaardige API-verzoeken te maken.
- API Security.io: een API-beveiligingsscanner in de cloud die REST- en GraphQL-API’s scant op beveiligingsproblemen. Het controleert op veelvoorkomende beveiligingsproblemen en verkeerde configuraties.
Combinatie van gereedschappen
Sommige tools bieden functionaliteit voor meer dan één type test:
- SoapUI: biedt functionaliteit voor functionele, prestatie- en basisbeveiligingstests van API’s.
- Katalon Studio: ondersteunt functionele, prestatie- (via integratie met JMeter) en basisbeveiligingstests.
Conclusie
Het creëren van een geweldige API vereist een zorgvuldige planning, een focus op beveiliging en prestaties, en een toewijding aan bruikbaarheid en duidelijke communicatie. Door de richtlijnen in dit document te volgen, kunt u een API ontwerpen die niet alleen krachtig en efficiënt is, maar ook gemakkelijk te gebruiken en te integreren is voor ontwikkelaars in hun applicatie.