Vad är REST?
REST (Representational State Transfer) är en arkitekturstil för att bygga webbtjänster som använder HTTP på ett konsekvent sätt. Ett REST API använder oftast HTTP-förfrågningar för att skapa, läsa, ändra och radera data.
REST är inte ett strikt, formellt protokoll. Det är snarare en samling principer som gör att ett API känns mer konsekvent, lättare att förstå och enklare att underhålla.
Principerna bakom REST
1. Client-Server Architecture
Klient och server är åtskilda, vilket gör att båda kan utvecklas oberoende av varandra.
2. Stateless
Varje förfrågan från klient till server måste innehålla all information som behövs. Servern lagrar inget tillstånd (state) om klienten.
3. Cacheable
Svaret måste ange om datan kan cachas för att förbättra prestandan.
4. Uniform Interface
Ett konsekvent gränssnitt mellan klient och server, som omfattar:
- Resursidentifiering via URI
- Manipulation via representationer
- Självbeskrivande meddelanden
- HATEOAS (Hypermedia as the Engine of Application State)
5. Layered System
Arkitekturen kan byggas upp av flera lager (säkerhet, lastbalansering, cachning).
6. Code on Demand (valfritt)
Servern kan skicka körbar kod till klienten (till exempel JavaScript).
HTTP-metoder inom REST
REST använder standardiserade HTTP-metoder för operationer:
GET - Läsa data
// Hämta alla users
GET /api/users
// Hämta en specifik user
GET /api/users/123
POST - Skapa ny data
POST /api/users
Content-Type: application/json
{
"name": "Budi Santoso",
"email": "budi@example.com"
}
PUT - Uppdatera data (ersätt)
PUT /api/users/123
Content-Type: application/json
{
"name": "Budi Santoso Updated",
"email": "budi.new@example.com"
}
PATCH - Uppdatera data delvis
PATCH /api/users/123
Content-Type: application/json
{
"email": "budi.new@example.com"
}
DELETE - Radera data
DELETE /api/users/123
HTTP-statuskoder
Ett REST API använder HTTP-statuskoder för att visa resultatet av en förfrågan:
2xx - Success
200 OK- Förfrågan lyckades201 Created- En ny resurs skapades204 No Content- Förfrågan lyckades, men inget innehåll skickas tillbaka
3xx - Redirection
301 Moved Permanently- Resursen har flyttats permanent304 Not Modified- Resursen är oförändrad (cachen är fortfarande giltig)
4xx - Client Errors
400 Bad Request- Förfrågan är ogiltig401 Unauthorized- Autentisering krävs403 Forbidden- Autentiserad, men saknar behörighet404 Not Found- Resursen hittades inte422 Unprocessable Entity- Valideringsfel
5xx - Server Errors
500 Internal Server Error- Fel på servern502 Bad Gateway- Ogiltigt svar från en uppströmsserver503 Service Unavailable- Servern är tillfälligt nere
Komplett exempel på ett REST API
Resurs: Products
// GET /api/products - Lista alla products
Response: 200 OK
[
{
"id": 1,
"name": "Laptop ASUS",
"price": 8500000,
"stock": 15
},
{
"id": 2,
"name": "Mouse Logitech",
"price": 250000,
"stock": 50
}
]
// GET /api/products/1 - Detaljer för en product
Response: 200 OK
{
"id": 1,
"name": "Laptop ASUS",
"price": 8500000,
"stock": 15,
"description": "Gaminglaptop med kraftfulla specifikationer",
"created_at": "2024-01-01T10:00:00Z"
}
// POST /api/products - Skapa en ny product
Request Body:
{
"name": "Keyboard Mechanical",
"price": 750000,
"stock": 30
}
Response: 201 Created
{
"id": 3,
"name": "Keyboard Mechanical",
"price": 750000,
"stock": 30,
"created_at": "2024-01-15T14:30:00Z"
}
// PUT /api/products/1 - Uppdatera en product
Request Body:
{
"name": "Laptop ASUS ROG",
"price": 9000000,
"stock": 12
}
Response: 200 OK
{
"id": 1,
"name": "Laptop ASUS ROG",
"price": 9000000,
"stock": 12,
"updated_at": "2024-01-15T15:00:00Z"
}
// DELETE /api/products/1 - Radera en product
Response: 204 No Content
Best practice för REST API
1. Använd substantiv, inte verb
Mindre lyckat:
GET /getUsers
POST /createUser
PUT /updateUser
DELETE /deleteUser
Bättre:
GET /users
POST /users
PUT /users/123
DELETE /users/123
2. Använd plural för collections
Bättre:
GET /users
GET /products
GET /orders
3. Nästlade resurser för relationer
// Orders som tillhör en specifik user
GET /users/123/orders
// Comments som tillhör ett specifikt post
GET /posts/456/comments
// En specifik comment
GET /posts/456/comments/789
4. Filtrering, sortering och paginering
// Filtrering
GET /products?category=laptop&price_min=5000000
// Sortering
GET /products?sort=price&order=desc
// Paginering
GET /products?page=2&limit=20
// Kombination
GET /products?category=laptop&sort=price&order=asc&page=1&limit=10
5. Versionshantering
// URL-versionering (vanligast)
GET /api/v1/users
GET /api/v2/users
// Header-versionering
GET /api/users
Headers: Accept: application/vnd.api.v1+json
// Query-parameter
GET /api/users?version=1
6. Konsekventa felsvar
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Data som skickades är ogiltig",
"details": [
{
"field": "email",
"message": "Ogiltigt e-postformat"
},
{
"field": "password",
"message": "Lösenordet måste vara minst 8 tecken"
}
]
}
}
Implementera ett REST API
Node.js med Express
const express = require('express');
const app = express();
app.use(express.json());
// GET all users
app.get('/api/users', async (req, res) => {
const users = await db.users.findAll();
res.json(users);
});
// GET user by ID
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// POST create user
app.post('/api/users', async (req, res) => {
const { name, email } = req.body;
const user = await db.users.create({ name, email });
res.status(201).json(user);
});
// PUT update user
app.put('/api/users/:id', async (req, res) => {
const user = await db.users.update(req.params.id, req.body);
res.json(user);
});
// DELETE user
app.delete('/api/users/:id', async (req, res) => {
await db.users.delete(req.params.id);
res.status(204).send();
});
app.listen(3000);
Ruby on Rails
class Api::UsersController < ApplicationController
# GET /api/users
def index
@users = User.all
render json: @users
end
# GET /api/users/:id
def show
@user = User.find(params[:id])
render json: @user
end
# POST /api/users
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created
else
render json: @user.errors, status: :unprocessable_entity
end
end
# PUT /api/users/:id
def update
@user = User.find(params[:id])
if @user.update(user_params)
render json: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
# DELETE /api/users/:id
def destroy
@user = User.find(params[:id])
@user.destroy
head :no_content
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
Autentisering i ett REST API
1. API Keys
GET /api/users
Headers:
X-API-Key: your_api_key_here
2. Bearer Token (JWT)
POST /api/login
{
"email": "user@example.com",
"password": "password123"
}
Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
// Efterföljande förfrågningar
GET /api/users
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
3. OAuth 2.0
För autentisering via tredje part (Google, Facebook, GitHub).
REST jämfört med GraphQL
| Aspekt | REST | GraphQL | |-------|------|---------| | Endpoints | Många endpoints | En enda endpoint | | Datahämtning | Over-fetching eller under-fetching kan förekomma | Klienten kan välja exakt vilken data som behövs | | Inlärningskurva | Lättare att lära sig | Mer komplext | | Cachning | Mer direkt stöd för HTTP-cachning | Kräver oftast ett särskilt tillvägagångssätt | | Mognadsgrad | Använts i stor skala under lång tid | Relativt nyare och fortfarande under utveckling |
Verktyg för att testa ett REST API
1. Postman
Ett GUI-verktyg som ofta används för att testa API:er.
2. cURL
Kommandoradsverktyg för HTTP-förfrågningar.
curl -X GET https://api.example.com/users
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"Budi","email":"budi@example.com"}'
3. HTTPie
En användarvänlig kommandoradsklient för HTTP.
http GET https://api.example.com/users
http POST https://api.example.com/users name=Budi email=budi@example.com
4. Insomnia
Ett alternativt GUI-verktyg, likt Postman.
Vanliga misstag i REST API
- Använda verb i URL:en -
/getUseristället för/users - Inkonsekventa statuskoder - Att returnera 200 för alla svar
- Bristfällig felhantering - Otydliga felmeddelanden
- Exponera intern struktur - URL:en avslöjar databasstrukturen
- Ingen rate limiting - API:et kan missbrukas
- Ingen versionshantering - Breaking changes utan bakåtkompatibilitet
Tips för utvecklare
- Design first - Planera API-strukturen innan du börjar koda
- Dokumentera allt - Använd Swagger/OpenAPI för dokumentation
- Testa noggrant - Skriv integrationstester för API-endpoints
- Övervaka prestanda - Följ svarstider och felfrekvens
- Säkerhet först - Validera alltid indata, använd HTTPS, implementera autentisering
- Följ standarder - Använd HTTP-metoder och statuskoder på rätt sätt
Sammanfattning
REST är fortfarande ett mycket vanligt sätt att bygga API:er, särskilt i webbapplikationer. Genom att förstå grundprinciperna kan du designa tydligare endpoints, mer konsekventa svar och integrationer som är enklare för andra team att använda.
Om du håller på att lära dig backend är REST ett bra ställe att börja. Bygg ett enkelt API först, förstå hur HTTP-metoder och statuskoder används, och lägg sedan gradvis till funktioner som autentisering, paginering, filtrering och versionshantering.