Kramerius API dokumentace

Zdroj: README.md

API endpoint: kramerius.php

Endpoint slouží pro dohledání UUID stránky v Krameriu podle vstupu z Wikidat, nebo pro dohledání informací o stránce podle jejího UUID.

Stav po migraci

URL a metoda

Poznámka: GET s query parametry nebo s body není podporován a vrací 405.

Režim 1: Wikidatový lookup (wd + page)

Request body

PolePovinnéPopis
wdanoQID dokumentu na Wikidatech (např. Q123456).
pageanoČíslo stránky (např. 12).
volumeneRočník nebo svazek.
volume_yearsneObdobí ročníku (např. 1831 nebo 1830-1831).
issueneČíslo vydání.
issue_typeneTyp vydání, používá se pro zpřesnění shody podle mods:note v streams/BIBLIO_MODS (např. večerní, večerní vydání, večerní vyd.).
issue_dateneDatum vydání (YYYY-MM-DD, YYYY-MM, YYYY nebo DD.MM.YYYY).
supplementneČíslo přílohy (např. 1 nebo "2. příloha").
debugneBoolean; pokud je true, vrací se debug_trace.
manual_limitneInteger 10-400; maximální počet kandidátů pro manuální výběr (volitelné, jinak adaptivně podle úplnosti vstupu).
manual_depthneInteger 3-16; hloubka průchodu stromu Krameria při manuálním fallbacku (volitelné, jinak adaptivně podle úplnosti vstupu).

Příklad requestu:

{
  "wd": "Q96613911",
  "page": "140",
  "volume": "3",
  "volume_years": "1849",
  "issue": "18",
  "issue_type": "",
  "issue_date": "1849-04-01",
  "supplement": "",
  "debug": false
}

Režim 2: Přímý UUID lookup (uuid)

Dohledá veškeré dostupné informace o stránce podle jejího UUID. Procházení hierarchie:

stránka → vydání → svazek → dokument.

Poznámka: pokud stránka leží ve větvi supplement, API u issue_uuid vrací přednostně UUID rodičovského čísla (periodicalitem), nikoli UUID samotné přílohy. Díky tomu zůstávají pole issue, issue_date a citace konzistentní.

Request body

PolePovinnéPopis
uuidanoUUID stránky v Krameriu (např. 35d64c24-9cf2-408b-9147-935f1323be20).
debugneBoolean; pokud je true, vrací se debug_trace.

Příklad requestu:

{
  "uuid": "35d64c24-9cf2-408b-9147-935f1323be20",
  "debug": false
}

Úspěšná odpověď

HTTP status: 200

Struktura odpovědi je stejná pro oba režimy (Wikidatový i UUID lookup):

{
  "ok": true,
  "selection_required": false,
  "results_meta": {
    "offset": 0,
    "batch_size": 25,
    "returned_count": 1,
    "minimum_total_count": 1,
    "has_more": false
  },
  "results": [
    {
      "api_base": "https://ndk.cz/search/api/v5.0",
      "view_url": "https://ndk.cz/uuid/uuid:35d64c24-9cf2-408b-9147-935f1323be20",
      "document_uuid": "ae811ecf-435d-11dd-b505-00145e5790ea",
      "volume_uuid": "b1a8ec04-435d-11dd-b505-00145e5790ea",
      "issue_uuid": "e5204673-435d-11dd-b505-00145e5790ea",
      "page_uuid": "35d64c24-9cf2-408b-9147-935f1323be20",
      "document": "Blahověst: Katolický týdenník pro Čechy, Morawany, Slowáky a Slezany",
      "volume_nr": "3",
      "volume_years": "1849",
      "issue": "18",
      "issue_type": "",
      "issue_date": "1849-04-01",
      "supplement": "",
      "page": "140",
      "page_label": "140",
      "citation": "Blahověst: Katolický týdenník pro Čechy, roč. 3 (1849), č. 18, 1. dubna 1849, str. 140"
    }
  ]
}

Poznámka: Pole debug_trace je vráceno pouze při debug=true, proto v běžné odpovědi s debug=false nebude přítomno.

Význam polí v results:

