Produkty Poradenství O nás Blog Kontakt English
arrow_back Zpět na blog

Observabilita a optimalizace vašeho GraphQL API

Observabilita a optimalizace vašeho GraphQL API

Část 7 série „Production GraphQL with Netflix DGS" — Bonus: Provoz


GraphQL API jsou pro tradiční monitoring neviditelná. Každý request dorazí na stejný endpoint /graphql, vrátí HTTP 200 (i když tělo odpovědi obsahuje chyby) a nenese žádný URL-based kontext pro vaše dashboardy. Pokud monitorujete GraphQL API stejně jako REST, letíte naslepo.

Tento článek pokrývá vrstvu observability a optimalizace nad vaším DGS backendem: federation s GraphQL routerem, identifikace klientů, metriky na úrovni operací, klasifikace chyb, analytika schématu a techniky optimalizace výkonu, které zabrání vašemu API stát se úzkým hrdlem.

Proč GraphQL potřebuje odlišnou observabilitu

S REST dokáže váš monitoring stack odpovídat na základní otázky pouhým pohledem na HTTP metadata:

Text
GET /api/products?page=0&size=20  →  200  →  42ms
POST /api/orders                   →  201  →  156ms
GET /api/orders/123                →  404  →  3ms

Každý endpoint je samostatná URL. Můžete stavět dashboardy, nastavovat alerty a identifikovat pomalé endpointy, aniž byste nahlíželi do těl requestů.

GraphQL tento model rozbíjí:

Text
POST /graphql  →  200  →  42ms   (Was this a product search? An order? Which fields?)
POST /graphql  →  200  →  3200ms (Slow — but what operation? Which resolver?)
POST /graphql  →  200  →  12ms   (200 OK, but the response body contains 3 errors)

Každý request je POST /graphql, každá odpověď je 200 OK (protože GraphQL vrací chyby v těle odpovědi, ne jako HTTP stavové kódy), a bez inspekce payloadu nerozeznáte lehký dropdown dotaz od hluboce vnořeného analytického query.

Řešením je observabilita na úrovni operací: pojmenujte své operace, měřte je individuálně, sledujte, kteří klienti je posílají, a monitorujte chybovost per operace — ne per endpoint.

Federation: vrstva routeru

Jak váš systém roste, rozdělíte GraphQL API napříč více službami. Federation router skládá jejich schémata do jednoho grafu a směruje příchozí dotazy na správnou službu.

Architektura

