REST API — základní principy

REST (Representational State Transfer) je architektonický styl pro webová API. Definuje, jak klient (prohlížeč) komunikuje se serverem přes HTTP.

1

Zdroje (Resources)

Vše je zdroj identifikovaný URL: /users, /users/42, /users/42/orders. URL jsou podstatná jména, ne slovesa.

2

HTTP metody jako slovesa

GET = číst, POST = vytvořit, PUT/PATCH = aktualizovat, DELETE = smazat. Metoda říká, co s zdrojem udělat.

3

Bezstavovost (Stateless)

Každý požadavek obsahuje vše potřebné — server si nepamatuje předchozí požadavky. Autentizace = token v každém requestu.

4

JSON jako formát dat

Dnes prakticky vždy JSON. Hlavička Content-Type: application/json informuje server o formátu těla požadavku.

🧪
JSONPlaceholder — naše API: Budeme používat https://jsonplaceholder.typicode.com — bezplatné fake REST API pro testování. Podporuje GET, POST, PUT, PATCH, DELETE (změny se simulují, ale neukládají).
Kapitola 1 / 8 Další: HTTP metody →

HTTP metody & status kódy

MetodaURL příkladAkceTělo requestu
GET/users nebo /users/1Načíst seznam nebo detailŽádné
POST/usersVytvořit nový záznamJSON s daty
PUT/users/1Nahradit celý záznamKompletní JSON
PATCH/users/1Aktualizovat část záznamuJen změněná pole
DELETE/users/1Smazat záznamŽádné

Nejdůležitější HTTP status kódy

KódNázevKdy nastane
200 OKÚspěchGET, PUT, PATCH úspěšný
201 CreatedVytvořenoPOST úspěšně vytvořil záznam
204 No ContentBez obsahuDELETE úspěšný (žádná data zpět)
400 Bad RequestŠpatný požadavekNeplatná data v těle requestu
401 UnauthorizedNeautorizovánChybí nebo neplatný token
403 ForbiddenZakázánoPřístup odepřen (i s tokenem)
404 Not FoundNenalezenoZdroj neexistuje
422 UnprocessableNelze zpracovatValidační chyba na serveru
500 Server ErrorServerová chybaChyba na straně serveru

🧠 Kvíz: Chcete aktualizovat pouze pole email uživatele s ID 5. Jakou HTTP metodu použijete?

Kapitola 2 / 8 Další: Architektura →

Architektura projektu

Než napíšeme první řádek kódu, navrhujeme strukturu. Dobře navržená aplikace je snáze rozšiřitelná a testovatelná.

// Vrstvová architektura pro jednoduchý SPA
//
// UI vrstva (DOM, events, rendering)
//   ↕
// Business logika (validace, transformace dat)
//   ↕
// API vrstva (fetch, error handling, auth)
//   ↕
// REST API (server)

// Struktura souborů (vanilla JS projekt)
src/
  api/
    client.js        // base fetch wrapper
    contacts.js      // contacts CRUD metody
  components/
    ContactCard.js   // karta kontaktu
    ContactForm.js   // formulář pro přidání/editaci
    Toast.js         // notifikace
  utils/
    validate.js      // validační funkce
    format.js        // formátování dat
  app.js             // hlavní logika
index.html

API wrapper — base client

// api/client.js — centrální místo pro všechny API volání
const BASE_URL = 'https://jsonplaceholder.typicode.com';

async function request(endpoint, options = {}) {
  const url = `${BASE_URL}${endpoint}`;
  const config = {
    headers: {
      'Content-Type': 'application/json',
      // 'Authorization': `Bearer ${getToken()}`,
      ...options.headers,
    },
    ...options,
  };

  try {
    const response = await fetch(url, config);
    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new Error(error.message || `HTTP ${response.status}`);
    }
    // 204 No Content nemá tělo
    if (response.status === 204) return null;
    return response.json();
  } catch (error) {
    console.error(`API Error [${options.method || 'GET'} ${endpoint}]:`, error);
    throw error;
  }
}

// Exportované helperové funkce
export const api = {
  get:    (url)          => request(url),
  post:   (url, data)    => request(url, { method: 'POST',   body: JSON.stringify(data) }),
  put:    (url, data)    => request(url, { method: 'PUT',    body: JSON.stringify(data) }),
  patch:  (url, data)    => request(url, { method: 'PATCH',  body: JSON.stringify(data) }),
  delete: (url)          => request(url, { method: 'DELETE' }),
};
Kapitola 3 / 8 Další: CRUD operace →

CRUD operace v praxi

Create, Read, Update, Delete — čtyři základní operace každé datové aplikace. Ukážeme je na příkladu správce příspěvků:

// api/posts.js — CRUD pro příspěvky
const BASE = 'https://jsonplaceholder.typicode.com';

// READ — seznam
export async function getPosts(limit = 10) {
  const res = await fetch(`${BASE}/posts?_limit=${limit}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// READ — detail
export async function getPost(id) {
  const res = await fetch(`${BASE}/posts/${id}`);
  if (!res.ok) throw new Error(res.status === 404 ? 'Nenalezeno' : `HTTP ${res.status}`);
  return res.json();
}

// CREATE
export async function createPost(data) {
  const res = await fetch(`${BASE}/posts`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json(); // vrátí vytvořený objekt s id
}

// UPDATE (kompletní)
export async function updatePost(id, data) {
  const res = await fetch(`${BASE}/posts/${id}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// UPDATE (částečný)
export async function patchPost(id, fields) {
  const res = await fetch(`${BASE}/posts/${id}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(fields),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// DELETE
export async function deletePost(id) {
  const res = await fetch(`${BASE}/posts/${id}`, { method: 'DELETE' });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return true;
}

🧠 Kvíz: REST API vrátí status 201 Created. Co to typicky znamená pro klienta?

Kapitola 4 / 8 Další: Komponenty →

JavaScript komponenty bez frameworku

Frameworky (React, Vue) přinášejí komponentový model — ale základní principy lze implementovat i ve vanilla JS. Komponenta = funkce, která přijme data a vrátí HTML string nebo DOM element.

// Funkcionální komponenta — vrátí HTML string
function PostCard({ id, title, body, onDelete, onEdit }) {
  return `
    <article class="card" data-id="${id}">
      <h3 class="card-title">${escapeHtml(title)}</h3>
      <p class="card-body">${escapeHtml(body.substring(0, 100))}...</p>
      <div class="card-actions">
        <button class="btn-edit" data-id="${id}">✏️ Upravit</button>
        <button class="btn-delete" data-id="${id}">🗑️ Smazat</button>
      </div>
    </article>
  `;
}

// XSS ochrana — VŽDY escapujte user input!
function escapeHtml(str) {
  return String(str)
    .replace(/&/g, '&')
    .replace(//g, '>')
    .replace(/"/g, '"');
}

// Render seznam komponent
function renderPosts(posts, container) {
  container.innerHTML = posts.map(post => PostCard(post)).join('');
}

// Toast notifikace jako komponenta
function showToast(message, type = 'success') {
  const toast = document.createElement('div');
  toast.className = `toast toast-${type}`;
  toast.textContent = message;
  document.body.appendChild(toast);
  requestAnimationFrame(() => toast.classList.add('visible'));
  setTimeout(() => {
    toast.classList.remove('visible');
    setTimeout(() => toast.remove(), 300);
  }, 3000);
}
Živý editor — komponenty a event delegace

Kompletní CRUD aplikace

Spojíme vše dohromady — správce příspěvků s načítáním, přidáváním, editací a mazáním. Volá skutečné JSONPlaceholder API.

Kompletní CRUD správce příspěvků (živé API)