Backend
You will now implement the actual logic of this API: the image filter.
✅ Start of with a new import at the top of your src/main.rs
file.
You later need to specify the image's mime type:
use fastly::mime;
✅ In your main
function match for a POST
request on the /image
path and call a handler function.
match (req.get_method(), req.get_path()) {
// (cut)
(&Method::POST, "/image") => convert_image(req),
✅ Create this new handler function, taking in the request and returning a response or an error.
pub fn convert_image(mut req: Request) -> Result<Response, Error> {
// (to be filled in)
}
✅ Next you need to get the required data from the request. Start with the filter name from the query.
let filter_str = req.get_query_parameter("filter").unwrap();
let filter = filter_str.parse().unwrap();
✅ Now you can check and read the body from the request.
if !req.has_body() {
return Ok(
Response::from_status(StatusCode::BAD_REQUEST)
.with_body_text_plain("missing image")
);
}
let body = req.take_body();
let body = body.into_bytes();
✅ You can decode the image data using the image
crate, which is re-exported from rustagram
.
The documentation is available at docs.rs/image.
Import the modules using the following lines on the top of your src/main.rs
file.
use rustagram::image;
use rustagram::image::io::Reader;
use rustagram::RustagramFilter;
✅ Now use the Reader
type to load the image from the buffer.
let img = Reader::new(Cursor::new(body))
.with_guessed_format()
.unwrap();
let img = img.decode().unwrap();
✅ Currently Fastly enforces very small resource limits (memory usage, computation time), so you need to limit the work the application does if you want to deploy it. The easiest is to scale down the image before applying an image filter.
let img = img.thumbnail(500, 500);
Locally you can skip this if you want. Larger images just take longer to process.
✅ Now that you have the image and a filter you can apply this filter as before. Instead of writing the result to a file it should be written to a buffer in PNG format.
let out = img.to_rgba8().apply_filter(filter);
let mut bytes: Vec<u8> = Vec::new();
out.write_to(&mut Cursor::new(&mut bytes), image::ImageOutputFormat::Png)?;
✅ The buffer containing the final image can now be returned as the response. Don't forget to set the correct content type.
Ok(Response::from_status(StatusCode::OK)
.with_body(bytes)
.with_content_type(mime::IMAGE_PNG))
✅ Run the project locally:
fastly compute serve
Your application should be reachable at http://127.0.0.1:7676/.
✅ In another terminal you can use curl
to send an image and save the converted file.
curl http://127.0.0.1:7676/image?filter=valencia -X POST -H "Content-Type: application/octet-stream" -T skyline.jpg -o result.png
In the next chapter you learn how to build a small web frontend and serve that along your image filter application.