1

My web application has a REST API via Rocket, connects to a MySQL database, and there's a single endpoint. I cannot figure out how to access the database connection inside the controller:

#![feature(decl_macro)]
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;

use rocket_contrib::json::Json;
use serde::Serialize;

#[macro_use]
extern crate mysql;
use mysql as my;
use mysql::consts::ColumnType::MYSQL_TYPE_DATE;
use mysql::prelude::Queryable;
use mysql::Pool;

#[get("/orgs")]
fn get_orgs(conn: MyDb) -> Json<Vec<Org>> {
    // I need to have the db connection here to pass it to get_all.
    let o = match Org::get_all() {
        Ok(o) => o,
        Err(e) => panic!(e),
    };

    Json(o)
}

#[derive(Serialize)]
pub struct Org {
    pub id: Option<i32>,
    pub name: String,
}

fn main() {
    let url = "mysql://root:mysql@(localhost:33061)/somedb";
    let pool = Pool::new(url)?;
    let mut conn = pool.get_conn();
    // I need to pass "conn" around, first to get_orgs, then to Org::get_all.
    rocket::ignite().mount("/", routes![get_orgs]).launch();
}

impl Org {
    fn get_all(mut conn: mysql::Conn) -> Result<Vec<Org>, Err> {
        let all_orgs = conn.query_map("SELECT id, name from organization", |(id, name)| Org {
            id,
            name,
        })?;

        return match all_orgs() {
            Ok(all_orgs) => all_orgs,
            Err(e) => e,
        };
    }
}

My assumption is that #[get("/orgs")] does a bunch of code generation. I found this: https://rocket.rs/v0.4/guide/state/#databases - which looks correct, but I cannot figure out a working example to connect to my MySQL instance via the connection string.

Here are my dependencies:

[dependencies]
rocket = "0.4.2"
rocket_codegen = "0.4.2"
rocket_contrib = "0.4.2"
serde = {version = "1.0", features = ["derive"]}
serde_json = {version = "1.0"}
mysql = "*"

How do I make the MySQL connection and pass it around?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
cbll
  • 6,499
  • 26
  • 74
  • 117

1 Answers1

0

You need to tell Rocket about your database. This is done via Fairings. The document you linked actually includes them in an example:

fn main() {
    rocket::ignite()
       .attach(LogsDbConn::fairing())
       .launch();
}

The important piece above is attach, where the database connection is passed to Rocket as a fairing. Only then can Rocket pass the connection to your route, so that you can use it...

jdno
  • 4,104
  • 1
  • 22
  • 27
  • I am using this implementation and it works locally, given the database exists. However, I want to run my rocket api from a Docker environment and in this environment; my database doesn't (always) exist when the api lauches, sometimes it initiates late, sometimes not at all. What can I do to make rocket retry the connection once it has launched? – milovanderlinden Dec 31 '20 at 13:12
  • @milovanderlinden Check out https://docs.docker.com/compose/startup-order/ for some solutions to your problem. If none of them works for you, it's probably best to create a new question and tag it with Docker. – jdno Jan 01 '21 at 14:13