API JSON e servizi REST: Guida completa per sviluppatori
Guida completa alle API JSON e REST: metodi HTTP, autenticazione, best practices, esempi pratici con fetch e axios. Impara a creare e consumare API moderne.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# API JSON e servizi REST: Guida completa per sviluppatori
Le API REST con JSON sono il fondamento del web moderno. Questa guida completa ti insegnerà tutto ciò che devi sapere per creare e consumare API JSON professionalmente.
Cos'è una API REST?
REST (Representational State Transfer) è uno stile architetturale per API web che usa:
- HTTP methods: GET, POST, PUT, DELETE
- JSON: Formato di scambio dati
- Stateless: Ogni richiesta è indipendente
- Resource-based: URL rappresentano risorse
Esempio API REST
GET /api/users # Lista utenti
GET /api/users/123 # Utente specifico
POST /api/users # Crea utente
PUT /api/users/123 # Aggiorna utente
DELETE /api/users/123 # Elimina utente
Metodi HTTP
GET - Recuperare dati
// Fetch API
fetch('https://api.example.com/users/123')
.then(response => response.json())
.then(user => {
console.log(user);
// { id: 123, nome: "Marco", email: "marco@example.com" }
});
// Async/await
async function getUser(id) {
const response = await fetch(https://api.example.com/users/${id});
const user = await response.json();
return user;
}
POST - Creare risorse
const newUser = {
nome: "Marco",
email: "marco@example.com",
password: "SecurePass123"
};
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newUser)
})
.then(response => response.json())
.then(data => {
console.log('Utente creato:', data);
// { id: 456, nome: "Marco", ... }
});
PUT - Aggiornare risorse
const updatedUser = {
nome: "Marco Rossi",
email: "marco.rossi@example.com"
};
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updatedUser)
})
.then(response => response.json())
.then(data => console.log('Utente aggiornato:', data));
PATCH - Aggiornamento parziale
// Aggiorna solo l'email
const patch = {
email: "nuovo.email@example.com"
};
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(patch)
})
.then(response => response.json())
.then(data => console.log('Email aggiornata:', data));
DELETE - Eliminare risorse
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('Utente eliminato');
}
});
Codici di stato HTTP
2xx Success
200 OK # Richiesta riuscita
201 Created # Risorsa creata
204 No Content # Successo senza body
3xx Redirection
301 Moved Permanently
302 Found
304 Not Modified
4xx Client Error
400 Bad Request # Dati invalidi
401 Unauthorized # Non autenticato
403 Forbidden # Non autorizzato
404 Not Found # Risorsa non trovata
422 Unprocessable # Validazione fallita
5xx Server Error
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
Gestione errori completa
async function apiCall(url, options = {}) {
try {
const response = await fetch(url, options);
// Gestisci errori HTTP
if (!response.ok) {
const error = await response.json();
throw new Error(HTTP ${response.status}: ${error.message});
}
// Parse JSON
const data = await response.json();
return { success: true, data };
} catch (error) {
console.error('API Error:', error);
return {
success: false,
error: error.message
};
}
}
// Uso
const result = await apiCall('https://api.example.com/users');
if (result.success) {
console.log('Dati:', result.data);
} else {
console.error('Errore:', result.error);
}
Autenticazione
1. API Key
fetch('https://api.example.com/data', {
headers: {
'X-API-Key': 'your-api-key-here'
}
})
.then(response => response.json())
.then(data => console.log(data));
2. Bearer Token
const token = 'your-jwt-token';
fetch('https://api.example.com/protected', {
headers: {
'Authorization': Bearer ${token}
}
})
.then(response => response.json())
.then(data => console.log(data));
3. Basic Auth
const username = 'user';
const password = 'pass';
const credentials = btoa(${username}:${password});
fetch('https://api.example.com/data', {
headers: {
'Authorization': Basic ${credentials}
}
})
.then(response => response.json());
Axios - Cliente HTTP avanzato
const axios = require('axios');
// GET request
const user = await axios.get('https://api.example.com/users/123');
console.log(user.data);
// POST request
const newUser = await axios.post('https://api.example.com/users', {
nome: "Marco",
email: "marco@example.com"
});
// PUT request
const updated = await axios.put('https://api.example.com/users/123', {
nome: "Marco Rossi"
});
// DELETE request
await axios.delete('https://api.example.com/users/123');
Axios instance con configurazione
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${token}
}
});
// Interceptors per logging
api.interceptors.request.use(request => {
console.log('Request:', request.method.toUpperCase(), request.url);
return request;
});
api.interceptors.response.use(
response => {
console.log('Response:', response.status);
return response;
},
error => {
console.error('Error:', error.message);
return Promise.reject(error);
}
);
// Uso
const users = await api.get('/users');
const newUser = await api.post('/users', { nome: "Marco" });
Paginazione
Query parameters
// GET /api/users?page=2&limit=10
async function getUsers(page = 1, limit = 10) {
const url = new URL('https://api.example.com/users');
url.searchParams.append('page', page);
url.searchParams.append('limit', limit);
const response = await fetch(url);
return response.json();
}
// Response
{
"data": [...], // 10 utenti
"pagination": {
"page": 2,
"limit": 10,
"total": 95,
"pages": 10
}
}
Cursor-based
// GET /api/users?cursor=abc123
{
"data": [...],
"pagination": {
"next_cursor": "xyz789",
"has_more": true
}
}
Filtri e ordinamento
// GET /api/users?role=admin&sort=-created_at&filter[active]=true
const url = new URL('https://api.example.com/users');
url.searchParams.append('role', 'admin');
url.searchParams.append('sort', '-created_at');
url.searchParams.append('filter[active]', 'true');
const response = await fetch(url);
const users = await response.json();
Versionamento API
1. URL versioning
https://api.example.com/v1/users
https://api.example.com/v2/users
2. Header versioning
fetch('https://api.example.com/users', {
headers: {
'Accept-Version': 'v2'
}
})
3. Query parameter
https://api.example.com/users?version=2
Rate limiting
Gestione rate limits
async function apiCallWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
// Check rate limit headers
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(Rate limited. Retry after ${retryAfter}s);
await new Promise(resolve => setTimeout(resolve, retryAfter 1000));
continue;
}
if (response.ok) {
return await response.json();
}
throw new Error(HTTP ${response.status});
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 (i + 1)));
}
}
}
Webhook
Ricevere webhook (Express)
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/payment', (req, res) => {
const event = req.body;
console.log('Webhook ricevuto:', event.type);
switch (event.type) {
case 'payment.succeeded':
// Gestisci pagamento riuscito
console.log('Pagamento:', event.data);
break;
case 'payment.failed':
// Gestisci pagamento fallito
console.log('Pagamento fallito:', event.data);
break;
}
// Rispondi 200 per confermare ricezione
res.json({ received: true });
});
app.listen(3000);
Best practices
1. Usa metodi HTTP corretti
// ✅ Corretto
GET /api/users // Ottieni lista
POST /api/users // Crea nuovo
PUT /api/users/123 // Aggiorna completamente
PATCH /api/users/123 // Aggiorna parzialmente
DELETE /api/users/123 // Elimina
// ❌ Da evitare
GET /api/createUser
POST /api/getUsers
2. Usa nomi di risorsa plurali
✅ /api/users
✅ /api/products
✅ /api/orders
❌ /api/user
❌ /api/product
3. Usa nesting per relazioni
GET /api/users/123/orders # Ordini dell'utente
GET /api/users/123/orders/456 # Ordine specifico
POST /api/users/123/orders # Crea ordine per utente
4. Restituisci codici status appropriati
// POST - Creazione riuscita
res.status(201).json({ id: 123, nome: "Marco" });
// PUT - Aggiornamento
res.status(200).json({ id: 123, nome: "Marco Rossi" });
// DELETE - Eliminazione
res.status(204).send(); // No content
// Errore validazione
res.status(422).json({
error: "Validazione fallita",
details: [...]
});
// Non trovato
res.status(404).json({
error: "Risorsa non trovata"
});
5. Fornisci messaggi di errore chiari
// ✅ Errore chiaro
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Dati non validi",
"details": [
{
"field": "email",
"message": "Email non valida"
},
{
"field": "password",
"message": "Password troppo corta (minimo 8 caratteri)"
}
]
}
}
// ❌ Errore vago
{
"error": "Bad request"
}
6. Implementa HATEOAS (opzionale)
{
"id": 123,
"nome": "Marco",
"_links": {
"self": { "href": "/api/users/123" },
"orders": { "href": "/api/users/123/orders" },
"edit": { "href": "/api/users/123", "method": "PUT" },
"delete": { "href": "/api/users/123", "method": "DELETE" }
}
}
Documentazione API
OpenAPI/Swagger
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users:
get:
summary: Lista utenti
responses:
'200':
description: Successo
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
post:
summary: Crea utente
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewUser'
responses:
'201':
description: Creato
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: integer
nome:
type: string
email:
type: string
NewUser:
type: object
required:
- nome
- email
properties:
nome:
type: string
email:
type: string
Testing API
Jest + Supertest
const request = require('supertest');
const app = require('./app');
describe('User API', () => {
test('GET /api/users - Lista utenti', async () => {
const response = await request(app)
.get('/api/users')
.expect('Content-Type', /json/)
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
});
test('POST /api/users - Crea utente', async () => {
const newUser = {
nome: "Marco",
email: "marco@example.com"
};
const response = await request(app)
.post('/api/users')
.send(newUser)
.expect('Content-Type', /json/)
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.nome).toBe('Marco');
});
test('GET /api/users/999 - Utente non trovato', async () => {
await request(app)
.get('/api/users/999')
.expect(404);
});
});
Conclusione
Le API REST con JSON sono essenziali per:
- ✅ Comunicazione frontend-backend
- ✅ Integrazione tra servizi
- ✅ App mobile
- ✅ Microservizi
- ✅ Webhooks
- Usa metodi HTTP corretti
- Restituisci codici status appropriati
- Documenta con OpenAPI
- Implementa autenticazione
- Gestisci errori in modo chiaro
- Versiona l'API
Con queste conoscenze, sei pronto a creare e consumare API REST professionali!
Articoli Correlati
Python e JSON: Guida completa alla manipolazione dati
Impara a lavorare con JSON in Python: parsing, serializzazione, validazione, file I/O e best practices. Include esempi pratici con json, jsonschema e pydantic.
JavaScript e JSON: Guida completa a JSON.parse() e JSON.stringify()
Guida completa su JSON in JavaScript: parsing, serializzazione, gestione errori, localStorage, fetch API e best practices. Include esempi pratici e troubleshooting.
Comprendere JSON Schema: Validazione e documentazione dati
Guida completa a JSON Schema: validazione dati, tipi, vincoli, pattern, esempi pratici e librerie. Impara a validare e documentare API JSON professionalmente.