Skip to content

21 • RESTful

AJAX, REST, JSON, XML, chybové a návratové kódy, vracení dat, Web API, význam metod

😡

Je to RESTful (REST + ful) jako playful (play + ful) - ne RESTfull, jak píše Kazda pořád dokola!!

Co je API

API (Application Programming Interface) je rozhraní, přes které spolu komunikují aplikace nebo její části. Definuje, jaké operace lze provést a jak, ale skrývá interní implementaci.

Typy API

TypKde se používáPříklad
Webové APIKomunikace přes HTTPREST, GraphQL, gRPC
Knihovní APIV rámci programuDOM API, fs (Node.js), React API
Operační systémAplikace ↔ OSPOSIX, Win32
GrafickéGPU akceleraceOpenGL, Vulkan, DirectX, WebGL
HardwarovéKomunikace s HWI2C, SPI, USB

V kontextu webu se "API" typicky myslí HTTP API vystavené serverem pro klienty (web, mobil, partneři).


REST: architektonický styl

REST (Representational State Transfer) je architektonický styl pro tvorbu distribuovaných systémů, popsaný Royem Fieldingem v jeho disertaci v roce 2000. Není to standard, je to soubor principů.

💡

REST vs RESTful: REST je striktní architektura podle Fieldinga. "RESTful" se v praxi používá jako volnější označení pro API, které dodržuje hlavní principy. Většina "REST API" v praxi je vlastně RESTful, ne čisté REST.

6 architektonických omezení (constraints) REST

  1. Client-Server (oddělení zájmů): klient se stará o UI, server o data a logiku. Mohou se vyvíjet nezávisle.
  2. Stateless (bezstavový): každý request obsahuje vše potřebné pro zpracování. Server si nepamatuje předchozí requesty od daného klienta.
  3. Cacheable (cachovatelný): odpovědi musí být explicitně označené jako cachovatelné nebo ne (přes hlavičky Cache-Control, ETag).
  4. Uniform Interface (jednotné rozhraní): konzistentní princip identifikace zdrojů (URI), manipulace přes reprezentace (JSON, XML), self-descriptive messages.
  5. Layered System (vrstvená architektura): klient neví, jestli mluví přímo se serverem nebo přes proxy/load balancer/CDN.
  6. Code on Demand (volitelné): server může poslat klientovi kód k provedení (např. JavaScript). Jediné nepovinné omezení.

Richardson Maturity Model

jak moc jsou dodržovány REST principy:

LevelPrincipTypický příklad
Level 0Jedno URL, jedna metoda (typicky POST)SOAP, RPC
Level 1Více URL pro různé zdroje/users, /products
Level 2Použití HTTP metod (GET/POST/PUT/DELETE)"Klasické" REST API
Level 3HATEOAS (hypermedia)Odkazy v odpovědích na další akce

Většina dnešních "REST API" je na Level 2. Level 3 (HATEOAS) je v praxi vzácný.

HATEOAS

Hypermedia As The Engine Of Application State: API odpovědi obsahují odkazy na další možné akce, takže klient nepotřebuje znát strukturu URL předem.

json
{
  "id": 42,
  "name": "Axo",
  "_links": {
    "self": { "href": "/users/42" },
    "posts": { "href": "/users/42/posts" },
    "edit": { "href": "/users/42", "method": "PUT" }
  }
}

Plus: API je samodokumentující. Mínus: implementačně náročnější, klienti to typicky nevyužívají.


Klasická vs asynchronní komunikace

Klasická (server-rendered)Asynchronní (AJAX)
Kdy se posílá requestPři změně stránkyKdykoli, na pozadí
Co server vracíCelé HTMLJSON s daty
Reload stránkyAno, při každé akciNe
Latence vnímaná uživatelemVyššíNižší (částečný update)
PříkladTradiční PHP web, WikipediaGmail, Google Maps, Figma

AJAX: Asynchronous JavaScript and XML

AJAX je technika pro komunikaci se serverem bez nutnosti reloadu stránky. Pojem se vžil v roce 2005 (Jesse James Garrett) po prvních AJAX-heavy aplikacích od Googlu (Gmail 2004, Google Maps 2005). Tyto aplikace ukázaly, že web umí konkurovat desktopu.

Drobnost: "XML" v názvu je dnes anachronismus. AJAX se v 95+ % případů používá s JSON, ne XML. Pojem ale zůstal.

Princip

image.png

Typické use cases

  • Našeptávač ve search baru
  • Chat (nové zprávy se objevují)
  • Dynamický scroll (lazy load, infinite scroll)
  • Validace formulářů "za běhu"
  • Lajk tlačítko, koš v e-shopu
  • Notifikace, real-time dashboardy

Implementace: tři generace

1. XMLHttpRequest (XHR) - klasika z 2000

Stará API, pořád funguje. Sleduje progress, ale syntakticky nešikovná (callbacks).

jsx
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/users');
xhr.onload = () => console.log(xhr.response);
xhr.onerror = () => console.error('Error');
xhr.send();

Fetch API - moderní default (od 2015)

Vrací Promise. Cleaner syntaxe.

jsx
// GET
const response = await fetch('/api/users');
const data = await response.json();

// POST s tělem
const response = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'axo', age: 18 })
});

if (response.ok) {
  const newUser = await response.json();
}

Chyták s Fetch: fetch neodmítne Promise při HTTP 4xx/5xx odpovědi (na rozdíl od axios). Promise se rejectne jen při síťové chybě (DNS, no connection). Pro HTTP chyby musíš kontrolovat response.ok sám.

Axios, ky, ofetch - knihovny

Knihovny postavené nad fetch/XHR s lepší ergonomií.

jsx
// Axios
const { data } = await axios.get('/api/users');
await axios.post('/api/users', { name: 'Axo' });

// Auto-throw na 4xx/5xx
try {
  const { data } = await axios.get('/api/users/999');
} catch (error) {
  if (error.response?.status === 404) { /* ... */ }
}

Promises a async/await

Promise reprezentuje asynchronní operaci se třemi stavy:

StavVýznamCo s tím
PendingOperace probíháČekat
FulfilledÚspěch, vyřešeno.then() nebo await
RejectedSelhání.catch() nebo try/catch

Promise patterns

jsx
// Sekvenční (jeden po druhém)
const user = await fetchUser();
const posts = await fetchPosts(user.id);

// Paralelní (oba najednou, čekáme na oba)
const [user, posts] = await Promise.all([
  fetchUser(),
  fetchPosts()
]);

// Paralelní, vrátit nejrychlejší
const fastest = await Promise.race([
  fetch('/api/v1/data'),
  fetch('/api/v2/data')
]);

// Paralelní, čekáme na všechny i s chybami
const results = await Promise.allSettled([
  fetchUser(),
  fetchPosts(),
  fetchComments()
]);
// results: [{status: 'fulfilled', value: ...}, {status: 'rejected', reason: ...}, ...]

HTTP metody a jejich význam

MetodaCRUDCo děláTělo?Bezpečná?Idempotentní?
GETReadZískat zdrojNeAnoAno
POSTCreateVytvořit novýAnoNeNe
PUTUpdateNahradit celýAnoNeAno
PATCHUpdateUpravit částAnoNeNe (obecně)
DELETEDeleteSmazatVolitelněNeAno
HEAD-Jen hlavičky (jako GET)NeAnoAno
OPTIONS-Dostupné metody (CORS)NeAnoAno

Bezpečná (safe) metoda

Metoda, která nemění stav serveru. Můžeš ji volat libovolněkrát bez konzekvencí.

  • GET, HEAD, OPTIONS = bezpečné
  • Vše ostatní mění stav

Důležitý důsledek: crawlery, prefetchery a "preview" tlačítka prohlížeče volají GET. Pokud tvoje GET endpoint něco smaže nebo upraví (anti-pattern), bude se to dít náhodně. Klasická chyba: /users/delete?id=5 jako GET.

Idempotentní metoda

Metoda, jejíž opakované volání má stejný efekt jako jednotlivé.

  • GET (nemění nic = stejné)
  • PUT (nahradí celé = výsledek stejný i při opakování)
  • DELETE (smazaný uživatel zůstane smazaný)
  • POST (vytvoří nový záznam pokaždé = neidempotentní)
  • PATCH (obecně neidempotentní, závisí na operaci)

