W zeszły weekend potrzebowałem publicznego endpointu do odbierania zgłoszeń z formularza na landing page'u. Nic wymyślnego — przyjąć POST z JSON-em, zwalidować kilka pól, zwrócić sensowną odpowiedź. Całość obsłużyłaby może 50 requestów tygodniowo. Nie chciałem wbijać karty kredytowej do serwera za 20 dolarów miesięcznie, uczyć się nowego narzędzia infra ani siedzieć przy pipelinie CI za każdym razem, kiedy zmieniam trzy linijki. Dziesięć minut po tym jak zacząłem, API było żywe w 300+ miastach i nie kosztowało mnie ani grosza. Oto cały spacer.

Cloudflare Workers ma darmowy tier, który jest naprawdę hojny: 100 000 requestów dziennie, brak karty kredytowej przy rejestracji, a twój kod biegnie na krawędzi zamiast w jednym regionie. Dla małych API, których potrzebuje większość side-projectów — odbiorników webhooków, handlerów formularzy, skracaczy linków, proxy JSON — możesz wypuścić i zapomnieć. Ten przewodnik prowadzi cię od "brak konta na Cloudflare" do "żywy URL odpowiada na curl" w jakieś dziesięć minut. Zbudujemy prawdziwy endpoint: walidator JSON-a, który przyjmuje POST, sprawdza payload i odsyła czystą odpowiedź.

Co dostajesz za darmo (a czego nie)

Plan free Cloudflare Workers daje ci 100 000 requestów dziennie i 10 milisekund czasu CPU na request. Brzmi ciasno, dopóki nie zdasz sobie sprawy, że większość endpointów JSON — sparsuj body, zrób odrobinę pracy, zwróć odpowiedź — kończy się grubo poniżej 1 ms. Sufit 10 ms to czas CPU, nie czas zegarowy, więc upstreamowy fetch trwający 800 ms wciąż liczy się jako mniej więcej 1 ms CPU, bo twój kod głównie czeka na I/O.

Czego nie dostajesz na planie free: pamięci trwałej o wysokim throughput (Workers KV ma własną darmową kwotę — hojną w większości przypadków, ale oddzielną od liczby requestów), dużych payloadów odpowiedzi ani triggerów cron częściej niż raz na minutę. Dla typowego serwisu "odbierz JSON, zrób coś, zwróć JSON", który nie potrzebuje bazy danych, nie uderzysz w ścianę.

Karta kredytowa niepotrzebna przy rejestracji. Zakładając konto, Cloudflare pyta o e-mail i hasło — i tyle. Dashboard później pyta cię o dane do płatności dla produktów płatnych, ale darmowy tier Workers nie wymaga niczego i nie zaskoczy cię opłatą.

Zainstaluj Node.js i Wranglera

Wrangler to CLI Cloudflare'a do Workers. Zainstaluj go przez npm — będziesz potrzebował Node.js 18 lub nowszego. Jeśli już masz Node'a, to one-liner:

bash
npm install -g wrangler

# Verify
wrangler --version
# Should print 3.x or higher

Teraz się zaloguj. To otworzy przeglądarkę po OAuth, założy konto Cloudflare jeśli go jeszcze nie masz, i lokalnie zapisze poświadczenia:

bash
wrangler login

# Opens https://dash.cloudflare.com/oauth/authorize ...
# After you approve: "Successfully logged in."

Zescaffolduj projekt

Jedna komenda i masz szkielet projektu z sensownymi domyślnymi ustawieniami — przykładowy handler fetch, plik konfiguracyjny wrangler.toml i lokalny serwer dev gotowy do pracy:

bash
npm create cloudflare@latest free-json-api

# When prompted, pick:
#   "Hello World" Worker
#   JavaScript (or TypeScript — your call)
#   No deploy yet (we'll do that ourselves)

cd free-json-api

Generator wrzuca wszystko, czego potrzebujesz, do jednego folderu. Otwórz src/index.js — to plik, który uruchamia twojego Workera. Zastąpimy jego zawartość czymś bardziej użytecznym niż domyślne Hello World.

Napisz API JSON

Oto kompletny Worker, który przyjmuje POST z JSON-em, waliduje dwa wymagane pola i zwraca czystą odpowiedź. Obsługuje typowe ścieżki błędów — zła metoda, niepoprawny JSON, brakujące pola — zamiast wybuchać do generycznego 500:

js
export default {
  async fetch(request) {
    if (request.method !== 'POST') {
      return Response.json(
        { error: 'POST only' },
        { status: 405 },
      );
    }

    let body;
    try {
      body = await request.json();
    } catch {
      return Response.json(
        { error: 'Body must be valid JSON' },
        { status: 400 },
      );
    }

    const { email, message } = body;
    if (typeof email !== 'string' || typeof message !== 'string') {
      return Response.json(
        { error: 'email and message are required (strings)' },
        { status: 422 },
      );
    }

    return Response.json({
      ok: true,
      receivedAt: new Date().toISOString(),
      echo: { email, message },
    });
  },
};

