Use the Lattice SDK for gRPC in Rust
This page shows how you can install, set up, and use the Lattice SDK for gRPC in Rust to get information about an entity in your environment.
Click to go to the gRPC SDK repository. By downloading and/or using, you agree to the terms of use. If you do not agree, do not use the SDK.
Before you begin
- Complete the set up steps to generate a valid API bearer token and publish at least one entity to your environment.
- Install the latest version of Rust. When you install Rust using
rustup
, you also get the latest version of Cargo. You can use Cargo to set up your project and manage dependencies.
Set up your Rust project
For this project, you use cargo
to set up an example project. In the following steps,
you'll replace the starter code with examples that let you connect with your Lattice environment.
-
Confirm that you have Cargo installed:
cargo --version
-
Create a new Rust project:
cargo new $YOUR_PROJECTCargo creates a project folder consisting of a
Cargo.toml
to list versioned dependencies, and amain.rs
file where you implement the main function for your program.Next, you'll replace the starter code.
Get the example files
Copy and paste the following examples into your Rust project:
main.rs
use tonic::metadata::MetadataValue;
use tonic::transport::ClientTlsConfig;
use tonic::transport::Channel;
use tonic::Status;
use tonic::Request;
use anduril_lattice_sdk::anduril::entitymanager::v1::entity_manager_api_client::EntityManagerApiClient;
use anduril_lattice_sdk::anduril::entitymanager::v1::GetEntityRequest;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Replace $YOUR_BEARER_TOKEN with your token. You must keep the word Bearer in the metadata string.
let token = "$YOUR_BEARER_TOKEN";
let bearer_token = format!("Bearer {}", token);
let header_value: MetadataValue<_> = bearer_token.parse().map_err(|_| Status::internal("Invalid Bearer Token"))?;
let tls_config = ClientTlsConfig::new().with_native_roots();
let http_endpoint = format!("$YOUR_LATTICE_URL");
let registration_channel = Channel::from_shared(http_endpoint)
.map_err(|e| Status::invalid_argument(format!("Invalid HTTP endpoint: {}", e)))?
.tls_config(tls_config)
.map_err(|_| Status::internal("TLS configuration failed"))?
.connect()
.await
.map_err(|e| Status::unavailable(format!("Failed to connect: {}", e)))?;
let mut em_client = EntityManagerApiClient::with_interceptor(registration_channel, |mut req: Request<()>| {
req.metadata_mut().insert("authorization", header_value.clone());
Ok(req)
});
let response = em_client.get_entity(GetEntityRequest {
entity_id: String::from("$ENTITY_ID")
}).await?.into_inner();
println!("Response: {:?}", response);
Ok(())
}
In main.rs
, replace $YOUR_LATTICE_URL
, $YOUR_BEARER_TOKEN
, and $ENTITY_ID
with your information.
Your project structure should now look similar to the following:
├── src
│ └── main.rs
├── .gitignore
└── Cargo.toml
Install the SDK
To install the gRPC SDK in Rust, do the following:
-
Add the
lattice-sdk-rust
dependency to yourCargo.toml
file. You will also need a gRPC implementation. We recommend that you use Tonic and Tokio:cargo add anduril-lattice-sdk
# Optional packages.
cargo add tonic -F features-tls
cargo add tokio -F fullAfter installing the packages, Cargo adds
Cargo.lock
to your project folder. This file is automatically generated and updated by Cargo when you build or update your project.Cargo.lock
ensures reproducible builds of your project by locking dependency versions. This helps you ensure consistency across different developments.Your
Cargo.toml
file should now look similar to the following:[package]
name = "$YOUR_PROJECT"
version = "0.1.0"
edition = "2021"
[dependencies]
anduril-lattice-sdk = "1.0.0"
tonic = { version="0.8", features=["tls","tls-roots"] }
tokio = { version="1.0", features=["full"] } -
Verify that you can fetch the required dependencies:
cargo build
This command compiles your Rust project and its dependencies. Cargo places the resulting binary files in
target/debug
.
Run the application
Run your project and connect to Lattice:
cargo run
If the request is successful and you replaced the entity ID then you should see the entity object you created when setting up your development environment. If you did not change the entity ID to a valid, existing entity, then you will get the following error:
ConnectError: [not_found] entity not found ENTITY_ID
This means you successfully authenticated and completed the call to your environment, but the entity does not exist. This is an expected error. If you get any other error then there is a problem with your code. Check that your Lattice environment URL and our bearer token are correct.
To build an optimized binary release of your project,
you can build your project using the --release
option:
cargo build --release
This creates an optimized build in target/release
.
How it works
In main.rs
, you first set up the Tokio runtime and the main function. This is the entry point for your
program. You then declare and parse the bearer token you previously generated.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Replace $YOUR_BEARER_TOKEN with your token.
// You must keep the word Bearer in the metadata string.
let token = "$YOUR_BEARER_TOKEN";
let bearer_token = format!("Bearer {}", token);
let header_value: MetadataValue<_> = bearer_token.parse().map_err(|_| Status::internal("Invalid Bearer Token"))?;
Next, you create a secure TLS channel using your Lattice environment hostname.
let tls_config = ClientTlsConfig::new().with_native_roots();
// Replace $YOUR_LATTICE_HOSTNAME with your environment's hostname.
// For example, example.anduril.com.
let lattice_hostname = format!("$YOUR_LATTICE_HOSTNAME");
let registration_channel = Channel::from_shared(lattice_hostname)
.map_err(|e| Status::invalid_argument(format!("Invalid HTTP endpoint: {}", e)))?
.tls_config(tls_config)
.map_err(|_| Status::internal("TLS configuration failed"))?
.connect()
.await
.map_err(|e| Status::unavailable(format!("Failed to connect: {}", e)))?;
Then, you create a new API client, EntityManagerApiClient
with an interceptor. The interceptor
modifies each outgoing API request and passes your token to request's authorization
metadata header.
let mut em_client = EntityManagerApiClient::with_interceptor(registration_channel, |mut req: Request<()>| {
req.metadata_mut().insert("authorization", header_value.clone());
Ok(req)
});
Finally, using the get_entity
method, you pass in your $ENTITY_ID
and make an asynchronous API call
to the Lattice API.
let response = em_client.get_entity(GetEntityRequest {
entity_id: String::from("$ENTITY_ID")
}).await?.into_inner();
println!("Response: {:?}", response);
Ok(())
}
What's next
- Start building and publishing entities into Lattice.
- See the Lattice sample applications.