Praktický význam: pokud klient nezná, jestli první request dorazil (timeout), idempotentní metody může bezpečně opakovat. Pro POST se používají idempotency keys: klient vygeneruje UUID a pošle ho v hlavičce, server pak odmítne duplicitní vytvoření se stejným key.

html
POST /api/orders
Idempotency-Key: 7f9c2a3b-1234-5678-90ab-cdef12345678

POST vs PUT vs PATCH (klasická matoucí trojka)

bash
# POST: vytvoř nový (server přidělí ID)
POST /api/users
{ "name": "Axo", "email": "..." }
 201 Created, Location: /api/users/42

# PUT: nahraď celý objekt (všechny fieldy)
PUT /api/users/42
{ "name": "Axo", "email": "...", "role": "admin" }
 200 OK

# PATCH: změň jen tyto fieldy
PATCH /api/users/42
{ "role": "admin" }
 200 OK (ostatní fieldy zůstanou nezměněné)

URL design pro REST API

PrincipPříklad
Použij podstatná jména, ne slovesa/users ne /getUsers
Plurály pro kolekce/users, /products
Jednotné pojmenováníBuď /users nebo /user, ne mix
Vnořené zdroje/users/42/posts (posty uživatele 42)
Hierarchie přes lomítka/categories/15/products/3
Akce přes podzdroje, ne slovesa/users/42/follow (POST) místo /followUser?id=42
Filtry, řazení v query/posts?author=42&sort=date&order=desc

Příklady kompletního CRUD endpointu

bash
GET    /api/users              seznam (s paginací, filtrováním)
GET    /api/users/42           detail jednoho
POST   /api/users              vytvoř nového
PUT    /api/users/42           nahraď celého
PATCH  /api/users/42           uprav část
DELETE /api/users/42           smaž

GET    /api/users/42/posts     posty uživatele (vnořený zdroj)
POST   /api/users/42/follow    custom akce (jako podzdroj)

Vracení dat: stránkování, filtrování, řazení

Vrátit 1000 záznamů najednou je špatně: pomalé, paměťově náročné, většinou zbytečné.

Stránkování (pagination)

Offset-based (klasické)

json
GET /api/posts?page=2&limit=20

Vrátí 20 záznamů od pozice druhá stránka)

+ Plus: jednoduché, intuitivní.

  • Mínus: nestabilní (pokud někdo přidá záznam mezi stránkami, posune se ti vše).

Cursor-based (moderní pro velké datasety)

bash
GET /api/posts?cursor=eyJpZCI6MTAwfQ&limit=20

Klient pošle "kurzor" (typicky ID nebo timestamp posledního záznamu z předchozí stránky). Server vrátí dalších 20 od kurzoru.

Plus: stabilní i při dynamických změnách. Mínus: nelze skočit na "stránku 5".

Použití: Twitter feed, Instagram, Reddit, infinite scroll.

Pagination v odpovědi

json
{
  "data": [...],
  "meta": {
    "page": 2,
    "limit": 20,
    "total": 247,
    "totalPages": 13
  },
  "links": {
    "self": "/api/posts?page=2",
    "next": "/api/posts?page=3",
    "prev": "/api/posts?page=1",
    "first": "/api/posts?page=1",
    "last": "/api/posts?page=13"
  }
}

Filtrování

bash
/api/posts?author=42
/api/posts?status=published&category=tech
/api/products?price_min=100&price_max=500
/api/users?created_after=2026-01-01

Řazení

bash
/api/posts?sort=date              # vzestupně
/api/posts?sort=-date             # sestupně (mínus prefix)
/api/posts?sort=date,-views       # více sloupců

Výběr polí (sparse fieldsets)

Klient si může říct, která pole chce vrátit:

bash
/api/users?fields=id,name,email

Snižuje velikost odpovědi a zrychluje response time. Tohle GraphQL řeší elegantněji nativně.

Expand / include vztažených dat

bash
/api/posts?include=author,comments

Místo dvou requestů (jeden na post, druhý na autora) vrátí všechno najednou. Anti-pattern: vždy includovat všechno (přemíra dat).

