I’ve got a Rocket to ride…. seriously

Quick recap — Rust and Mongodb

In my last post, I presented a simple and truncated explanation of MongoDB use from Rust. If the very Rust specific match xxx {} and the async/await are removed then the code mirrors closely to the implementation in python. The biggest difference is that instead of {“$match”: { field: value}} there is a doc! {“$match”:{“name”: “Upper West Side”}}, where doc! is what is called a macro in Rust (a short-hand to reduce code). If one were to want to serialize/deserialize the BSON retrieved from MongoDB in Rust you’d use the serde (serialization/deserialization) crate.

This matches the data structure within the Atlas collection:

View of the restaurants collection from Compass

I excluded the coordinates and marked it @todo. Using the structure was a new experience, seeing as I haven’t racked up the kilometrage in Rust. Working with Rust makes me wish I remembered more of my experience in C, but there is also to the paradigm of Traits to learn when progressing with Rust.

For newbies only*: In Rust, objects are made manifest by taking a data struct and adding to the struct traits. For example, my Restaurant struct has no default conversion to a string for display. To add that there needs to be a Display trait attached to the structure as follows:

One disappointment is that you can’t take an existing external struct and add a trait on directly, the gestalt of Rust is composition over inheritance, and coming from OO in Java or JS that is the mental shock of sorts. Then again I am a newbie to Rust and you are all riding along with me on this trip. If I persist long enough I’ll overcome it, although even the documentation style in Rust is foreign.

Rocket: a web framework for Rust

So…

ווי איז ראַקעט

What is Rocket?

Rocket is the beginning of a web-application system, analogous to Node Express. It isn’t quite new and shiny and lacks the ecosystem of sophisticated GUI like Material for React/Flutter, but like Flash Gordon (cf above) it is capable of quite a bit. The snippet of code below shows how to set up Mongodb with Rocket. It is based on a couple of trial-and-error experiments in integrating the two together since the documentation and Dr. Google was less than forthcoming. First, it is important to understand how a Rocket application works. The documentation at rocket.rs and the GitHub for the project. I started by looking at the fairings and database projects in the examples. So what is a fairing? Despite the formal definition, in the context of Rocket a fairing is a way to create the middleware for a Rocket application.

In Rocket a fairing is the implementation of middle-ware

Ready to ignite

Rocket: as easy as 1–2–3 liftoff?

There is simple logic in a basic Rocket + Mongo application:

  • Create a mongo Client with the sync MongoDB driver
  • Load the Client into Rocket::Build with a staging function (doesn’t need to be called stage), but the function can not be asynchronous.
  • Attach the staging function to rocket with an attach
    [launch]
    fn rocket() -> _ { rocket::build().attach( module_name.stage() )
  • Build endpoints or routes that pull the Client for their queries

Why can’t I use the async driver?

In my example, fn init() -> Option<Client> is not async and can not be async if I want to call it from fn stage. Calling an async function yields a Future and the Rocket::Build won’t accept that:

An async stage has no future.

The impermissibility of an async function echoes back to the creation of the Client. The async driver requires that the creation of the Client be in an async block, so just use the sync client and everything falls into place. Unfortunately, that wasn’t clear to me for far too long.

Passing the Client to the Rocket::Build has one trick: Putting the client in a Box (locking it into an address in memory) then using Rocket<Build>::manage to put it into the State.

The below are examples of two endpoints (or routes). The code is fairly simple because the queries are simple. Like any good web library, you can also have calls that take parameters. Unfortunately, the documentation is a bit murky about optional parameters or using a ?paramA=xxxx&paramB=yyyyy. A simple REST type call /mongo/restaurants/neighborhood/cuisines call is possible but if the cuisines parameter is missing then the call isn’t matched up properly to the function and a 404 error is thrown.

Mission not accomplished

Probably a bit more time invested would answer all my questions, but I thought that at this stage opening up to an audience interested in asking questions as well as offering advice would be useful.

Advanced REST client is the goto tool for understanding your web application
That’s all for now. Stay in touch

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store