I'm using the Iron web framework (for the Rust programming language) in an application and I have a path exposed to POST JSON data at using the Router crate.
It works but I have to percent encode my JSON data and append it as a string to the end of my HTTP POST request - which works but is a bit tedious and I'd like to eventually POST raw image files.
I'd like to be able to do something along the lines of the following curl command:
curl -v -i --header "Content-Type: application/json" -X POST -d @some_local_json_file.json http://my_server_ip_address:3000/example_path/post/json_object_here
I'm currently getting a HTTP/1.1 404 Not Found
error:
curl -v -i --header "Content-Type: application/json" -X POST -d @some_local_json_file.json http://my_server_ip_address:3000/example_path/post/json
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying my_server_ip_address...
* Connected to my_server_ip_address (my_server_ip_address) port 3000 (#0)
> POST /example_path/post/json HTTP/1.1
> Host: my_server_ip_address:3000
> User-Agent: curl/7.45.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 2354
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
HTTP/1.1 100 Continue
* We are completely uploaded and fine
< HTTP/1.1 404 Not Found
HTTP/1.1 404 Not Found
< Date: Mon, 28 Dec 2015 22:44:03 GMT
Date: Mon, 28 Dec 2015 22:44:03 GMT
< Content-Length: 0
Content-Length: 0
<
* Connection #0 to host my_server_ip_address left intact
The meat of my main
function looks like:
fn main() {
// create the router
let mut router = Router::new();
router.post("/example_path/post/:json", post_to_documents);
let mut mount = Mount::new();
// mount the router
mount.mount("/", router);
Iron::new(mount).http("0.0.0.0:3000").unwrap();
}
And the post_to_documents
listed above is along the lines of:
fn post_to_documents(req: &mut Request) -> IronResult<Response>
{
let document_url_encoded = req.extensions.get::<Router>()
.unwrap()
.find("json")
.unwrap_or("/");
// Just return Ok
Ok(Response::with((status::Ok, "Ok")))
}
I want to have the JSON data in the document_url_encoded
variable. (I guess it's poorly named since it would not be url/percent encoded in this case)
You have a misunderstanding of how HTTP POST works, or at least how it works when exposed through Iron and friends. A POST request is sent in a separate part of the request from the URL / path information, and Iron exposes these two concepts separately.
You are using Iron Router to map paths to functions and to extract simple parameters from the path. You need to also use Iron Body Parser to extract data from the POST body. It will automatically parse JSON for you, as well as give access to the raw binary data.
extern crate iron;
extern crate router;
extern crate mount;
extern crate bodyparser;
use iron::prelude::*;
use iron::status;
use router::Router;
use mount::Mount;
fn post_to_documents(req: &mut Request) -> IronResult<Response> {
match req.extensions.get::<Router>().and_then(|r| r.find("json")) {
Some(name) => println!("The name was {:?}", name),
None => println!("There was no name!"),
}
match req.get::<bodyparser::Json>() {
Ok(Some(json_body)) => println!("Parsed body:\n{:?}", json_body),
Ok(None) => println!("No body"),
Err(err) => println!("Error: {:?}", err)
}
Ok(Response::with((status::Ok, "Ok")))
}
fn main() {
let mut router = Router::new();
router.post("/documents/post/:json", post_to_documents, "new_document");
let mut mount = Mount::new();
mount.mount("/", router);
Iron::new(mount).http("0.0.0.0:3000").unwrap();
}
I have a file called input.json
:
{"key": "value"}
And I run this command:
curl -v -i --header "Content-Type: application/json" -X POST -d @input.json http://127.0.0.1:3000/documents/post/awesome
With this output from the server:
The name was "awesome"
Parsed body:
Object({"key": String("value")})
I cannot explain why you are getting a 404 error.
This was done with