Add support for emitting Prefer header
This commit is contained in:
@@ -10,7 +10,7 @@ pub enum ContainerType {
|
||||
}
|
||||
|
||||
impl ContainerType {
|
||||
pub fn as_named_node(&self) -> NamedNodeRef<'_> {
|
||||
pub fn as_named_node_ref(&self) -> NamedNodeRef<'_> {
|
||||
match self {
|
||||
ContainerType::Basic => vocab::ldp::BASIC_CONTAINER,
|
||||
ContainerType::Direct => vocab::ldp::DIRECT_CONTAINER,
|
||||
@@ -18,7 +18,7 @@ impl ContainerType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_named_node(node: NamedNodeRef<'_>) -> Option<Self> {
|
||||
pub fn from_named_node_ref(node: NamedNodeRef<'_>) -> Option<Self> {
|
||||
match node {
|
||||
vocab::ldp::BASIC_CONTAINER => Some(ContainerType::Basic),
|
||||
vocab::ldp::DIRECT_CONTAINER => Some(ContainerType::Direct),
|
||||
|
||||
@@ -3,4 +3,3 @@ use reqwest_middleware::reqwest::header::HeaderName;
|
||||
pub const X_STATE_TOKEN: HeaderName = HeaderName::from_static("x-state-token");
|
||||
pub const X_IF_STATE_TOKEN: HeaderName = HeaderName::from_static("x-if-state-token");
|
||||
pub const PREFER: HeaderName = HeaderName::from_static("prefer");
|
||||
pub const PREFERENCE_APPLIED: HeaderName = HeaderName::from_static("preference-applied");
|
||||
|
||||
+5
-3
@@ -2,24 +2,26 @@
|
||||
|
||||
mod container;
|
||||
mod error;
|
||||
pub mod header;
|
||||
mod header;
|
||||
pub mod middleware;
|
||||
pub mod model;
|
||||
mod prefer;
|
||||
mod rdf_source;
|
||||
mod resource;
|
||||
pub mod traverse;
|
||||
mod traverse;
|
||||
pub mod vocab;
|
||||
|
||||
pub use http;
|
||||
pub use oxigraph;
|
||||
pub use reqwest_middleware;
|
||||
pub use reqwest_middleware::reqwest;
|
||||
|
||||
pub use container::ContainerType;
|
||||
pub use error::{Error, Result};
|
||||
pub use prefer::{Preference, header_for_preferences};
|
||||
pub use rdf_source::{
|
||||
RdfSource, RdfSourceUpdateRequest, RdfSourceUpdateResponse, SerializationOptions,
|
||||
};
|
||||
pub use resource::{
|
||||
Resource, ResourceRequest, ResourceRequestBuilder, ResourceType, ResponseFormat,
|
||||
};
|
||||
pub use traverse::Traverse;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! This module contains functionality related to the content of RDF documents.
|
||||
|
||||
mod dataset;
|
||||
#[cfg(feature = "keyed")]
|
||||
mod keyed_dataset;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
use crate::vocab;
|
||||
use http::{HeaderMap, HeaderValue};
|
||||
use oxigraph::model::{NamedNode, NamedNodeRef};
|
||||
|
||||
/// [Request preferences](https://www.w3.org/TR/ldp/#prefer-parameters)
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Preference {
|
||||
Containment,
|
||||
Membership,
|
||||
MinimalContainer,
|
||||
Other(NamedNode),
|
||||
}
|
||||
|
||||
impl Preference {
|
||||
pub fn as_named_node_ref(&self) -> NamedNodeRef<'_> {
|
||||
match self {
|
||||
Preference::Containment => vocab::ldp::PREFER_CONTAINMENT,
|
||||
Preference::Membership => vocab::ldp::PREFER_MEMBERSHIP,
|
||||
Preference::MinimalContainer => vocab::ldp::PREFER_MINIMAL_CONTAINER,
|
||||
Preference::Other(preference) => preference.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header_for_preferences<'a, I, J>(include: I, omit: J) -> crate::Result<HeaderMap>
|
||||
where
|
||||
I: IntoIterator<Item = &'a Preference>,
|
||||
J: IntoIterator<Item = &'a Preference>,
|
||||
{
|
||||
let include_str = include
|
||||
.into_iter()
|
||||
.map(|preference| preference.as_named_node_ref().as_str().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
let omit_str = omit
|
||||
.into_iter()
|
||||
.map(|preference| preference.as_named_node_ref().as_str().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
let mut value = String::from("return=representation");
|
||||
|
||||
if !include_str.is_empty() {
|
||||
value = format!("{value}; include=\"{include_str}\"");
|
||||
}
|
||||
|
||||
if !omit_str.is_empty() {
|
||||
value = format!("{value}; omit=\"{omit_str}\"");
|
||||
}
|
||||
|
||||
let header_value = HeaderValue::from_str(&value)
|
||||
.expect("Failed to produce Prefer header value");
|
||||
|
||||
Ok(HeaderMap::from_iter([(
|
||||
crate::header::PREFER,
|
||||
header_value,
|
||||
)]))
|
||||
}
|
||||
+30
-5
@@ -1,6 +1,6 @@
|
||||
use crate::container::ContainerType;
|
||||
use crate::rdf_source::RdfSource;
|
||||
use crate::vocab;
|
||||
use crate::{Preference, prefer, vocab};
|
||||
use bytes::Bytes;
|
||||
use futures::Stream;
|
||||
use http::Method;
|
||||
@@ -41,6 +41,8 @@ pub struct ResourceRequestBuilder {
|
||||
follow_described_by: bool,
|
||||
validate_support: bool,
|
||||
formats: Vec<RdfFormat>,
|
||||
include_preferences: Vec<Preference>,
|
||||
omit_preferences: Vec<Preference>,
|
||||
}
|
||||
|
||||
impl ResourceRequestBuilder {
|
||||
@@ -60,6 +62,8 @@ impl ResourceRequestBuilder {
|
||||
follow_described_by: true,
|
||||
validate_support: true,
|
||||
formats: Vec::new(),
|
||||
include_preferences: Vec::new(),
|
||||
omit_preferences: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +115,18 @@ impl ResourceRequestBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Include a representation preference according to [section 7.2](https://www.w3.org/TR/ldp/#prefer-parameters).
|
||||
pub fn include_preference(mut self, preference: Preference) -> Self {
|
||||
self.include_preferences.push(preference);
|
||||
self
|
||||
}
|
||||
|
||||
/// Omit a representation preference according to [section 7.2](https://www.w3.org/TR/ldp/#prefer-parameters).
|
||||
pub fn omit_preference(mut self, preference: Preference) -> Self {
|
||||
self.omit_preferences.push(preference);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the request.
|
||||
pub fn build(self) -> ResourceRequest {
|
||||
ResourceRequest { builder: self }
|
||||
@@ -290,6 +306,15 @@ impl ResourceRequest {
|
||||
let mut request_builder = self.builder.client.get(url_to_get);
|
||||
request_builder = self.add_media_types(request_builder);
|
||||
|
||||
if !self.builder.include_preferences.is_empty() || !self.builder.omit_preferences.is_empty()
|
||||
{
|
||||
let header = prefer::header_for_preferences(
|
||||
&self.builder.include_preferences,
|
||||
&self.builder.omit_preferences,
|
||||
)?;
|
||||
request_builder = request_builder.headers(header);
|
||||
}
|
||||
|
||||
response = request_builder.send().await?.error_for_status()?;
|
||||
|
||||
if self.builder.validate_support {
|
||||
@@ -335,20 +360,20 @@ pub enum ResourceType {
|
||||
}
|
||||
|
||||
impl ResourceType {
|
||||
pub fn as_named_node(&self) -> NamedNodeRef<'_> {
|
||||
pub fn as_named_node_ref(&self) -> NamedNodeRef<'_> {
|
||||
match self {
|
||||
ResourceType::NonRdfSource => vocab::ldp::NON_RDF_SOURCE,
|
||||
ResourceType::RdfSource(None) => vocab::ldp::RDF_SOURCE,
|
||||
ResourceType::RdfSource(Some(container_type)) => container_type.as_named_node(),
|
||||
ResourceType::RdfSource(Some(container_type)) => container_type.as_named_node_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_named_node(node: NamedNodeRef<'_>) -> Option<Self> {
|
||||
pub fn from_named_node_ref(node: NamedNodeRef<'_>) -> Option<Self> {
|
||||
match node {
|
||||
vocab::ldp::NON_RDF_SOURCE => Some(ResourceType::NonRdfSource),
|
||||
vocab::ldp::RDF_SOURCE => Some(ResourceType::RdfSource(None)),
|
||||
_ => {
|
||||
let container_type = ContainerType::from_named_node(node);
|
||||
let container_type = ContainerType::from_named_node_ref(node);
|
||||
if container_type.is_some() {
|
||||
Some(ResourceType::RdfSource(container_type))
|
||||
} else {
|
||||
|
||||
@@ -17,4 +17,11 @@ pub mod ldp {
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/ns/ldp#DirectContainer");
|
||||
pub const INDIRECT_CONTAINER: NamedNodeRef<'_> =
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/ns/ldp#IndirectContainer");
|
||||
|
||||
pub const PREFER_CONTAINMENT: NamedNodeRef<'_> =
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/ns/ldp#PreferContainment");
|
||||
pub const PREFER_MEMBERSHIP: NamedNodeRef<'_> =
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/ns/ldp#PreferMembership");
|
||||
pub const PREFER_MINIMAL_CONTAINER: NamedNodeRef<'_> =
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/ns/ldp#PreferMinimalContainer");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user