PolePopis
api_baseDetekovaná základní URL Kramerius API.
view_urlPřímý odkaz do Digitální knihovny/NDK na nalezenou stránku.
document_uuidUUID dokumentu.
volume_uuidUUID svazku nebo ročníku.
issue_uuidUUID vydání.
page_uuidUUID stránky.
documentNázev periodika nebo dokumentu.
volume_nrČíslo ročníku nebo svazku.
volume_yearsRok nebo období ročníku.
issueČíslo vydání.
issue_typeTyp vydání zadaný uživatelem a použitý pro filtraci. Pokud filtr použit nebyl, může zůstat prázdné i tehdy, když se typ vydání propsal do citation.
issue_dateDatum vydání v ISO formátu podle dostupné přesnosti (YYYY, YYYY-MM nebo YYYY-MM-DD). Pokud upstream vrátí DD.MM.YYYY nebo MM.YYYY, API jej před vrácením normalizuje.
supplementČíslo přílohy v normalizovaném formátu, pokud je k dispozici.
pageNormalizované číslo strany použité pro dohledání.
page_labelTextové označení strany vrácené Krameriem.
citationLidsky čitelná citace vhodná pro zobrazení v UI. Pokud je v Krameriu dostupný typ vydání (mods:note), může být součástí citace i bez vyplněného pole issue_type.

Poznámka k issue_uuid: u stránek z příloh (supplement) je issue_uuid normalizováno na rodičovské vydání (periodicalitem), pokud je v metadata kontextu dostupné.

Poznámka: u textových příloh může API při nedohledání přílohy v přesně zadaném čísle projít i další kandidátní čísla ve stejném ročníku a vybrat to, které přílohu skutečně obsahuje.

Sémantika selection_required

Ideální výsledek API je právě jedna jednoznačně určená stránka. V praxi se ale mohou vrátit i více shody (širší dotaz nebo nedokonalá metadata ve zdroji).

selection_required neznamená "je více výsledků". Znamená "klient musí přepnout do ručního režimu".

Stavokselection_requiredVýznam
Jednoznačný výsledek (UUID nebo přesný WD dotaz)truefalseAPI dohledalo cílovou stránku automaticky.
Více automaticky dohledaných správných výsledků (jeden stejný zdroj má více UUID nebo je na více instancích Krameria)truefalseAPI vrátilo více platných výsledků; klient může použít results[0].
Nejednoznačný výsledek (HTTP 300)falsetrueAutomatické dohledání není jednoznačné, klient musí vybrat správnou stránku z kandidátů.
Nedohledán výsledekfalsetrueAutomatické dohledání selhalo, uživatel musí pokračovat ručně (např. přes ruční prohlížení).

Doporučené chování klienta:

Chybová odpověď

Endpoint vrací chybovou odpověď ve třech praktických režimech:

HTTP 300 — manuální výběr

Endpoint nalezl více kandidátů a nelze jednoznačně určit správnou stránku. Klient musí zobrazit výběr uživateli.

{
  "ok": false,
  "error_code": "selection_required",
  "selection_required": true,
  "manual_user_message": "Bylo nalezeno více odpovídajících výsledků. Vyberte prosím správnou stránku.",
  "results": [
    {
      "api_base": "https://ndk.cz/search/api/v5.0",
      "document_uuid": "uuid:...",
      "document": "...",
      "volume_nr": "...",
      "volume_years": "...",
      "issue": "...",
      "issue_type": "...",
      "issue_date": "...",
      "supplement": "...",
      "page": "...",
      "page_label": "...",
      "citation": "...",
      "page_uuid": "uuid:...",
      "volume_uuid": "uuid:...",
      "issue_uuid": "uuid:...",
      "view_url": "https://ndk.cz/uuid/uuid:...",
      "preview_url": "https://...",
      "full_preview_url": "https://..."
    }
  ]
}

HTTP 422 — chyba dohledání

Dohledání selhalo (např. neplatný vstupní kontext stránky nebo nedostupná data zdroje). Podle typu selhání může být selection_required buď false (tvrdá chyba), nebo true (API doporučuje ruční pokračování).

{
  "ok": false,
  "error": "Položka na Wikidatech neobsahuje UUID dokumentu.",
  "error_code": "missing_document_uuid",
  "selection_required": false,
  "results": [],
  "results_meta": {
    "offset": 0,
    "batch_size": 25,
    "returned_count": 0,
    "minimum_total_count": 0,
    "has_more": false
  }
}

Pole chybové odpovědi

PolePopis
okVždy false.
errorTextový popis chyby. Přítomno u chybových odpovědí mimo větev HTTP 300 s kandidáty.
error_codeStrojově čitelný kód chyby (viz níže).
statusHTTP status kód odpovědi (stejná hodnota jako ve status line).
selection_requiredtrue, pokud klient musí nabídnout uživateli ruční výběr nebo ruční dohledání; jinak false.
results_meta.offsetOffset použité dávky výsledků.
results_meta.batch_sizeVelikost dávky výsledků vrácené endpointem.
results_meta.returned_countPočet skutečně vrácených položek v results.
results_meta.minimum_total_countMinimální jistý počet nalezených položek. Pokud je has_more: true, skutečný počet může být vyšší.
results_meta.has_moretrue, pokud existují další výsledky za aktuální dávkou.
manual_user_messageZpráva pro zobrazení uživateli. Přítomno pouze při HTTP 300.
resultsKandidáti pro manuální výběr (HTTP 300), jinak obvykle prázdné pole.
error_detailInterní detail chyby. Přítomno pouze při debug=true.
debug_traceLadící výpis průběhu. Přítomno pouze při debug=true.
failure_contextKontext selhání (vstupní payload a metadata). Přítomno pouze při debug=true.

Kódy chyb

error_codeHTTPPopis
selection_required300Nalezeno více kandidátů, vyžadován manuální výběr.
missing_required_params400Chybí povinný parametr (např. page).
invalid_wd400Neplatný formát parametru wd.
cors_origin_blocked403Origin je explicitně blokován blacklistem CORS.
cors_origin_not_allowed403Origin v CORS požadavku není na whitelistu.
wikidata_uuid_not_found404Na Wikidatech nebylo nalezeno UUID pro Kramerius.
wikidata_entity_not_found404Wikidata entita nebyla nalezena.
document_not_found404Dokument nebyl v cílové instanci nalezen.
api_base_not_found404Nepodařilo se dohledat API base pro UUID dokumentu.
upstream_not_found404Nadřazená služba nevrátila požadovaný zdroj.
all_wd_candidates_failed404Žádný kandidát z WD nevedl na použitelný výsledek.
method_not_allowed405Nepodporovaná HTTP metoda nebo GET s parametry/body.
missing_document_uuid422Wikidatový záznam neobsahuje UUID dokumentu.
page_not_found422Stránka podle zadaného čísla nebyla v dokumentu nalezena.
empty_document422Dokument nemá dostupné stránky nebo obsah.
invalid_upstream_json502Nadřazená služba vrátila neplatnou JSON odpověď.
registry_unavailable502Registr Kramerius není dostupný.

Pole kandidátů v results (HTTP 300)

Každý kandidát obsahuje stejná pole jako úspěšná odpověď (viz tabulku výše), doplněná o:

PolePopis
preview_urlURL náhledu skenu stránky.
full_preview_urlURL skenu stránky v plném rozlišení.

HTTP status kódy

HTTP statusMetodaPopis
200GETVrací dokumentaci API (pouze bez parametrů a bez body).
200POSTDohledání úspěšné (ok: true).
204OPTIONSOdpověď na preflight požadavek.
300POSTManuální výběr vyžadován — endpoint nalezl více kandidátů (selection_required: true).
400POSTNeplatný nebo neúplný vstup (missing_required_params, invalid_wd).
403GET/POST/OPTIONSCORS origin není povolen (error_code: cors_origin_not_allowed).
404POSTZdroj nebyl nalezen (wikidata_uuid_not_found, document_not_found, all_wd_candidates_failed aj.).
405*Nepodporovaná metoda nebo GET s parametry.
422POSTDohledání stránky selhalo (např. missing_document_uuid, page_not_found, empty_document).
502POSTChyba nebo nedostupnost nadřazené služby (invalid_upstream_json, registry_unavailable).

Omezení počtu výsledků

CORS konfigurace

CORS je řízen pouze environment proměnnými, takže stejný endpoint lze bezpečně použít pro web, mobil i server-to-server klienty.