API versioning

API se časem vyvíjí. Breaking changes (rušení polí, změny formátů) musí být verzované, aby staré klienty nepřestaly fungovat.

URL versioning (nejběžnější)

bash
/api/v1/users
/api/v2/users

Plus: jasně vidět ve URL, snadné cachování. Mínus: porušuje REST princip ("zdroj má jedno URI").

Většina velkých API (Stripe, GitHub, Twitter, Slack) používá právě URL versioning pro pragmatičnost.

Header versioning

bash
GET /api/users
Accept: application/vnd.example.v1+json

Plus: "čistší" URL. Mínus: hůř se debugguje, klient na to musí myslet.

Query parameter

bash
/api/users?version=1

Plus: jednoduché. Mínus: zase porušuje REST.

Formáty dat

JSON: dnešní standard

json
{
  "name": "Radomír Mendřický",
  "age": 20,
  "isStudent": true,
  "isSuspicious": true,
  "address": {
    "street": "Hanychovská 67",
    "city": "Liberec"
  },
  "hobbies": ["coding", "stamina", "making out with women"]
}

Plus:

  • Lehký, čitelný
  • Nativní pro JavaScript (JSON.parse, JSON.stringify)
  • Široká podpora ve všech jazycích
  • Menší než XML

Mínus:

  • Žádné typy (datum je string, čísla limitované IEEE 754)
  • Žádné komenty
  • Žádné schema by default (ale existuje JSON Schema)

XML

xml
<Person id="67">
  <Name>Reiser</Name>
  <Age>19</Age>
  <Address>
    <Street>Švermovka</Street>
    <City>Liberec</City>
  </Address>
</Person>
<!-- comment jako v html -->

Plus:

  • Validace přes XSD/DTD schémata
  • Atributy (<book id="1">)
  • Mature ekosystém (XPath, XSLT)

Mínus:

  • Verbózní (víc dat než JSON)
  • Náročnější parsing
  • Už není cool

Kde se ještě používá: SOAP API, RSS feedy, sitemap.xml, SVG, Office dokumenty (DOCX, XLSX), Java enterprise (pom.xml)

YAML

yaml
name: axo4xo
age: 18
hasMaturita: false
address:
  city: Liberec
hobbies:
  - coding
  - music
  - gaming
# komentář

