A reusable, spec-compliant OAI-PMH 2.0 implementation for Rust.
oai_pmh_rs::core- Transport-agnostic OAI-PMH protocol engine
- Request validation, list semantics, resumption token lifecycle, XML response body/envelope helpers
OaiProvidertrait for repository-specific behavior
oai_pmh_rs::transport::actix(feature-gated)- Actix GET/POST handlers
text/xmlresponses, optional gzip (Accept-Encoding: gzip)- Transient internal failures mapped to HTTP
503 Service Unavailable+Retry-After
- Full verb support:
Identify,ListMetadataFormats,ListSets,GetRecord,ListIdentifiers,ListRecords - Protocol error semantics (
badVerb,badArgument,badResumptionToken, etc.) - Core-owned list semantics:
- date filtering (
from/until) - cursor and continuation behavior
- token encoding/decoding (including backward-compatible decode for legacy tokens missing optional fields)
- date filtering (
- XML envelope generation helpers
- Optional Actix integration via
actixfeature
- Default features: none
actix: enables Actix adapter (transport::actix) and gzip response support
Implement OaiProvider and call handle_oai_request.
use std::collections::HashMap;
use oai_pmh_rs::core::handle_oai_request;
// params normally come from query/body parsing.
let mut params = HashMap::new();
params.insert("verb".to_string(), "Identify".to_string());
// provider: impl OaiProvider
// let body_xml = handle_oai_request(¶ms, &provider).await?;Provider responsibilities in 0.2.x:
- Record and set operations:
identify,list_metadata_formats,list_sets,get_record_header,get_record_metadata - List source primitives (core builds pagination/tokens on top):
list_source_count(metadata_prefix, set)list_source_batch(metadata_prefix, set, offset, limit)list_entry_header(entry)list_entry_disseminatable(entry, metadata_prefix)
- Internal error classification:
classify_internal_error
Useful helpers:
handle_oai_requestencode_resumption_token/decode_resumption_tokensuccess_document/error_document
[dependencies]
actix-web = "4"
oai-pmh-rs = { version = "0.2", features = ["actix"] }use actix_web::{web, App, HttpServer};
use oai_pmh_rs::transport::actix::{oai_get, oai_post, AppState};
// provider: impl OaiProvider + Clone
let state = web::Data::new(AppState {
provider,
retry_after_seconds: 30,
});
HttpServer::new(move || {
App::new()
.app_data(state.clone())
.service(
web::resource("/")
.route(web::get().to(oai_get))
.route(web::post().to(oai_post)),
)
});Expected HTTP behavior with the Actix adapter:
- Successful protocol responses: HTTP
200withtext/xml; charset=utf-8 - Protocol errors (
badArgument,badVerb, etc.): OAI XML error response with HTTP200 - Transient internal failures: HTTP
503withRetry-After - Gzip: enabled when
Accept-Encodingincludesgzip
0.2.x moves list/token orchestration into core and changes OaiProvider accordingly.
Removed from provider:
list_records(...)decode_resumption_token(...)
Added to provider:
- associated type:
type ListEntry list_source_count(...)list_source_batch(...)list_entry_header(...)list_entry_disseminatable(...)- optional override:
include_complete_list_size(...)
Core now provides the canonical token helpers:
encode_resumption_token(...)decode_resumption_token(...)
examples/core_minimal.rs— core-only in-memory provider exampleexamples/actix_server.rs— minimal Actix integration example
Both compile with:
cargo check --examples --all-featuresRust 1.80+
Apache License 2.0