Getting started with SurrealDB using Docker and a Rust client

SurrealDB Docker

This is a simple example on how to use SurrealDB running in Docker and connect to it from your computer using a Rust-based client.

It is a simplified version of the example provided by SurrealDB.

I assume you already have Docker and Rust installed.

Start the SurrealDB in Docker

Create a volume for the database

First we create a volume in Docker to make it easy to have a persistent database without the need to think where to put it.

docker volume create my-surreal-db

Start the database server in one terminal

Then we can start the SurrealDB server in a Docker container.

The --name flag tells Docker to call the container surrealdb. This is an arbitrary name that can help us identify it if necessary.

The --rm flag tells Docker to remove the container once it stopped running so having an easily recognizable name might not be that important.

The -p 8000:8000 flag tells Docker to share the internal port 8000 where SurrealDB listens on the 8000 port of the computer. By default this will only accept connections from your computer so this is fine.

The --user root tells the Docker to run as user root.

The -v my-surreal-db:/database maps the volume we created earlier to the /database folder internally. Apparently this is where SurrealDB stores its files.

The surrealdb/surrealdb:latest is the name of of the image we will use. It will be downloaded automatically if you don't have it on the disk yet.

The start --log trace file://database is passed to SurrealDB. This is here we tell what is the name of the user and its password we would accept. It is also here where we tell SurrealDB to store its files in the /database folder.

docker run --name surrealdb --rm -p 8000:8000 --user root \
   -v my-surreal-db:/database surrealdb/surrealdb:latest   \
   start --log trace file://database

The Rust client

Once we have the database server running we need to create a crate for our code, add the dependencies and run.

Create the crate

$ cargo new in-docker-demo
$ cd in-docker-demo/

Add the dependencies to Cargo.toml

Obviously we need SurrealDB, but we also need serde to serialized and deserialize the structs and we need tokio for the async.

The specific versions probably do not matter much but if you want to check the code, you'll find the Cargo.lock file in our GitHub repository.

examples/surrealdb/in-docker-demo/Cargo.toml

[package]
name = "in-docker-demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
surrealdb = "1.4.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.35", features = ["macros", "rt-multi-thread"] }


The code

Finally we have the code:

examples/surrealdb/in-docker-demo/src/main.rs

use serde::{Deserialize, Serialize};
use surrealdb::engine::remote::ws::Ws;
use surrealdb::sql::Thing;
use surrealdb::Surreal;

#[derive(Debug, Serialize, Deserialize)]
struct Message {
    text: String,
}

#[derive(Debug, Deserialize)]
struct Record {
    #[allow(dead_code)]
    id: Thing,
}

#[tokio::main]
async fn main() -> surrealdb::Result<()> {
    // Connect to the server
    let db = Surreal::new::<Ws>("127.0.0.1:8000").await?;

    // Select a specific namespace / database
    db.use_ns("test-ns").use_db("test-db").await?;

    let args = std::env::args().collect::<Vec<String>>();
    if args.len() == 2 {
        // Create a new message with a random id
        let created: Vec<Record> = db
            .create("messages")
            .content(Message {
                text: args[1].to_owned(),
            })
            .await?;
        dbg!(created);
    } else {
        // Select all the messages records
        let mut response = db.query("SELECT * from messages").await?;
        let messages: Vec<Message> = response.take(0)?;
        for message in &messages {
            println!("{}", message.text);
        }
    }

    Ok(())
}

First we connect to the server that listens on port 8000 (as defined on the Docker command line) on 127.0.0.1 (aka. localhost) as that's the default for Docker.

Then we select the namespace and database we are going to use. You can use any name there. The idea behind them is to allow you to map departments and project in a single organization to namespaces and databases.

Then we get a value from the command line. If the user supplied a value we use that value to create a new record in the database.

Otherwise we list the existing messages.

Running the code

This will add the message "Hello World" to the database:

cargo run "Hello World"

This will list all the messages.

cargo run

Stop and restart server

We can stop the database by pressing Ctrl-C.

We can then start it again with the same docker command we started it earlier.

If we list the messages now they are all still there as they were saved in the database on that volume somewhere on your hard-disk.

Remove the volume

The volume with the database takes up some space on your disk. After you are done with all the experiments you can remove it using the following command:

docker volume remove my-surreal-db

Related Pages

SurrealDB - relation between tables - foreign key
SurrealDB

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo