Glossary
Domain and technical terms you meet when using ddb. For the option reference
see the README and the full cookbook in Usage.md.
ddb targets the DDB v2 API (https://api.deutsche-digitale-bibliothek.de/2).
Its read routes — search, item, version — are public: no API key.
The DDB and its data
Deutsche Digitale Bibliothek (DDB). Germany’s national aggregator for digitised cultural and scientific heritage. It does not hold objects itself; it harvests metadata from ~500 partner institutions (archives, libraries, museums, research bodies) and offers one shared search across them.
Object / item. A single catalogued thing — a book, image, archival record,
piece of sheet music, film, audio recording, etc. Identified by a 32-character
id of upper-case letters and digits (e.g. TNPFDKO2VDGBZ72RWC6RKDNZYZQZP3XK),
the value in a search result’s id and the argument to ddb item. Surrounding
whitespace is ignored; any other id is rejected before a request, by the CLI and
the library alike.
Institution / provider. A data partner that contributes objects. There is no
dedicated institutions command in this CLI; filter or aggregate by provider
through the provider_fct facet instead (--facet provider_fct, or
--filter provider_fct:"…").
Sector (Sparte). The cultural sector an object’s provider belongs to, exposed
as the sector_fct facet with codes sec_01..sec_07: Archive, Library,
Monument protection, Research, Media, Museum, Other.
Search
v2 = Solr passthrough. In v2, ddb search is a thin wrapper over the DDB’s
Apache Solr index (GET /2/search/index/{collection}/{requestHandler}, by
default search/select). Your options map onto native Solr query parameters and
the response is native Solr JSON, not a DDB-curated envelope. --handler picks
another request handler, but only handlers that return Solr’s standard response
envelope (numFound, docs) are supported — select does; one that answers in another
shape (a real-time get, say) fails with an error naming the handler.
There is no fallback for other shapes.
Solr / Lucene query syntax. search queries use bare keywords, "quoted
phrases", boolean AND/OR/NOT, field-scoped terms (title:Faust), ranges,
and *:* to match every document.
q (the query). The search term(s). Required; pass '*:*' to browse all
objects. ddb search caps results at --rows 10 by default; the library’s
search() sends the same default (DEFAULT_SEARCH_ROWS).
rows / start. --rows is the page size (Solr rows); --offset is how many
leading documents to skip (Solr start). Together they page a result set. An offset at
or past numFound is not an error upstream (an empty docs); the CLI notes it on stderr.
Response shape. A Solr response has four parts you care about:
| Path | What it is |
|---|---|
response.numFound |
total hits for the query — read this for “how many match?” |
response.start |
offset of the first returned doc (the --offset you paged to) |
response.docs[] |
this page of documents (each has an id, plus Solr fields) |
facet_counts.facet_fields.<field> |
facet values + counts, when --facet was used |
Document fields. Each docs[] entry carries the item id plus many Solr
fields — commonly label / title (display text), type (media-type codes),
objecttype, place / place_fct, provider / provider_fct, preview
(thumbnail URL), license. Fields vary by object; project what you need with jq.
Facet. A field the index can group and count by — object type, place,
provider, language, sector, time. --facet <field> asks Solr to return value
counts for that field, in facet_counts.facet_fields.<field> as a flat array
[value, count, value, count, …]. The array can include values with count 0, and
values are delivered as the institutions wrote them (place_fct has München next to
München, Oktoberfest).
*_fct fields. The DDB’s facet field names end in _fct. The common ones:
| Field | Facets by | Value form |
|---|---|---|
type_fct |
media type | codes like mediatype_002 (see below) |
objecttype_fct |
object type | words (Druckgraphik, …) |
place_fct |
place | place names |
provider_fct |
contributing institution | provider names |
sector_fct |
cultural sector | sec_01..sec_07 |
language_fct |
language | language codes |
keywords_fct |
subject keywords | words |
begin_time / end_time |
time period | day numbers, not years: 660725 = 1 Jan 1810 (Python date.toordinal() + 1) |
mimetype_fct |
media MIME type | MIME types |
There is no time_fct and no federal-state facet: time_fct and state_fct are
undefined fields, and using one fails with HTTP 500 (exit 1).
The type_fct codes, as labelled by the objects’ item.media value (sampled
2026-09-15): mediatype_001 audio, mediatype_002 image, mediatype_003 text,
mediatype_005 video, mediatype_007 unknown (no digitised media, metadata only),
mediatype_010 3D.
--facet vs. --filter. --facet type_fct asks Solr to return counts for
that field (so you can see what to narrow to). --filter takes a raw Solr
filter query (fq) that restricts the result set, e.g.
--filter place_fct:"Berlin" or --filter type_fct:mediatype_002. Repeat
--filter to AND several constraints; express OR inside one fq
(--filter 'place_fct:("Berlin" OR "Dessau")').
sort. Solr sort syntax: <field> asc|desc, e.g. --sort "score desc"
(relevance, the default when omitted) or --sort "id asc". Comma-separate for
tie-breakers (--sort "score desc, id asc").
fields (fl). --fields id,label,type restricts each returned document to
those fields (Solr fl) — the cleanest way to tame verbose docs.
Item components
Item components. ddb item <id> --part <component> fetches one component of an
object. Most are JSON; a few are served as XML or a plain file and are printed
raw (so > file.xml and piping keep them intact):
Component (--part) |
What it is | Format |
|---|---|---|
view (default) |
the data set a DDB frontend object page is built from — the friendliest view | JSON |
aip |
the Archive Information Package (the full record) | JSON |
edm |
the Europeana Data Model record — the standardised, interoperable profile the DDB shares with Europeana | RDF/XML |
binaries |
related binary files (thumbnails, media) with their URLs | JSON |
children / parents |
the direct children one level down / the whole chain up, starting with the object itself and ending with its institution (finding aids, multi-part works) | JSON |
source |
the ingest source metadata | JSON |
source-description |
a description of the source record | JSON |
source-record |
the raw provider record (METS/MODS, LIDO, MARCXML, …); for a sub-item (a book section, an archive unit) often its ancestor’s whole record, with a note naming it | XML |
iiif |
the IIIF Presentation manifest (only where the object has one) | JSON |
citation |
a citation/quote file for a newspaper issue (only where applicable) | BIB file |
--part childrenalso accepts--rows/--offsetfor paging a large child set.--lang <code>sets the preferred label language forview/aip/edm/binaries/source/source-description; an object without a record in that language answers404(seen for--lang en). Any other part ignores these upstream, so the CLI and the library reject them there before a request.
Auth & rights
No API key. The read routes this CLI uses are public — search, item and
version all work anonymously. A 403 is therefore unusual and means --base-url
was pointed at an authenticated endpoint, or the specific item component is
access-restricted — not “you need a key”.
CC0 1.0. The Creative Commons “no rights reserved” public-domain dedication. The DDB API returns metadata exclusively under CC0 — freely reusable, no attribution required.
Rights statement / Lizenzkorb. The DDB’s “license basket”: the fixed set of
rights notices an institution may attach to a digital object’s media (image,
audio, video) — CC0, CC BY, CC BY-SA, Public Domain Mark, various In Copyright
/ Rights Reserved statements. Object media (not downloaded by this CLI) can
therefore be more restricted than the CC0 metadata — always check the individual
object’s rights before reusing its media: in view the media licence URI is
item.license.resource (item.rights is often empty), in binaries it is each
file’s kind. See DATA_LICENSE.md.
CLI / technical
Exit codes. 0 success · 2 usage error (bad flag, wrong-length id) · 4
not found · 6 network failure · 1 other API/runtime error. See
Usage.md.
Log record. Every diagnostic line the CLI writes to stderr: a timestamp, a level
(ERROR, WARN, INFO) and a topic ddb.<area>, as text (log4j style) or with
--log-format jsonl as one JSON object per line. The areas: cli (usage errors,
commander’s messages, unexpected errors), api (the API’s answers: an error status, the
paging and ancestor notes, and a malformed answer — bad JSON, the wrong shape, an HTML
page instead of a version), http (the connection, the cleartext warning, and one WARN per retry before it waits) and output
(the -o file, stdout failures). A record is always one line; control characters in it
are escaped.
Cross-origin credential stripping. The read routes send no credentials, but if
you inject one via a header and the API ever redirects to a different host, the
client drops every header you added (Authorization, Proxy-Authorization,
Cookie, X-API-Key, any token header) before following, so none is leaked to
another origin. A redirect to the same origin (scheme, host and port), with a relative or
an absolute Location, keeps them. A user:password@ in --base-url is sent as an
Authorization header that follows the same rule, never inside the URL, and userinfo in
a Location is ignored. A library user’s own transport must not follow redirects itself
(HttpRequest.redirect is "manual"); one that does sends those headers to the other host
before the client can intervene, which it cannot prevent.