Dwie rzeczy warte podkreślenia. Response.json() serializuje obiekt i ustawia za ciebie Content-Type: application/json, więc nie musisz pamiętać o nagłówku. A zawijanie request.json() w try/catch to najważniejszy nawyk przy budowaniu Workerów — bez tego niepoprawny payload zwraca nieprzejrzysty 500 z runtime'u Cloudflare'a zamiast użytecznego 400 z twojego kodu.

Przetestuj lokalnie

Wrangler ma wbudowany lokalny serwer dev, który uruchamia ten sam izolat V8, którego Cloudflare używa na produkcji. Odpal go:

bash
npm run dev

# ⛅️ wrangler 3.x
# [wrangler:inf] Ready on http://localhost:8787

W innym terminalu uderz w niego curl-em. Spróbuj najpierw happy path, potem celowo zepsutego payloadu — powinieneś zobaczyć czyste błędy JSON zamiast stack trace'ów:

bash
# Happy path
curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","message":"hello"}'

# {"ok":true,"receivedAt":"2025-10-15T...","echo":{...}}

# Broken JSON (note the missing closing brace)
curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"email": "ava"'

# {"error":"Body must be valid JSON"}

# Missing required field
curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'

# {"error":"email and message are required (strings)"}
Tip: jeśli odpowiedź wygląda dziwnie w terminalu, wklej ją do JSON Formattera, żeby ładnie sformatować i przejrzeć. Robię to dwadzieścia razy dziennie, kiedy pracuję z nieznanymi API.

Zdeployuj na świat — jedną komendą

Kiedy lokalnie działa, wypchnij to globalnie:

bash
npx wrangler deploy

# Total Upload: 1.18 KiB / gzip: 0.55 KiB
# Uploaded free-json-api (1.34 sec)
# Published free-json-api (4.21 sec)
#   https://free-json-api.<your-subdomain>.workers.dev
# Current Deployment ID: ...

Ten URL jest teraz żywy w każdym data center Cloudflare'a. Request z Berlina trafia do Frankfurtu, jeden z Tokio do Tokio, jeden z São Paulo do São Paulo — ten sam kod, zero dodatkowej konfiguracji. Bundle ważył 1,2 KiB. Przetestuj żywy URL tymi samymi komendami curl, których używałeś lokalnie — po prostu zamień localhost:8787 na hostname workers.dev, który Wrangler wypisał.

Kiedy wyrośniesz z darmowego tieru

Przez długi czas nie wyrośniesz. 100 tys. requestów dziennie to mniej więcej 1,15 requesta na sekundę uśrednione przez 24 godziny — komfortowo więcej niż większość side-projectów, narzędzi wewnętrznych czy wczesnoetapowych produktów. Pierwsze, co zwykle wypycha cię z darmowego tieru, to nie liczba requestów, tylko storage: jeśli zaczniesz dużo pisać do KV, R2 albo D1, mają one swoje własne kwoty. Plan płatny zaczyna się od 5 dolarów miesięcznie i daje ci 10 milionów requestów, więcej CPU na request i siatkę bezpieczeństwa kartą kredytową na skoki ruchu. Większość projektów nigdy go nie potrzebuje.

Co dalej

To, co właśnie wypuściłeś, to absolutne minimum użytecznego Workera. Prawdziwe produkcyjne endpointy potrzebują kilku dodatkowych nawyków — CORS dla wywołań z przeglądarki, zarządzanie sekretami dla kluczy API, cachowanie na krawędzi dla wolnych upstreamów i strategia proxy do serwisów upstream. Pokrywam te tematy w Cloudflare Workers i JSON — praktyczny przewodnik, który podchwytuje tam, gdzie kończy się ten artykuł.

Kilka narzędzi, które trzymam otwarte, gdy buduję Workery operujące na JSON-ie: JSON Formatter do pretty-printowania odpowiedzi, JSON Validator, kiedy trzeba dokładnie ustalić, dlaczego payload został odrzucony, oraz JSON Path do planowania logiki wybierania pól, zanim ją napiszę. Sam format JSON jest wyspecyfikowany w RFC 8259 — warto go przejrzeć, kiedy zaczniesz obsługiwać dziwne dane od prawdziwych użytkowników.

Po głębsze wzorce dla Workerów — KV storage, Durable Objects, scheduled triggers, bindingi do AI inference — najlepszym źródłem, jakie znalazłem, jest galeria przykładów Workers Cloudflare'a. To gotowa do skopiowania lista przepisów na kolejne kroki.

Podsumowanie

Cloudflare Workers to rzadki darmowy tier, który jest faktycznie sensowny dla prawdziwych side-projectów. Brak karty kredytowej na start, 100 tys. requestów dziennie i deploy mieszczący się w jednej komendzie. Wzorzec z tego artykułu — przyjmij JSON, zwaliduj, zwróć JSON — pokrywa zaskakująco dużo z tego, co robi większość API. Jeśli wstrzymujesz się z wypuszczeniem małego API, bo infra wydaje się harówą, to jest ścieżka, którą sam chciałbym był wybrać trzy lata temu.