Plus:

  • Nejlepší čitelnost
  • Komenty (#)
  • Méně syntaktického šumu

Mínus:

  • Whitespace je významný (chybný odsazení = chyba)
  • Pomalejší parsing
  • "Norway problem": NO se parsuje jako boolean false (YAML 1.1)

Použití: Docker Compose, GitHub Actions, Kubernetes, ESPHome

Srovnání

JSONXMLYAML
ČitelnostDobráHoršíNejlepší
VelikostMaláVelkáMalá
ValidaceJSON SchemaDTD/XSDOmezená
KomentyNeAnoAno
Pro APIStandardLegacyNepoužívá se
Pro configObčasObčasStandard

Binární alternativy

Pro vysoce výkonné komunikace (mikroslužby, IoT) se používají binární formáty:

FormátPoužití
Protocol Buffers (Protobuf)gRPC, Google ekosystém
MessagePack"Binární JSON", menší a rychlejší
CBORIoT (RFC 8949)
Apache AvroBig data, Kafka
FlatBuffersHry, real-time aplikace

Tyto formáty nejsou lidsky čitelné, ale jsou výrazně menší a rychleji se parsují.

10 • HTTP stavové kódy pro REST

SkupinaVýznam
1xxInformační
2xxÚspěch
3xxPřesměrování
4xxChyba klienta
5xxChyba serveru

Klíčové kódy pro REST API

KódProč
200 OKGET/PUT/PATCH úspěšný s daty v odpovědi
201 CreatedPOST: záznam vytvořen, Location header s novou URL
202 AcceptedRequest přijat, ale ještě se asynchronně zpracovává
204 No ContentÚspěch, ale žádná data (typicky DELETE)
304 Not ModifiedCache je stále platná (s ETag/If-None-Match)
400 Bad RequestŠpatný formát, chybějící parametry
401 UnauthorizedNení přihlášen (nesprávný/žádný token)
403 ForbiddenPřihlášen, ale nemá oprávnění
404 Not FoundZdroj neexistuje
405 Method Not AllowedTato metoda na tomto URL není povolená
409 ConflictKonflikt (duplicitní e-mail, edit race condition)
410 GoneZdroj definitivně zmizel
422 Unprocessable EntitySyntakticky OK, ale validace selhala
429 Too Many RequestsRate limiting, klient posílá moc
500 Internal Server ErrorNěco se rozbilo na serveru
502 Bad GatewayUpstream server neodpověděl správně
503 Service UnavailableServer dočasně nedostupný
504 Gateway TimeoutUpstream timeout

11 • Standardizovaný error response (Problem Details)

RFC 9457 (Problem Details for HTTP APIs) definuje standardní strukturu chybové odpovědi:

json
{
  "type": "https://example.com/errors/invalid-email",
  "title": "Neplatný e-mail",
  "status": 422,
  "detail": "E-mail 'foo@' nesplňuje formát.",
  "instance": "/users/create",
  "field": "email"
}

Content-Type: application/problem+json

Klient ví, jak chybu zpracovat: type jako strojový identifikátor, title pro uživatele, detail pro debug.

Klasický error response (bez RFC)

json
{
  "error": "InvalidInput",
  "message": "E-mail je povinný",
  "field": "email"
}

Většina API si dělá vlastní formát, ale konzistence napříč endpointy je klíčová.

Ošetření chyb na klientovi

jsx
async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);

    if (!response.ok) {
      // Fetch nevyhodí pro 4xx/5xx automaticky
      const error = await response.json().catch(() => null);
      throw new ApiError(response.status, error?.message);
    }

    return await response.json();
  } catch (error) {
    if (error instanceof TypeError) {
      // Síťová chyba (no connection, DNS fail)
      console.error('Network error', error);
    }
    throw error;
  }
}

// Použití
try {
  const user = await fetchUser(42);
} catch (error) {
  if (error.status === 404) {
    showMessage('Uživatel neexistuje');
  } else if (error.status === 401) {
    redirectToLogin();
  } else {
    showMessage('Něco se pokazilo');
  }
}

Retry logika

Pro idempotentní operace lze opakovat při dočasné chybě:

jsx
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) return response;
      if (response.status < 500) return response; // klient error, nemá smysl opakovat
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
    await new Promise(r => setTimeout(r, 2 ** i * 1000)); // exponential backoff
  }
}

Bezpečnost REST API

PrincipDetail
HTTPS onlyŠifrování v přenosu, ověření identity serveru
AutentizaceJWT v Authorization: Bearer <token> headeru
AutorizaceRole-based access (RBAC), kontrolovat každý endpoint
Rate limitingLimit requestů na IP/uživatele za čas
CORSOmezit, kdo smí volat z prohlížeče
Input validaceVždy validovat na serveru, klient může lhát
No secrets in URLHesla, tokeny patří do hlaviček nebo těla
CSRF protekcePro session-based auth, SameSite cookies
API klíčePro server-to-server, v X-API-Key headeru
bash
GET /api/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ...
X-API-Key: abc123def456

Rate limiting hlavičky

Server typicky vrací informace o limitech:

bash
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1717996400

# Při překročení:
HTTP/1.1 429 Too Many Requests
Retry-After: 60

Dokumentace API: OpenAPI / Swagger

OpenAPI (Swagger) je standardní formát pro strojově čitelnou dokumentaci REST API. Píšeš YAML nebo JSON, který popisuje endpointy, parametry, response schémata. Z toho se generuje:

  • Interaktivní dokumentace (Swagger UI)
  • Klientské SDK pro různé jazyky
  • Test framework
  • Mock server
yaml
openapi: 3.0.0
info:
  title: Moje API
  version: 1.0.0
paths:
  /users/{id}:
    get:
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Uživatel
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: Neexistuje

Alternativy k REST

GraphQL

