Skip to content

Commit

Permalink
runtimes/core: use path param types
Browse files Browse the repository at this point in the history
This is more robust now that we've improved the type parser
  • Loading branch information
eandre committed Jun 11, 2024
1 parent 08de93e commit e768135
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 40 deletions.
29 changes: 11 additions & 18 deletions runtimes/core/src/api/schema/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ pub struct SchemaUnderConstruction {
body: Option<usize>,
query: Option<usize>,
header: Option<usize>,
path: Option<usize>,
rpc_path: Option<meta::Path>,
}

Expand All @@ -59,11 +58,7 @@ impl SchemaUnderConstruction {
body: self.body.map(|v| Body::new(reg.schema(v))),
query: self.query.map(|v| Query::new(reg.schema(v))),
header: self.header.map(|v| Header::new(reg.schema(v))),
path: self
.rpc_path
.as_ref()
.map(|mp| Path::from_meta(mp, self.path.map(|v| reg.schema(v))))
.transpose()?,
path: self.rpc_path.as_ref().map(Path::from_meta).transpose()?,
})
}
}
Expand All @@ -88,7 +83,6 @@ impl EncodingConfig<'_, '_> {
body: None,
query: None,
header: None,
path: None,
rpc_path: self.rpc_path.cloned(),
});
};
Expand All @@ -114,33 +108,35 @@ impl EncodingConfig<'_, '_> {
let mut body: Option<jsonschema::Struct> = None;
let mut query: Option<jsonschema::Struct> = None;
let mut header: Option<jsonschema::Struct> = None;
let mut path: Option<jsonschema::Struct> = None;

for f in &st.fields {
// If it's a path field, skip it. We handle it separately in Path::from_meta.
if path_fields.contains(f.name.as_str()) {
continue;
}

let (name, mut field) = self.registry_builder.struct_field(f)?;
combined.fields.insert(name.to_owned(), field.clone());

// Resolve which location the field should be in.
let is_path_field = path_fields.contains(f.name.as_str());
let loc = f.wire.as_ref().and_then(|w| w.location.as_ref());
let wire_loc = match (loc, is_path_field) {
(_, true) => WireLoc::Path,
(None, false) => self
let wire_loc = match loc {
None => self
.default_loc
.with_context(|| format!("no location defined for field {}", f.name))?
.into_wire_loc(),
(Some(schema::wire_spec::Location::Header(hdr)), false) => {
Some(schema::wire_spec::Location::Header(hdr)) => {
WireLoc::Header(hdr.name.clone().unwrap_or_else(|| f.name.clone()))
}
(Some(schema::wire_spec::Location::Query(_)), false) => WireLoc::Query,
Some(schema::wire_spec::Location::Query(_)) => WireLoc::Query,
};

// Add the field to the appropriate struct.
let (dst, name_override) = match wire_loc {
WireLoc::Body => (&mut body, None),
WireLoc::Query => (&mut query, None),
WireLoc::Header(s) => (&mut header, Some(s)),
WireLoc::Path => (&mut path, None),
WireLoc::Path => unreachable!(),
};
field.name_override = name_override;

Expand Down Expand Up @@ -170,7 +166,6 @@ impl EncodingConfig<'_, '_> {
body: body.map(&mut build),
query: query.map(&mut build),
header: header.map(&mut build),
path: path.map(&mut build),
rpc_path: self.rpc_path.cloned(),
})
}
Expand Down Expand Up @@ -397,7 +392,6 @@ pub fn request_encoding(
body: None,
query: None,
header: None,
path: None,
rpc_path: Some(rpc_path.clone()),
},
}]);
Expand Down Expand Up @@ -438,7 +432,6 @@ pub fn response_encoding(
body: None,
query: None,
header: None,
path: None,
rpc_path: None,
});
};
Expand Down
41 changes: 19 additions & 22 deletions runtimes/core/src/api/schema/path.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::ptr;
Expand All @@ -15,31 +14,21 @@ use crate::api::jsonschema::Basic;
use crate::api::schema::JSONPayload;
use crate::api::{jsonschema, APIResult};
use crate::encore::parser::meta::v1 as meta;
use crate::encore::parser::meta::v1::path_segment::ParamType;

/// The URL path to an endpoint, e.g. ("/foo/bar/:id").
#[derive(Debug, Clone)]
pub struct Path {
/// The path segments.
segments: Vec<Segment>,
dynamic_segments: Vec<jsonschema::Basic>,
dynamic_segments: Vec<Basic>,

/// The capacity to use for generating requests.
capacity: usize,
}

impl Path {
pub fn from_meta(
path: &meta::Path,
schema: Option<jsonschema::JSONSchema>,
) -> anyhow::Result<Self> {
let empty_fields = jsonschema::Struct {
fields: HashMap::new(),
};
let fields = match &schema {
Some(schema) => schema.root(),
None => &empty_fields,
};

pub fn from_meta(path: &meta::Path) -> anyhow::Result<Self> {
let mut segments = Vec::with_capacity(path.segments.len());
for seg in &path.segments {
use meta::path_segment::SegmentType;
Expand All @@ -49,14 +38,22 @@ impl Path {
}
SegmentType::Param => {
let name = &seg.value;
let typ = match fields.fields.get(name) {
Some(field) => match &field.value {
jsonschema::BasicOrValue::Basic(typ) => *typ,
_ => anyhow::bail!("invalid field type in request schema"),
},
// If the segment doesn't exist in the schema it's because the endpoint is raw.
// Treat this as a string.
None => Basic::String,
let typ = match ParamType::try_from(seg.value_type)
.context("invalid path parameter type")?
{
ParamType::String => Basic::String,
ParamType::Bool => Basic::Bool,
ParamType::Uuid => Basic::String,
ParamType::Int
| ParamType::Int8
| ParamType::Int16
| ParamType::Int32
| ParamType::Int64
| ParamType::Uint
| ParamType::Uint8
| ParamType::Uint16
| ParamType::Uint32
| ParamType::Uint64 => Basic::Number,
};

segments.push(Segment::Param {
Expand Down

0 comments on commit e768135

Please sign in to comment.