Skip to content

Simple guide · Overview

Page status: Active

Public API Plan

Related issue: ramideltoro/nutsnews#39

Visual overview

Primary diagram

System map

Related issue: ramideltoro/nutsnews#39

Render the repository-owned system map when you need it.

Diagram is not rendered yet.

View as text
Public API Plan

Related issue: ramideltoro/nutsnews#39

flowchart LR
  accTitle: Public API Plan
  accDescr {
    Related issue: ramideltoro/nutsnews#39
  }
  A[Define public API contracts] --> B[Version and validate schema expectations]
  B --> C[Roll out endpoint safety and auth controls]
  C --> D[Document migration and rollout strategy]
  D --> E{Regression checks pass?}
  E -->|No| F[Block rollout and update plan]
  E -->|Yes| G[Enable staged public release]
  G --> H[Monitor usage and compatibility]
  H --> I[Publish rollout results and update docs]
  F --> I

Public API Plan

Fullscreen diagram view.

Related issue: ramideltoro/nutsnews#39

Status: planning only. This document does not approve or implement a new public API route.

NutsNews may later offer a small read-only public API for approved reader and partner use cases. The first version should expose only public story-card data that already appears on the site, keep private review and operational fields hidden, and rely on conservative rate limits plus CDN caching.

The current /api/articles and /api/search routes are public compatibility surfaces for the web app and iOS app, but they are not yet a documented third-party developer product. A formal public API should be additive and versioned, for example under /api/public/v1/*, so existing clients keep their contract while external consumers get a stable, intentionally limited surface.

The first version should support read-only article discovery, single-article lookup by public ID or slug, and optional search/category filtering. It should not expose admin state, source scoring internals, AI prompts, model decisions, worker run metadata, analytics, audit logs, credentials, or unpublished/rejected content.

Public API implementation should happen only after the endpoint inventory, contract tests, abuse limits, cache policy, privacy review, and rollback plan are ready. The API should reuse existing public article serialization patterns where safe, but it must not silently change the current iOS/web compatibility contract documented in Public API Contract Tests.

The first release target is a cache-friendly, unauthenticated read API with bounded query parameters, deterministic response shapes, explicit pagination, and no write operations. If usage or abuse risk grows, API keys can be added as a second phase without changing the anonymous read contract.

Use caseSupported in first public version?Notes
Display the latest positive-news headlines in a small widgetYesReturn recent public article cards with source attribution and original links.
Search the public archive by keywordYes, boundedKeep query length, page size, and result count limited.
Filter by category or languageYesUse the same public category and language concepts visible in the reader UI.
Fetch one public story for preview or sharingYesUse a stable public ID or slug; return only public card/detail fields.
Build large mirrors, bulk exports, or datasetsNoRequire separate review because of publisher rights, traffic, and retention concerns.
Trigger ingestion, translation, review, or refresh jobsNoThese remain internal Worker/admin operations.
Read admin review decisions or AI audit logsNoThese are protected operational records.
Track reader-level behaviorNoPublic API must not expose analytics or personal/device state.

Use versioned routes so the contract can evolve without breaking app or iOS clients:

EndpointPurposeRequest notes
GET /api/public/v1/articlesRecent public article cardspage or cursor, limit, category, lang; fixed maximum limit.
GET /api/public/v1/articles/{id}One public articleid is opaque and stable; unpublished, rejected, or removed stories return 404.
GET /api/public/v1/searchBounded public archive searchq, page or cursor, limit, lang; short queries return an empty success response.
GET /api/public/v1/openapi.jsonMachine-readable contractGenerated from the same source as contract tests once implementation starts.

Do not repurpose /api/articles or /api/search as the third-party contract without a reviewed migration. Those routes already carry web and iOS compatibility expectations.

First-version responses should expose only public fields needed for display and attribution.

FieldExpose?Notes
idYesOpaque stable public identifier. Do not require consumers to infer database shape.
url or article_urlYesNutsNews article/detail URL if a public article page exists.
original_urlYesPublisher destination URL for attribution and click-through.
sourceYesPublisher display name.
titleYesPublic article title in the requested or fallback language.
summaryYesPublic summary text, bounded to the same content policy as the site.
categoryYesPublic category label or slug.
image_urlYes, nullablePublic thumbnail URL only; do not expose image-processing internals.
published_atYes, nullablePublisher timestamp when known.
published_on_site_atYes, nullableNutsNews publication timestamp when available.
language_codeYesResponse language.
translation_availableYesBoolean language availability metadata.
next_cursor or next_pageYesChoose one pagination style per endpoint and document it before release.

These fields and concepts must stay private unless a later issue explicitly approves a narrower public release.

Hidden dataReason
Supabase service-role data, auth state, sessions, cookies, tokens, credentials, and environment valuesSecrets and access control.
Admin review status, reviewer identity, moderation notes, audit logs, and rejection reasonsOperational privacy and abuse prevention.
AI prompts, raw model output, model/provider routing, scoring rubrics, decision traces, and prompt/model version audit reportsInternal quality and security data.
Source trust tier internals, allowlist administration history, quality scores, and feed health diagnosticsCould expose abuse targets and vendor/publisher operations.
Worker runs, queue state, controller locks, retry metadata, and local AI health detailsInternal operations and reliability posture.
Raw feed payloads, full article bodies, scraped content, and publisher-only metadataPublisher rights and data minimization.
Analytics, saved stories, consent state, IP addresses, user agents, referrers, and device/browser identifiersReader privacy.
Draft, unpublished, rejected, removed, or embargoed articlesEditorial and takedown correctness.

Initial public API limits should be conservative and enforceable at the earliest reliable edge layer.

ControlInitial target
Anonymous read limit60 requests per minute per client IP or equivalent edge identity.
Search limit20 requests per minute because search is more expensive and less cacheable.
Maximum page size20 articles per page.
Maximum deep pagination500 articles or an equivalent cursor age/window until usage justifies more.
Method supportGET and HEAD only for public API routes.
Request bodyNot accepted. Reject bodies on GET requests where the framework exposes them.
CORSAllow GET from browsers only after explicit review; otherwise keep server-to-server/public same-origin behavior documented.
User-agent policyDo not require a custom user agent for v1, but log and rate-limit abusive generic traffic.
Error bodyStable JSON { "error": string } with no stack traces, SQL details, provider messages, or internal IDs.

If usage grows beyond free-tier or reliability budgets, add API keys, lower anonymous limits, or require allowlisted partner access before raising limits.

Public API responses should be safe to cache without exposing private state.

Route typeInitial cache targetNotes
Recent article listCDN s-maxage=300, stale-while-revalidate=600Fresh enough for readers while protecting Supabase and runtime capacity.
Single public articleCDN s-maxage=3600, stale-while-revalidate=86400Revalidate or purge if takedown/removal tooling needs faster removal.
Search resultsCDN s-maxage=120, stale-while-revalidate=300Bound query length and normalize cache keys.
OpenAPI contractCDN s-maxage=3600, stale-while-revalidate=86400Changes only with reviewed deploys.
Errors, rate limits, auth failures, and validation failuresno-store or short private cache onlyAvoid caching transient or client-specific failures.

Cache keys must include language, category, search query, pagination token/page, and version. They must not include credentials, cookies, raw IPs, or unbounded query strings.

  • Implement all public API routes as additive versioned endpoints.
  • Add each route to the app repository API inventory before release.
  • Add deterministic contract tests for success, empty, validation, pagination, cache headers, rate limits, and provider failure cases.
  • Publish an OpenAPI document only when it is generated or checked against the same source as the tests.
  • Never remove, rename, or change the type of a public v1 field without a reviewed migration.
  • Additive nullable fields are allowed only with documentation and contract coverage.
  • Breaking changes require a new version path and a sunset plan for the old version.

The public API must preserve the same privacy and attribution boundaries as the site:

  • Keep reader-specific state client-local or protected; never expose saved stories, consent choices, analytics, or device data.
  • Return publisher attribution and original links with article content.
  • Do not expose full article bodies or raw feed payloads.
  • Support takedown/removal by returning 404 for removed public IDs after cache purge or revalidation.
  • Keep summaries bounded to the public content policy documented for NutsNews.

Before implementation begins, create or update:

  1. Endpoint inventory and compatibility tests in ramideltoro/nutsnews.
  2. Cache and rate-limit tests for public API headers and abuse controls.
  3. OpenAPI generation or validation workflow.
  4. Privacy review covering exposed fields and logs.
  5. Publisher attribution review covering summaries, links, images, and takedowns.
  6. Observability checks for availability, latency, error rate, rate-limit rate, and cache hit rate.
  7. Rollback plan that can disable or hide the public API without breaking existing web/iOS routes.

The first implementation should include a runtime kill switch that returns 404 or 503 for /api/public/v1/* without affecting existing /api/articles, /api/search, health, sitemap, or admin routes. Rollback should not require schema deletion. If a schema or migration is needed later, it must be additive and safe to leave unused after disabling the API.