MedelProgrammeringREST

REST (Representational State Transfer)

Representational State Transfer

En mjukvaruarkitektur för att bygga webbtjänster som använder standardiserade HTTP-metoder för CRUD-operationer på resurser.

#api#webb#http#backend#restful#web-service

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 lyckades
  • 201 Created - En ny resurs skapades
  • 204 No Content - Förfrågan lyckades, men inget innehåll skickas tillbaka

3xx - Redirection

  • 301 Moved Permanently - Resursen har flyttats permanent
  • 304 Not Modified - Resursen är oförändrad (cachen är fortfarande giltig)

4xx - Client Errors

  • 400 Bad Request - Förfrågan är ogiltig
  • 401 Unauthorized - Autentisering krävs
  • 403 Forbidden - Autentiserad, men saknar behörighet
  • 404 Not Found - Resursen hittades inte
  • 422 Unprocessable Entity - Valideringsfel

5xx - Server Errors

  • 500 Internal Server Error - Fel på servern
  • 502 Bad Gateway - Ogiltigt svar från en uppströmsserver
  • 503 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

  1. Använda verb i URL:en - /getUser istället för /users
  2. Inkonsekventa statuskoder - Att returnera 200 för alla svar
  3. Bristfällig felhantering - Otydliga felmeddelanden
  4. Exponera intern struktur - URL:en avslöjar databasstrukturen
  5. Ingen rate limiting - API:et kan missbrukas
  6. Ingen versionshantering - Breaking changes utan bakåtkompatibilitet

Tips för utvecklare

  1. Design first - Planera API-strukturen innan du börjar koda
  2. Dokumentera allt - Använd Swagger/OpenAPI för dokumentation
  3. Testa noggrant - Skriv integrationstester för API-endpoints
  4. Övervaka prestanda - Följ svarstider och felfrekvens
  5. Säkerhet först - Validera alltid indata, använd HTTPS, implementera autentisering
  6. 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.

Relaterade termer

Kom igång

Redo att bygga med smbCloud?

Distribuera Node.js, Swift och Ruby med ett enda kommando.

Kom igång med smbCloud →

Senast uppdaterad: 15 januari 2024