graphql
query {
  user(id: 42) {
    name
    email
    posts(limit: 5) {
      title
      comments {
        text
      }
    }
  }
}
RESTGraphQL
EndpointMnoho (/users, /posts)Jeden (/graphql)
HTTP metodyGET/POST/PUT/DELETEVždy POST
DataServer určuje, co vrátíKlient si vybere fieldy
Over-fetchingČastéVyřešeno
Under-fetchingN+1 requestyVyřešeno (nested queries)
CacheHTTP cache snadnáKomplikovanější
File uploadNativníWorkaround (multipart, base64)
VerzováníČasté breaking changesDeprecate fieldů, schema evoluce
DokumentaceOpenAPI/SwaggerAutomatická (introspekce)

Použití: Facebook, GitHub, Shopify, Twitter. Vhodné pro komplexní UI s mnoha vztahy.

gRPC

RESTgRPC
ProtokolHTTP/1.1 nebo /2HTTP/2
FormátJSON (text)Protobuf (binární)
SchémaOpenAPI (volitelné).proto soubor (povinné)
Generování klientůOpenAPI generátoryNativní
StreamingSSE, WebSocketServer, client, bidirectional
Lidská čitelnostAno (curl funguje)Ne
PoužitíVeřejné API, webMikroslužby, mobile-backend

Použití: Google interní, Netflix, Uber.

tRPC

TypeScript-only "RPC over HTTP" pro end-to-end type safety mezi backend a frontend. Pokud máš oba v TS (typicky Next.js full-stack), můžeš mít sdílené typy bez OpenAPI ceremonií.

WebSocket / SSE

Pro real-time data (chat, live notifikace, sportovní výsledky):

  • WebSocket: trvalé obousměrné spojení
  • Server-Sent Events (SSE): trvalý stream serveru ke klientovi, jednosměrný

⚠️

NENÍ NÁHRADA (jinej purpose)! Spíš doplněk.

Tipy pro ústní zkoušku

Jak začít

"REST je architektonický styl pro Web API, navržený Royem Fieldingem v roce 2000. Postaven nad HTTP, používá URL pro identifikaci zdrojů a HTTP metody pro operace (GET, POST, PUT, PATCH, DELETE). Data se typicky vyměňují v JSON. AJAX je klientská technika pro asynchronní komunikaci s API bez reloadu stránky."

Co komise typicky chce slyšet

  • HTTP metody mapované na CRUD (GET/POST/PUT/PATCH/DELETE).
  • Idempotence a bezpečnost metod (GET bezpečná, POST ne).
  • JSON je standard, XML legacy.
  • Stavové kódy alespoň 200/201/204, 400/401/403/404, 500.
  • Stateless princip a jak se řeší stav (token v hlavičce).
  • AJAX a Fetch API, Promise stavy.

Doplňky, které komisi potěší

  • 6 architektonických omezení REST (Fielding), ne jen 4.
  • Richardson Maturity Model a kde dnešní API typicky jsou (Level 2).
  • Stránkování (cursor-based) pro velké datasety.
  • Idempotency keys pro retry-safe POST.
  • PATCH NENÍ obecně idempotentní podle RFC 5789.
  • OpenAPI/Swagger pro dokumentaci.
  • GraphQL jako alternativa s konkrétními výhodami (over-fetching).

Časté chytáky

OtázkaOdpověď
Rozdíl PUT a PATCH?PUT nahradí celý objekt, PATCH jen poslané fieldy. PUT je idempotentní, PATCH obvykle ne.
Co znamená stateless v REST?Server si nepamatuje předchozí requesty. Každý request musí obsahovat vše potřebné (typicky token v hlavičce).
Proč POST není idempotentní?Každé volání vytvoří nový záznam. Volání 3× = 3 nové záznamy.
Co dělá fetch, když dostane 500?Promise se nerejectuje, vrátí response s ok: false. Musíš kontrolovat sám. (Axios na rozdíl vyhodí.)
401 vs 403?401 = nepřihlášen, 403 = přihlášen ale nesmí.
Co je AJAX dnes?Termín z 2005 pro async komunikaci bez reloadu. Dnes se používá s JSON přes Fetch API.
Proč nepoužít GET na smazání?GET je bezpečná = nemění stav. Crawlery/prefetchery ji volají automaticky, smazalo by ti to data.