ProměnnáVýchozí hodnotaPopis
KRAMERIUS_API_CORS_MODEwhitelistRežim CORS: whitelist (jen povolené originy) nebo blacklist (povol vše kromě blokovaných).
CORS_MODEwhitelistKratší alias k KRAMERIUS_API_CORS_MODE (fallback).
KRAMERIUS_API_CORS_ALLOWED_ORIGINSprázdnéČárkou oddělený whitelist originů, např. https://app.example.com,https://admin.example.com. Pokud je prázdné, CORS je vypnutý.
CORS_ALLOWED_ORIGINSprázdnéKratší alias k KRAMERIUS_API_CORS_ALLOWED_ORIGINS (fallback, když hlavní proměnná není nastavena).
KRAMERIUS_API_CORS_BLOCKED_ORIGINSprázdnéČárkou oddělený blacklist originů. Podporuje přesnou shodu i masku *.domena.tld.
CORS_BLOCKED_ORIGINSprázdnéKratší alias k KRAMERIUS_API_CORS_BLOCKED_ORIGINS (fallback).
KRAMERIUS_API_CORS_ALLOW_CREDENTIALSfalsePokud je true, odpověď vrací konkrétní origin a Access-Control-Allow-Credentials: true.
CORS_ALLOW_CREDENTIALSfalseKratší alias k KRAMERIUS_API_CORS_ALLOW_CREDENTIALS (fallback).
KRAMERIUS_API_CORS_ALLOWED_HEADERSprázdnéVolitelné doplnění povolených hlaviček (k výchozím: Content-Type, Authorization, X-Requested-With, X-Request-Id, X-Client-Version).
CORS_ALLOWED_HEADERSprázdnéKratší alias k KRAMERIUS_API_CORS_ALLOWED_HEADERS (fallback).
KRAMERIUS_API_CORS_EXPOSE_HEADERSprázdnéVolitelné hlavičky pro Access-Control-Expose-Headers.
CORS_EXPOSE_HEADERSprázdnéKratší alias k KRAMERIUS_API_CORS_EXPOSE_HEADERS (fallback).
KRAMERIUS_API_CORS_MAX_AGE600Hodnota Access-Control-Max-Age pro preflight (0 až 86400).
CORS_MAX_AGE600Kratší alias k KRAMERIUS_API_CORS_MAX_AGE (fallback).

Poznámka: pokud zapnete credentials, nepoužívejte wildcard origin *; nastavte explicitní whitelist.

Příklad konfigurace (dev)

export CORS_MODE="blacklist"
export CORS_BLOCKED_ORIGINS="https://evil.example,*.blocked.local"
export CORS_ALLOW_CREDENTIALS="0"
export CORS_ALLOWED_HEADERS="Content-Type,Authorization"
export CORS_MAX_AGE="600"

Poznámka: v režimu blacklist je CORS otevřený pro všechny originy mimo CORS_BLOCKED_ORIGINS.

Příklad konfigurace (produkce)

export CORS_MODE="blacklist"
export CORS_BLOCKED_ORIGINS="https://evil.example,https://malicious.example,*.botnet.invalid"
export CORS_ALLOW_CREDENTIALS="0"
export KRAMERIUS_API_CORS_ALLOWED_HEADERS="Content-Type,Authorization"
export KRAMERIUS_API_CORS_EXPOSE_HEADERS="X-Request-Id"
export KRAMERIUS_API_CORS_MAX_AGE="600"

Preflight odpověď při povoleném originu vrací minimálně:

CORS ověření přes curl

1) Jednoduchý GET z povoleného originu

curl -i 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Origin: https://app.example.com'

2) Preflight OPTIONS

curl -i -X OPTIONS 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Origin: https://www.daelba.eu' \
  -H 'Access-Control-Request-Method: POST' \
  -H 'Access-Control-Request-Headers: content-type'

3) Blokovaný origin

curl -i -X POST 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Origin: https://www.daelba.eu' \
  -H 'Content-Type: application/json' \
  -d '{}'
curl -i -X OPTIONS 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Origin: https://evil.example' \
  -H 'Access-Control-Request-Method: POST'
curl -i -X POST 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Origin: https://evil.example' \
  -H 'Content-Type: application/json' \
  -d '{"wd":"Q123456","page":"12"}'

Očekávání pro blokovaný origin: bez Access-Control-Allow-Origin, typicky HTTP 403 a JSON s error_code: cors_origin_blocked.

cURL příklady

Wikidatový lookup:

curl -X POST 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Content-Type: application/json' \
  -d '{
    "wd": "Q96613911",
    "page": "140",
    "volume": "3",
    "volume_years": "",
    "issue": "18",
    "issue_type": "",
    "issue_date": "1849-04-01",
    "supplement": "",
    "debug": false
  }'

Přímý UUID lookup:

curl -X POST 'https://tools.daelba.eu/kramerius/api/' \
  -H 'Content-Type: application/json' \
  -d '{
    "uuid": "35d64c24-9cf2-408b-9147-935f1323be20",
    "debug": false
  }'

Testování

Integrační test endpointu (s mockovanými externími HTTP odpověďmi):

php kramerius/tests/api-endpoint-integration-test.php

Smoke test CORS (lokální PHP server + curl):

bash kramerius/tests/cors-smoke-test.sh

Poznámka: test využívá pouze pro testovací běh environment proměnnou KRAMERIUS_HTTP_MOCK_BOOTSTRAP, která přesměruje HTTP volání na lokální mock provider.