graph TD C["Client"] --> GW["API Gateway
Auth, rate limiting,
circuit breaker
"] GW --> R["GraphQL Router
Schema composition,
query planning
"] R --> S1["Products Service
DGS — catalog + inventory"] R --> S2["Orders Service
DGS — checkout + fulfillment"] R --> S3["Users Service
DGS — accounts + preferences"] style C fill:#4a9eff,stroke:#2171c7,color:#fff style GW fill:#7c4dff,stroke:#5e35b1,color:#fff style R fill:#7c4dff,stroke:#5e35b1,color:#fff style S1 fill:#00bfa5,stroke:#00897b,color:#fff style S2 fill:#00bfa5,stroke:#00897b,color:#fff style S3 fill:#00bfa5,stroke:#00897b,color:#fff

Router načte schéma každé služby, složí je do supergraphu a řeší query planning — rozhoduje, které služby je třeba zavolat pro každý příchozí dotaz a v jakém pořadí.

Kompozice supergraphu

Supergraph se skládá v build time (nebo při změně), nikoli za běhu při každém requestu:

graph LR S1["Service A
schema"] --> FETCH["Composition Tool"] S2["Service B
schema"] --> FETCH S3["Service C
schema"] --> FETCH FETCH --> DIFF{"Schema
changed?"} DIFF -->|Yes| DEPLOY["Deploy supergraph
to router"] DIFF -->|No| SKIP["Skip — no changes"] style FETCH fill:#7c4dff,stroke:#5e35b1,color:#fff style DIFF fill:#ffd54f,stroke:#f9a825,color:#333 style DEPLOY fill:#00bfa5,stroke:#00897b,color:#fff style SKIP fill:#bdbdbd,stroke:#9e9e9e,color:#333

Praktický kompoziční skript detekuje změny před aktualizací:

Bash
# Pseudocode for a composition pipeline
compose_supergraph() {
    # Fetch current schemas from running services
    rover supergraph compose --config supergraph.yaml > new_supergraph.graphqls

    # Only update if schema actually changed
    current_hash=$(sha256sum current_supergraph.graphqls | cut -d' ' -f1)
    new_hash=$(sha256sum new_supergraph.graphqls | cut -d' ' -f1)

    if [ "$current_hash" != "$new_hash" ]; then
        deploy_supergraph new_supergraph.graphqls
        log "Supergraph updated"
    else
        log "No schema changes detected, skipping"
    fi
}

Tento vzor composition-on-change zamezuje zbytečným reloadům routeru a činí pipeline idempotentní — bezpečný pro spuštění podle plánu nebo při každém deploymentu.

Publikování schématu (volitelné)

Volitelně můžete složené schéma publikovat do registru (Apollo Studio, GraphQL Hive nebo podobný nástroj) pro účely analytiky:

Bash
# Publish to a schema registry for field-level analytics
if [ "$PUBLISH_TARGET" = "registry" ]; then
    rover subgraph publish \
        --name core-service \
        --schema service-a.graphqls \
        --routing-url http://service-a:4000/graphql
fi

To umožní registru sledovat využití polí, detekovat breaking changes a poskytovat analytiku deprekací — schopnosti, které pokryjeme dále v tomto článku.

Autentizace služeb pro kompozici

Kompoziční nástroj potřebuje introspektovat vaše služby. V produkci by neměl používat stejnou autentizaci jako běžní uživatelé. Standardním přístupem je dedikovaný servisní token s omezenými oprávněními:

YAML
# Composition tool configuration
services:
    - name: core-service
      url: http://service-a.internal:4000/graphql
      headers:
          Authorization: "Bearer ${SERVICE_INTROSPECTION_TOKEN}"
    - name: health-service
      url: http://service-b.internal:4000/graphql
      headers:
          Authorization: "Bearer ${SERVICE_INTROSPECTION_TOKEN}"

Backend tento token validuje odděleně od uživatelských JWT — uděluje přístup k introspekci, ale nic víc.

Odolnost gateway

API gateway stojí před routerem a poskytuje vzory odolnosti, které by GraphQL vrstva neměla vlastnit:

Circuit Breaker

YAML
# Tune these values for your traffic patterns
circuit-breaker:
    sliding-window-size: 20
    sliding-window-type: TIME_BASED
    minimum-number-of-calls: 10
    wait-duration-in-open-state: 10s
    failure-rate-threshold: 60

Když míra selhání překročí práh v rámci sliding window, circuit se otevře a vrátí rychlé selhání místo toho, aby requesty narážely na padající službu.

U GraphQL rout se můžete rozhodnout circuit breaker neaplikovat — protože GraphQL zvládá částečná selhání elegantně (některá pole uspějí, jiná selžou a odpověď obsahuje jak data, tak chyby). Gateway potřebuje zasáhnout pouze při úplném výpadku služby.

Rate Limiting

Rate limiting per endpoint nedává u GraphQL smysl (je to všechno jeden endpoint). Místo toho limitujte podle identity:

YAML
# Example values — adjust based on your traffic and abuse patterns
rate-limiting:
    graphql:
        requests-per-minute: ${RATE_LIMIT_GRAPHQL}
    auth-login:
        requests-per-minute: ${RATE_LIMIT_LOGIN}
    auth-register:
        requests-per-hour: ${RATE_LIMIT_REGISTER}

Login a registrační endpointy dostávají přísné limity proti brute-force útokům. Hlavní GraphQL endpoint dostává velkorysý limit, který legitimní uživatelé nepřekročí, ale který zabrání automatizovanému scrapování.

Rate limiter používá ID autentizovaného uživatele, pokud je k dispozici, a pro neautentizované requesty padá zpět na IP adresu klienta. To zabraňuje jednomu uživateli vyhladovět ostatní a zároveň propouští legitimní provoz.

GraphQL error fallbacky

Když je backend zcela nedostupný, gateway vrátí správně formátovanou GraphQL chybu — ne HTML 503 stránku:

JSON
{
    "errors": [{
        "message": "Service temporarily unavailable. Please try again.",
        "extensions": {
            "code": "SERVICE_UNAVAILABLE"
        }
    }],
    "data": null
}

To je důležité, protože GraphQL klienti očekávají specifický formát odpovědi. HTML chybová stránka rozbije parsování JSON a způsobí kryptické chyby na straně klienta.

WebSocket routing

Subscriptions používají WebSocket spojení, které obchází router:

YAML
# WebSocket connections route directly to the backend
websocket-route:
    path: /graphql
    uri: ws://backend-service/graphql
    filters:
        - SetRequestHeader=Upgrade, websocket

WebSocket spojení jsou dlouhodobá (sessions mohou běžet hodinu i déle), takže potřebují jiné timeout a škálovací charakteristiky než běžné HTTP requesty.

Identifikace klientů

Apollo Studio (a podobné nástroje) dokáží zjistit, který klient odeslal každý request — ale pouze pokud se klient identifikuje.

Dvě povinné hlavičky

TYPESCRIPT
const graphqlClient = axios.create({
    headers: {
        'apollographql-client-name': 'web-app',
        'apollographql-client-version': '2.4.1'
    }
})

Tyto dvě hlavičky — apollographql-client-name a apollographql-client-version — pohánějí dashboard klientů:

  • Kteří klienti posílají requesty (webová aplikace, mobilní aplikace, admin panel, cron joby)
  • Která verze každého klienta je nasazena
  • Chybovost per verze klienta (rozbil deploy v2.4.1 něco?)
  • Rozpad operací per klient (co admin panel dotazuje a webová aplikace ne?)

Bez těchto hlaviček se váš provoz zobrazuje jako „Unidentified client" a ztrácíte veškerou per-klientskou viditelnost.

Injektování verze v build time

Nehardcodujte verzi — injektujte ji z package.json v build time:

TYPESCRIPT
// vite.config.ts
import pkg from './package.json'

export default defineConfig({
    define: {
        __APP_VERSION__: JSON.stringify(pkg.version)
    }
})

// In your GraphQL client setup
declare const __APP_VERSION__: string
const clientVersion = typeof __APP_VERSION__ !== 'undefined'
    ? __APP_VERSION__
    : 'unknown'

Tím zajistíte, že verze sleduje skutečné deploymenty. Pokud vidíte nárůst chyb u verze 2.4.1, ale ne u 2.4.0, přesně víte, který deployment vyšetřit.

Více názvů klientů

V architektuře micro-frontendů by měl každý MFE ideálně používat stejný název klienta s kontextem modulu v názvech operací:

Text
apollographql-client-name: my-web-app
apollographql-client-version: 2.4.1

Všechny MFE sdílejí stejného centralizovaného GraphQL klienta (a tedy stejné hlavičky), takže se v analytice zobrazují jako jeden klient. Jednotlivé operace se rozlišují podle názvů operací (např. GetProducts, CreateOrder), nikoli podle názvu klienta.

Metriky na úrovni operací

Měření pomocí AOP

AOP aspekt obalí každý @DgsQuery a @DgsMutation časováním a počítáním:

Java
@Aspect
@Component
public class OperationMetricsAspect {

    @Around("@annotation(com.netflix.graphql.dgs.DgsQuery) || " +
            "@annotation(com.netflix.graphql.dgs.DgsMutation)")
    public Object measureOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        String operationName = joinPoint.getSignature().getName();
        String operationType = isQuery(joinPoint) ? "query" : "mutation";
        long startTime = System.nanoTime();

        Object result = joinPoint.proceed();

        if (result instanceof Mono<?> mono) {
            return mono
                .doOnSuccess(v -> recordMetrics(operationType, operationName, startTime, "success"))
                .doOnError(e -> recordMetrics(operationType, operationName, startTime, "error"));
        }

        recordMetrics(operationType, operationName, startTime, "success");
        return result;
    }
}

Tím vznikají tři metriky na operaci:

MetrikaTypÚčel
gql.operation.latencyTimer (histogram)Distribuce latence per operace
gql.operation.countCounterPropustnost per operace
gql.operation.errorsCounterChybovost per operace a typ chyby

Histogramy založené na SLO

Namísto sledování pouhých průměrů a p99 nakonfigurujte histogramy s SLO hranicemi, které vám přesně řeknou, kolik requestů spadá do kterého latencového bucketu:

YAML
management:
    metrics:
        distribution:
            percentile-histogram:
                gql.operation.latency: true
            slo:
                # Choose boundaries that match your SLAs
                gql.operation.latency: 25ms, 75ms, 150ms, 300ms, 750ms, 1.5s, 3s

Tím se vygenerují histogram buckety na každé SLO hranici. Váš monitoring dashboard pak může zobrazit:

Text
gql.operation.latency (products.search):
  ≤ 75ms:   72%  ████████████████████
  ≤ 150ms:  89%  ████████████████████████
  ≤ 300ms:  96%  ██████████████████████████
  ≤ 750ms:  99%  ███████████████████████████
  ≤ 1.5s:   99.8%
  > 3s:     0.1%  (these need investigation)

Když 95. percentil operace překročí hranici (řekněme z 200ms na 500ms), je to předstihový indikátor výkonnostního problému — i když průměr je stále v pořádku.

Detekce pomalých dotazů

Zalogujte varování, když jakákoli operace překročí práh:

Java
private void recordSuccess(String type, String name, long startTime) {
    Duration duration = Duration.ofNanos(System.nanoTime() - startTime);

    if (duration.compareTo(LATENCY_THRESHOLD) > 0) {
        log.warn("GraphQL operation exceeded threshold",
                kv("operation", name),
                kv("type", type),
                kv("durationMs", duration.toMillis()));
    }
}

Se strukturovaným logováním můžete tyto pomalé operace vyhledávat v log agregátoru:

Text
# Example: searching for slow operations in your log aggregator
message="GraphQL operation exceeded threshold" AND durationMs > 2000

Tím odhalíte operace, které potřebují optimalizaci — dříve, než si toho všimnou uživatelé.

Klasifikace a monitoring chyb

Tok chyb

Chyby ve federovaném GraphQL systému procházejí více vrstvami:

graph TD EX["DGS throws exception"] --> H["DataFetcherExceptionHandler"] H --> CLS["Classify error code"] H --> SAN["Sanitize message"] H --> LOG["Log full details server-side"] CLS --> R["GraphQL response
data + errors array"] SAN --> R R --> ROUTER["Router forwards
HTTP 200"] ROUTER --> GW["Gateway passes through
No circuit breaker —
GraphQL handles partial failures
"] GW --> CLIENT["Client receives
data + errors"] style EX fill:#ff7043,stroke:#e64a19,color:#fff style H fill:#7c4dff,stroke:#5e35b1,color:#fff style R fill:#ffd54f,stroke:#f9a825,color:#333 style CLIENT fill:#4a9eff,stroke:#2171c7,color:#fff

Distribuce chybových kódů

Sledujte, které chybové kódy se vyskytují nejčastěji:

Chybový kódCo znamenáMonitorovat?
BAD_USER_INPUTValidační selhání (očekávané)Sledovat objem, ne jednotlivé chyby
NOT_FOUNDResource neexistuje (očekávané)Sledovat objem, hlídat nárůsty
FORBIDDENSelhání autorizace (bezpečnostní záležitost)Alertovat při nárůstech — může indikovat útok
INTERNAL_SERVER_ERRORBug (neočekávaný)Alertovat okamžitě — potřebuje opravu
SERVICE_UNAVAILABLEFallback gateway/routeruAlertovat — indikuje problém infrastruktury

Klíčový vhled: ne každá chyba je bug. BAD_USER_INPUT je normální chování uživatele. INTERNAL_SERVER_ERROR je defekt. Váš alerting by měl mezi nimi rozlišovat:

Java
// Alert-worthy: unexpected errors
if (exception instanceof RuntimeException && !(exception instanceof DomainException)) {
    log.error("Unexpected error in GraphQL operation",
            kv("path", path),
            kv("errorType", exception.getClass().getSimpleName()),
            exception);  // Full stack trace for debugging
}

// Info-level: expected validation failures
if (exception instanceof ValidationException) {
    log.info("Validation error",
            kv("path", path),
            kv("message", exception.getMessage()));
}

Chybovost per operace

Kombinací názvů operací s chybovými kódy najdete problémové oblasti:

Text
Operation: createOrder  →  12% error rate  →  80% BAD_USER_INPUT (ok, complex form)
Operation: getProducts  →  0.1% error rate →  mostly NOT_FOUND (ok, invalid URLs)
Operation: updateStock  →  8% error rate   →  60% INTERNAL_SERVER_ERROR (needs fixing!)

Mutace updateStock má 8 % chyb a většina jsou internal server errors — to je bug. Mutace createOrder má 12 % chyb, ale téměř všechny jsou validační selhání — to jsou jen uživatelé odesílající špatná data. Bez tohoto rozpadu vidíte jen „10 % chybovost na GraphQL API" a netušíte, kam se podívat.

Analytika schématu

Sledování využití polí

Schema registry dokáže sledovat, která pole klienti skutečně používají. To vyžaduje dvě věci:

  1. Registrace operací — klienti posílají pojmenované operace (ne anonymní dotazy)
  2. Reporting využití — router nebo backend reportuje, kterých polí se každá operace dotýká

S těmito daty můžete odpovídat na otázky jako:

Text
Field: Product.legacyCode
  Used by: 0 clients in the last 90 days
  Action: Safe to deprecate and remove

Field: Product.reviews
  Used by: web-app (v2.3+), mobile-app (v1.8+)
  Action: Cannot remove without client migration

Field: Product.internalSKU
  Used by: admin-panel only
  Action: Consider restricting to admin role

Detekce nepoužívaných polí

Analytika schématu odhaluje mrtvá pole — pole definovaná ve schématu, ale nikdy nepožadovaná:

GRAPHQL
type Product {
    id: ID!
    name: String!
    price: Float!
    legacyCode: String      # ← Last used 6 months ago
    internalNotes: String    # ← Never requested by any client
    migrationStatus: String  # ← Used only by deprecated v1 client
}

Bez analytiky se tato pole hromadí donekonečna. Jejich data loadery a resolvery se stále vykonávají, když jsou zahrnuta do dotazu, a jejich podkladová data je třeba udržovat. Analytika využití na úrovni polí vám umožňuje:

  1. Deprecovat pole, která se již nepoužívají
  2. Odstraňovat deprecovaná pole po uplynutí přechodného období
  3. Identifikovat pole, která by neměla být veřejná (jako internalNotes)

Validace schématu v CI

Zachyťte breaking changes dříve, než se dostanou do produkce, porovnáním verzí schématu:

Bash
# CI pipeline step
graphql-inspector diff \
    schema-deployed.graphqls \
    schema-current.graphqls

Tím zachytíte:

  • Odstranění polí (breaking)
  • Změny typů (breaking)
  • Přidání povinných argumentů (breaking)
  • Deprecations (non-breaking, informační)

Přidání tohoto kroku jako CI gate znamená, že breaking changes jsou zachyceny při code review, nikoli po deploymentu.

Optimalizace výkonu

Persisted Queries

Každý GraphQL request obsahuje celý query string — který může být velký. Automatic Persisted Queries (APQ) nahrazují query string hashem:

Text
# First request: send the full query
POST /graphql
{
    "query": "query GetProducts($page: Int!) { products(pageNumber: $page) { ... } }",
    "extensions": {
        "persistedQuery": {
            "version": 1,
            "sha256Hash": "abc123..."
        }
    }
}

# Subsequent requests: send only the hash
POST /graphql
{
    "extensions": {
        "persistedQuery": {
            "version": 1,
            "sha256Hash": "abc123..."
        }
    }
}

Router cachuje text dotazu podle hashe. Po prvním requestu klienti posílají pouze hash — což redukuje payload requestu o 80–90 % u komplexních dotazů.

Má to také bezpečnostní benefit: v uzamčeném produkčním prostředí můžete odmítnout dotazy, které nejsou v persisted seznamu — čímž efektivně vytvoříte allowlist operací.

Rozpočty složitosti dotazů

Nad rámec limitů hloubky a složitosti pokrytých v části 3 zvažte přiřazení explicitních nákladů drahým polím:

Java
// Custom field weights
fields.put("Product.reviews", 10);      // Triggers a DB join
fields.put("Product.recommendations", 20); // Triggers an ML service call
fields.put("Order.timeline", 5);         // Aggregates multiple events

Dotaz, který fetchuje products { reviews recommendations }, by stál 1 + 10 + 20 = 31 bodů na položku. Při stránce 20 položek je to 620 bodů — potenciálně nad rozpočtem. Klient buď zmenší velikost stránky, nebo odstraní drahé pole.

Load testing s GraphQL-aware metrikami

Standardní load testovací nástroje měří HTTP response časy, ale nedokáží rozlišovat GraphQL operace. Použijte nástroj jako k6 s custom metrikami:

JAVASCRIPT
// k6 load test with GraphQL-specific metrics
import { Trend, Rate } from 'k6/metrics'

const queryDuration = new Trend('graphql_query_duration')
const mutationDuration = new Trend('graphql_mutation_duration')
const errorRate = new Rate('graphql_error_rate')

export default function () {
    const start = Date.now()

    const response = http.post(GRAPHQL_URL, JSON.stringify({
        query: `query GetProducts($page: Int!) {
            products(pageNumber: $page, pageSize: 20) {
                items { id name price }
                totalElements
            }
        }`,
        variables: { page: 0 }
    }), { headers: { 'Content-Type': 'application/json' } })

    const duration = Date.now() - start
    queryDuration.add(duration)

    const body = JSON.parse(response.body)
    errorRate.add(body.errors ? 1 : 0)
}

Progresivní load profily

Navrhněte testovací profily, které simulují reálné vzory provozu:

ProfilVUsTrváníPrahyÚčel
Canary130sp95 < 500ms, errors < 1%Pre-deploy smoke test
Load10→3020minp95 < 1s, errors < 5%Validace kapacity
Stress20→30025minp95 < 5s, errors < 30%Zjištění bodu zlomu
Spike10→15012minp95 < 3s, errors < 15%Zvládání nárazového zatížení

Canary profil je obzvláště cenný: spouštějte ho automaticky před každým deploymentem. Pokud selže, přerušte rollout dřív, než jsou dotčeni uživatelé.

Realistický mix zátěže zrcadlí skutečný provoz:

Text
80% read operations (queries)
├── Product search: 30%
├── Product detail: 25%
├── Order list: 15%
└── User profile: 10%

20% write operations (mutations)
├── Add to cart: 10%
├── Place order: 5%
└── Update profile: 5%

Distribuované tracování

GraphQL request může zasáhnout více služeb, databází a cache. Distribuované tracování je propojí do jedné timeline.

Propagace trace kontextu

Klient zahájí trace odesláním korelačních hlaviček:

TYPESCRIPT
const headers = {
    'Content-Type': 'application/json',
    'X-Trace-Id': generateTraceId(),
    'X-Span-Id': generateSpanId()
}

Gateway, router a backend všechny propagují tato ID. Ve vašem log agregátoru můžete hledat podle trace ID a vidět kompletní cestu:

sequenceDiagram participant Client participant GW as Gateway participant Router participant Backend participant DB as Database Client->>GW: POST /graphql (traceId=abc123) GW->>Router: Forward with traceId Router->>Backend: Route to service (operation=GetProducts) Backend->>DB: SELECT products (12ms) DB-->>Backend: Results Backend->>Backend: DataLoader batch (loader=categories, 5 keys) Backend-->>Router: GraphQL response (45ms) Router-->>GW: Composed response GW-->>Client: HTTP 200 (48ms total)

OpenTelemetry většinu z toho automatizuje. S Java agentem je každý HTTP call, databázový dotaz a cache lookup automaticky instrumentován:

YAML
# OpenTelemetry configuration
otel:
    traces:
        exporter: otlp
    propagators: tracecontext   # W3C standard
    sampling:
        probability: 0.05  # Sample 5% of production traffic (adjust for your volume)

Propagátor tracecontext sleduje standard W3C Trace Context. Pokud potřebujete zpětnou kompatibilitu se staršími tracing systémy, přidejte dle potřeby další propagátory.

Checklist observability

Co monitorovatJakAlertovat když
Latence operacíSLO histogram per operacep95 překročí SLO hranici
Chybovost podle kóduCounter per chybový kód per operaceINTERNAL_SERVER_ERROR > 1 %
Identifikace klientůApollo hlavičky na každém requestu„Unidentified client" > 5 %
Využití políAnalytika schema registryPole nepoužívaná 90+ dní
Změny schématuCI schema diffDetekována breaking change
Složitost dotazůSkóre složitosti per requestPřekročení rozpočtu > 10 % requestů
Zdraví gatewayStav circuit breakeruCircuit se otevře
Zdraví kompoziceSupergraph diffKompozice selže
Subscription spojeníPočet WebSocket spojeníNárůst nad baseline
Zásahy rate limituCounter per identitaLegitimní uživatelé narážejí na limity

Co chybí (a co přidat dále)

Žádný observability setup není kompletní od prvního dne. Zde jsou vysoce účinná rozšíření ke zvážení:

  1. Validace schématu v CI — použijte graphql-inspector k zachycení breaking changes před mergem.
  2. Persisted queries — snížení velikosti payloadu a přidání allowlistu operací pro bezpečnost.
  3. Sledování nákladů per pole — přiřaďte váhy drahým resolverům pro chytřejší omezování složitosti.
  4. Korelace chyb na straně klienta — propojení frontendových chyb s backendovými traces pomocí sdílených trace ID.
  5. Canary deploymenty s GraphQL metrikami — rychlé selhání, pokud nová verze zhoršuje latenci operací.

Toto nejsou požadavky prvního dne — ale jsou to rozdíly mezi „máme monitoring" a „rozumíme svému API."


Titulní foto: Luke Chesser na Unsplash.

Další z blogu