[PR Feedback] Use JSON pointers instead of "creative" PathBufs
@@ -7,25 +7,26 @@ use actix_web::{web,
HttpRequest,
HttpResponse};
use serde_json;
-use std::{fs,
- path::{Components,
- Path,
- PathBuf}};
+use std::{borrow::Cow,
+ fs,
+ path::Path};
/// Show render context rooted at `path`
#[allow(clippy::needless_pass_by_value)] // Required by actix-web API
pub fn show(config: web::Data<config::Config>,
req: HttpRequest)
-> actix_web::Result<HttpResponse> {
- let path = req.match_info()
- .get("path")
- .map(PathBuf::from)
- .unwrap_or_default();
- let json =
- extract_data(&config.render_context_file, &path).map_err(actix_web::error::ErrorBadRequest)?;
-
- if let Some(json) = json {
- Ok(HttpResponse::Ok().json(json))
+ // A JSON pointer of "" means "everything". Pointers starting with
+ // "/" describe paths into the structure. We'll chop off any
+ // trailing "/" since that will end up looking for an item with a
+ // key of "", which we're just not going to deal with.
+ let pointer = match req.match_info().get("path") {
+ None | Some("") => Cow::Borrowed(""),
+ Some(path) => Cow::Owned(format!("/{}", path.trim_end_matches('/'))),
+ };
+ let json = read_json(&config.render_context_file).map_err(actix_web::error::ErrorBadRequest)?;
+ if let Some(value) = json.pointer(&pointer) {
+ Ok(HttpResponse::Ok().json(value))
} else {
Ok(HttpResponse::NotFound().finish())
}
@@ -33,13 +34,6 @@ pub fn show(config: web::Data<config::Config>,
////////////////////////////////////////////////////////////////////////
-fn extract_data<P>(render_context_file: P, path: P) -> Result<Option<serde_json::Value>>
- where P: AsRef<Path>
-{
- let data = read_json(render_context_file)?;
- lookup(data, path.as_ref().components())
-}
-
/// Read a file into a JSON value
fn read_json<P>(path: P) -> Result<serde_json::Value>
where P: AsRef<Path>
@@ -47,27 +41,3 @@ fn read_json<P>(path: P) -> Result<serde_json::Value>
let contents = fs::read_to_string(path)?;
serde_json::from_str(&contents).map_err(|e| e.into())
}
-
-/// Recursively descend through a JSON structure, based on the path
-/// provided in `keys`
-fn lookup(data: serde_json::Value, keys: Components) -> Result<Option<serde_json::Value>> {
- let mut result = data;
- for component in keys {
- let key: &str = &component.as_os_str().to_string_lossy();
-
- // For arrays, try to coerce key to an integer and do a lookup
- // that way
- let lookup_result = if result.is_array() {
- result.get(key.parse::<usize>()?)
- } else {
- result.get(key)
- };
-
- if let Some(stuff) = lookup_result {
- result = stuff.clone(); // eww
- } else {
- return Ok(None);
- }
- }
- Ok(Some(result))
-}
