> This is the Markdown version of the page. For the complete Lattice Developers documentation index, fetch https://developer.anduril.com/llms.txt. Append .md to any page URL for its clean Markdown.
# Manage objects
> Getting metadata, and managing the lifecycle of objects using the Lattice SDK
In Lattice, an **object** is a data model that represents a single file or a piece of data. This page explains how to manage objects in Lattice,
including retrieving metadata, setting expiration times, and deleting objects.
## Before you begin
* To configure your app to manage objects, [set up](/guides/getting-started/set-up) your Lattice environment.
* See an overview of the [Object schema and the Object Store API](/guides/objects/overview) in Lattice.
* If you haven't already, learn how to [upload](/guides/objects/upload) and [download](/guides/objects/download) objects.
> **gRPC authentication**
>
> These gRPC examples authenticate with a static environment token attached as request metadata.
> If you are using OAuth 2.0 client credentials instead, [set up the token refresh module](/guides/getting-started/authenticate#client-credentials) before running the examples on this page.
## Get object metadata
To retrieve metadata about an object without downloading its contents,
use the `getObjectMetadata` method, which performs a HEAD request to the server.
This operation returns metadata such as the object size in bytes, the SHA-256 checksum,
and timestamps indicating when the object was last modified, and when it expires.
#### Specify the object path
When using the [GetObjectMetadata](/reference/rest/objects/get-object-metadata) API, you must specify
the object path of the object for which you want to retrieve metadata.
For example, if you previously uploaded an image at `/api/v1/objects/image.jpg`,
you would use this path to request its metadata.
#### Get the object metadata
Run the following code to retrieve the object's metadata.
Replace **objectPath** with the path of the object.
```go title={"Go"} maxLines={25}
// Example code for getting object metadata
package main
import (
"context"
"fmt"
"os"
Lattice "github.com/anduril/lattice-sdk-go/v5"
"github.com/anduril/lattice-sdk-go/v5/client"
"github.com/anduril/lattice-sdk-go/v5/option"
)
func main() {
// Get environment variables
latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes
sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
// Check required environment variables
if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
fmt.Println("Missing required environment variables")
os.Exit(1)
}
// Initialize headers for sandbox authorization
headers := make(map[string][]string)
headers["Anduril-Sandbox-Authorization"] = []string{fmt.Sprintf("Bearer %s", sandboxesToken)}
// Create the client
c := client.NewClient(
option.WithToken(environmentToken),
option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
option.WithHTTPHeader(headers),
)
// Set object path
objectPath := ""
// Create context for the request
ctx := context.Background()
// Get the object metadata using HEAD request
response, err := c.Objects.WithRawResponse.GetObjectMetadata(ctx, &Lattice.GetObjectMetadataRequest{ObjectPath: objectPath})
if err != nil {
fmt.Printf("Error getting object metadata: %v\n", err)
os.Exit(1)
}
// The response contains headers with metadata information
fmt.Println("Object Metadata:")
fmt.Printf("Status Code: %d\n", response.StatusCode)
fmt.Printf("Path: %s\n", response.Header.Get("Path"))
fmt.Printf("Content-Length: %s bytes\n", response.Header.Get("Content-Length"))
fmt.Printf("Checksum: %s\n", response.Header.Get("Checksum"))
fmt.Printf("Last-Modified: %s\n", response.Header.Get("Last-Modified"))
fmt.Printf("Expires: %s\n", response.Header.Get("Expires"))
fmt.Println("Object metadata retrieved successfully")
}
```
```java title={"Java"} maxLines={25}
package org.example;
import com.anduril.Lattice;
import com.anduril.core.LatticeHttpResponse;
import java.util.List;
import java.util.Map;
public class GetObjectMetadata {
public static void main(String[] args) {
// Get environment variables
String endpoint = System.getenv("LATTICE_ENDPOINT");
String environmentToken = System.getenv("ENVIRONMENT_TOKEN");
String sandboxesToken = System.getenv("SANDBOXES_TOKEN");
// Check required variables and ensure URL has https://
if (endpoint == null || environmentToken == null || sandboxesToken == null) {
System.err.println("Missing required environment variables");
System.exit(1);
}
if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
try {
// Create Lattice client with Sandbox authentication
Lattice client = Lattice.builder()
.url(endpoint)
.token(environmentToken)
.addHeader("Anduril-Sandbox-Authorization", "Bearer " + sandboxesToken)
.build();
// Set the object path
String objectPath = "";
try {
// Get object metadata using HEAD request
// We need to use withRawResponse to access the headers
LatticeHttpResponse response = client.objects().withRawResponse().getObjectMetadata(objectPath);
// headers() is a Map> keyed on the exact
// casing the server sends (HTTP/2 lowercases header names), and
// each value is a list. Look the headers up case-insensitively
// and take the first value so the metadata isn't dropped.
System.out.println("Object Metadata:");
System.out.println("Path: " + firstHeader(response.headers(), "Path"));
System.out.println("Content-Length: " + firstHeader(response.headers(), "Content-Length") + " bytes");
System.out.println("Checksum: " + firstHeader(response.headers(), "Checksum"));
System.out.println("Last-Modified: " + firstHeader(response.headers(), "Last-Modified"));
System.out.println("Expires: " + firstHeader(response.headers(), "Expires"));
System.out.println("Object metadata retrieved successfully");
} catch (Exception e) {
System.err.println("Error getting object metadata: " + e.getMessage());
}
} catch (Exception e) {
System.err.println("Error initializing client: " + e.getMessage());
}
}
// Returns the first value of the named header, matched case-insensitively,
// or "" when the header is absent.
private static String firstHeader(Map> headers, String name) {
for (Map.Entry> entry : headers.entrySet()) {
if (entry.getKey().equalsIgnoreCase(name)) {
List values = entry.getValue();
return values.isEmpty() ? "" : values.get(0);
}
}
return "";
}
}
```
```py title={"Python"} maxLines={25}
from anduril import Lattice
import os
import sys
import asyncio
lattice_endpoint = os.getenv('LATTICE_ENDPOINT')
environment_token = os.getenv('ENVIRONMENT_TOKEN')
# Remove sandboxes_token from the following statements if you are not developing on Sandboxes.
sandboxes_token = os.getenv('SANDBOXES_TOKEN')
if not environment_token or not lattice_endpoint or not sandboxes_token:
print("Missing required environment variables.")
sys.exit(1)
client = Lattice(
base_url=f"https://{lattice_endpoint}",
token=lambda: str(environment_token),
# Remove the following if you are not developing on a Sandboxes.
headers={ "anduril-sandbox-authorization": f"Bearer {sandboxes_token}" }
)
async def app(object_path):
try:
response = client.objects.get_object_metadata(
object_path=object_path
)
# get_object_metadata returns the response headers as a dict. The
# underlying HTTP client (httpx) lowercases header names, and the dict
# lookup is case-sensitive, so query the headers with lowercase keys.
print("Object Metadata:")
print(f"Path: {response.get('path')}")
print(f"Content-Length: {response.get('content-length')} bytes")
print(f"Checksum: {response.get('checksum')}")
print(f"Last-Modified: {response.get('last-modified')}")
print(f"Expires: {response.get('expires')}")
except asyncio.CancelledError:
print(">>>Exiting...")
except Exception as error:
print(f"Exception: {error}")
if __name__ == "__main__":
# Replace with the path of the object you want to get metadata for
asyncio.run(app(object_path=""))
```
```ts title={"Typescript"} maxLines={25}
import { LatticeClient } from "@anduril-industries/lattice-sdk";
const latticeEndpoint = process.env.LATTICE_ENDPOINT;
const environmentToken = process.env.ENVIRONMENT_TOKEN;
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
const sandboxesToken = process.env.SANDBOXES_TOKEN;
if (!latticeEndpoint || !environmentToken || !sandboxesToken) {
console.log('Missing required environment variables.');
process.exit(1);
}
const client = new LatticeClient(
{
baseUrl: `https://${latticeEndpoint}`,
token: environmentToken,
// Remove the header if you are not developing on Sandboxes.
headers: { "Anduril-Sandbox-Authorization": `Bearer ${sandboxesToken}` }
}
);
async function App(objectPath: string) {
try {
// Get the object metadata using HEAD request
const response = await client.objects.getObjectMetadata({ objectPath });
// The response contains the headers with metadata information
console.log('Object Metadata:');
console.log(`Path: ${response.get('Path')}`);
console.log(`Content Length: ${response.get('Content-Length')} bytes`);
console.log(`Checksum: ${response.get('Checksum')}`);
console.log(`Last Modified: ${response.get('Last-Modified')}`);
console.log(`Expires: ${response.get('Expires')}`);
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
console.log('Process interrupted. Exiting...');
process.exit(0);
} else {
console.log(`Encountered the following error: ${error}`);
process.exit(1);
}
}
}
// Replace objectPath with the path of the object you want to get metadata for
const objectPath = "";
App(objectPath);
```
```rs title={"Rust"} startLine={36} maxLines={25}
use anduril_lattice_sdk::prelude::*;
use reqwest::Method;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box> {
let lattice_endpoint = env::var("LATTICE_ENDPOINT")
.expect("LATTICE_ENDPOINT environment variable not set");
let environment_token = env::var("ENVIRONMENT_TOKEN")
.expect("ENVIRONMENT_TOKEN environment variable not set");
// Remove sandboxes_token if you are not developing on Sandboxes.
let sandboxes_token = env::var("SANDBOXES_TOKEN")
.expect("SANDBOXES_TOKEN environment variable not set");
if environment_token.is_empty() || lattice_endpoint.is_empty() || sandboxes_token.is_empty() {
eprintln!("Missing required environment variables:");
eprintln!(" LATTICE_ENDPOINT");
eprintln!(" ENVIRONMENT_TOKEN");
eprintln!(" SANDBOXES_TOKEN");
std::process::exit(1);
}
let config = ClientConfig {
base_url: format!("https://{}", lattice_endpoint),
token: Some(environment_token),
// Remove custom_headers if you are not developing on Sandboxes.
custom_headers: HashMap::from([(
"anduril-sandbox-authorization".to_string(),
format!("Bearer {}", sandboxes_token),
)]),
..Default::default()
};
let client = Lattice::new(config)?;
// Replace with the path of the object you want metadata for.
let object_path = "";
let path = format!("api/v1/objects/{}", object_path);
match client
.objects
.http_client
.execute_request_raw::<()>(Method::HEAD, &path, None, None, None)
.await
{
Ok(response) => {
// Read a header value as a string, or "" if absent/non-ASCII.
let header = |name: &str| {
response
.headers
.get(name)
.and_then(|value| value.to_str().ok())
.map(str::to_string)
.unwrap_or_else(|| "".to_string())
};
println!("Object metadata for: {}", object_path);
println!(" Path: {}", header("Path"));
println!(" Content-Length: {}", header("Content-Length"));
println!(" Checksum: {}", header("Checksum"));
println!(" Last-Modified: {}", header("Last-Modified"));
println!(" Expires: {}", header("Expires"));
}
Err(e) => eprintln!("Exception: {}", e),
}
Ok(())
}
```
#### Inspect the metadata
If successful, the response will include headers with valuable information:
```bash
Object metadata:
- Path: your_object_path.jpg
- Content-Length: 2000000 bytes
- Checksum: 4191337226643912nbab1784de94c4f58bb78bf98bfb9916474b2fe5decbbaa6
- Last-Modified: Thu, 30 Oct 2025 00:30:41 UTC
- Expires: Thu, 30 Oct 2025 01:30:41 UTC
```
You can use this information to verify the object size before downloading,
confirm the object hasn't been modified using the checksum,
and check when the object expires and is removed from your environment.
## Set object time-to-live
In Lattice, an **object** is a data model that represents a single file or a piece of data. When uploading objects, you can control how long they will be stored in Lattice
by setting a Time-To-Live (TTL) value. This is useful for temporary files or for implementing storage policies.
#### Prepare the file and TTL value
Before uploading, you need to:
1. Have a file ready to upload
2. Determine the desired time-to-live in nanoseconds
For example, to keep an object for 24 hours, you would set the TTL to:
`24 * 60 * 60 * 1,000,000,000` nanoseconds (86,400,000,000,000 ns)
#### Upload with TTL header
Use the Lattice SDK to upload the object, adding the `Time-To-Live` request header to specify the TTL:
```go title={"Go"} maxLines={25}
package main
import (
"bytes"
"context"
"fmt"
"net/http"
"os"
"path/filepath"
"strconv"
Lattice "github.com/anduril/lattice-sdk-go/v5"
"github.com/anduril/lattice-sdk-go/v5/client"
"github.com/anduril/lattice-sdk-go/v5/option"
)
func main() {
// Get environment variables
latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes
sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
// Check required environment variables
if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
fmt.Println("Missing required environment variables")
os.Exit(1)
}
// Initialize headers for sandbox authorization
headers := http.Header{}
headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
// Create the client
c := client.NewClient(
option.WithToken(environmentToken),
option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
option.WithHTTPHeader(headers),
)
// File path of the object to upload
filePath := ""
// Set TTL to 1 hour in nanoseconds
ttlInNanoseconds := int64(1 * 60 * 60 * 1000000000) // 1 hour in nanoseconds
// Create context for the request
ctx := context.Background()
// Read the file contents into a byte slice.
fileContent, err := os.ReadFile(filePath)
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
os.Exit(1)
}
// Get file name for object path
objectPath := filepath.Base(filePath)
// Create TTL header
ttlHeaders := http.Header{}
ttlHeaders.Add("Time-To-Live", strconv.FormatInt(ttlInNanoseconds, 10))
// Upload object with TTL header
response, err := c.Objects.UploadObject(
ctx,
objectPath,
bytes.NewReader(fileContent),
option.WithHTTPHeader(ttlHeaders),
)
if err != nil {
fmt.Printf("Error uploading object: %v\n", err)
os.Exit(1)
}
fmt.Printf("Object uploaded successfully. Object path: %s\n", response.ContentIdentifier.Path)
fmt.Printf("Object will expire after %d seconds\n", ttlInNanoseconds/1000000000)
// Verify the expiry time by getting object metadata
metadataResponse, err := c.Objects.WithRawResponse.GetObjectMetadata(ctx, &Lattice.GetObjectMetadataRequest{ObjectPath: objectPath})
if err != nil {
fmt.Printf("Error getting object metadata: %v\n", err)
os.Exit(1)
}
fmt.Printf("Expiry time confirmed: %s\n", metadataResponse.Header.Get("Expires"))
}
```
```java title={"Java"} maxLines={25}
package org.example;
import com.anduril.Lattice;
import com.anduril.core.RequestOptions;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
public class UploadWithTtl {
public static void main(String[] args) {
// Get environment variables
String endpoint = System.getenv("LATTICE_ENDPOINT");
String environmentToken = System.getenv("ENVIRONMENT_TOKEN");
String sandboxesToken = System.getenv("SANDBOXES_TOKEN");
// Check required variables and ensure URL has https://
if (endpoint == null || environmentToken == null || sandboxesToken == null) {
System.err.println("Missing required environment variables");
System.exit(1);
}
if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
try {
// Create Lattice client with Sandbox authentication
Lattice client = Lattice.builder()
.url(endpoint)
.token(environmentToken)
.addHeader("Anduril-Sandbox-Authorization", "Bearer " + sandboxesToken)
.build();
// File path of the object to upload
String filePath = "";
// Set TTL to 1 hour in nanoseconds
long ttlInNanoseconds = 1L * 60 * 60 * 1000000000; // 1 hour in nanoseconds
// Create a File object from the file path
File file = new File(filePath);
// Get file name for object path
String objectPath = file.getName();
try {
// Create request options with TTL header
RequestOptions requestOptions = RequestOptions.builder()
.addHeader("Time-To-Live", String.valueOf(ttlInNanoseconds))
.build();
// Upload the file with TTL header using byte array
FileInputStream fileInputStream = new FileInputStream(file);
byte[] fileBytes = new byte[(int) file.length()];
fileInputStream.read(fileBytes);
fileInputStream.close();
var result = client.objects().uploadObject(objectPath, fileBytes, requestOptions);
System.out.println("Object uploaded successfully. Object path: " + result.getContentIdentifier().getPath());
System.out.println("Object will expire after " + (ttlInNanoseconds / 1_000_000_000) + " seconds");
// Verify the expiry time by getting object metadata. headers()
// is keyed on the server's header casing and holds list values,
// so look up "Expires" case-insensitively and take the first.
var metadata = client.objects().withRawResponse().getObjectMetadata(objectPath);
System.out.println("Expiry time confirmed: " + firstHeader(metadata.headers(), "Expires"));
} catch (Exception e) {
System.err.println("Error uploading object: " + e.getMessage());
}
} catch (Exception e) {
System.err.println("Error initializing client: " + e.getMessage());
}
}
// Returns the first value of the named header, matched case-insensitively,
// or "" when the header is absent.
private static String firstHeader(Map> headers, String name) {
for (Map.Entry> entry : headers.entrySet()) {
if (entry.getKey().equalsIgnoreCase(name)) {
List values = entry.getValue();
return values.isEmpty() ? "" : values.get(0);
}
}
return "";
}
}
```
```py title={"Python"} maxLines={25}
from anduril import Lattice
import os
import sys
import asyncio
lattice_endpoint = os.getenv('LATTICE_ENDPOINT')
environment_token = os.getenv('ENVIRONMENT_TOKEN')
# Remove sandboxes_token from the following statements if you are not developing on Sandboxes.
sandboxes_token = os.getenv('SANDBOXES_TOKEN')
if not environment_token or not lattice_endpoint or not sandboxes_token:
print("Missing required environment variables.")
sys.exit(1)
# Set the TTL value to 1 hour, expressed in nanoseconds.
time_to_live = 1 * 60 * 60 * 1000000000
headers = {
"anduril-sandbox-authorization": f"Bearer {sandboxes_token}"
}
client = Lattice(
base_url=f"https://{lattice_endpoint}",
token=lambda: str(environment_token),
headers=headers
)
async def app(file_path):
try:
# Get the file name.
file_name = os.path.basename(file_path)
# Define a unique path for the object using the file name.
object_path = f"{file_name}"
# Open the file in binary mode.
with open(f"{file_path}", "rb") as file:
# Use the upload_object method to upload the file to Lattice.
client.objects.upload_object(
object_path=object_path,
request=file,
request_options={
"additional_headers": {
"time-to-live": f"{time_to_live}"
}
}
)
print(f"Object path: {object_path}")
# Verify the expiry time by getting object metadata
metadata = client.objects.get_object_metadata(
object_path=object_path
)
print(f"Object expires on {metadata.get('expires')}")
except asyncio.CancelledError:
print(">>>Exiting...")
except Exception as error:
print(f"Exception: {error}")
if __name__ == "__main__":
# Replace with your file path
file_path = ""
asyncio.run(app(file_path))
```
```ts title={"Typescript"} maxLines={25}
import { LatticeClient } from "@anduril-industries/lattice-sdk";
import { basename } from 'path';
import { createReadStream } from "fs";
const latticeEndpoint = process.env.LATTICE_ENDPOINT;
const environmentToken = process.env.ENVIRONMENT_TOKEN;
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
const sandboxesToken = process.env.SANDBOXES_TOKEN;
if (!latticeEndpoint || !environmentToken || !sandboxesToken) {
console.log('Missing required environment variables.');
process.exit(1);
}
const client = new LatticeClient(
{
baseUrl: `https://${latticeEndpoint}`,
token: environmentToken,
// Remove the header if you are not developing on Sandboxes.
headers: { "Anduril-Sandbox-Authorization": `Bearer ${sandboxesToken}` }
}
);
async function App(filePath: string, ttlInNanoseconds: number) {
const fileStreamReadable = createReadStream(filePath);
try {
// Set the object path using the file name.
const objectPath = `${basename(filePath)}`;
// Upload the file to Lattice with TTL header
// The Time-To-Live header sets the expiration time in nanoseconds
const requestOptions = {
headers: {
'Time-To-Live': ttlInNanoseconds.toString()
}
};
const result = await client.objects.uploadObject(
fileStreamReadable,
objectPath,
requestOptions
);
console.log(`Object uploaded successfully. Object path: ${result.content_identifier.path}`);
console.log(`Object will expire after ${ttlInNanoseconds / 1e9} seconds`);
// You can verify the expiry time by getting the object metadata
const metadata = await client.objects.getObjectMetadata({ objectPath });
console.log(`Expiry time confirmed: ${metadata.get('Expires')}`);
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
console.log('Process interrupted. Exiting...');
process.exit(0);
} else {
console.log(`Encountered the following error: ${error}`);
process.exit(1);
}
} finally {
fileStreamReadable.close();
}
}
// Replace filepath with the path of the file you want to upload.
const filePath = "";
// Set TTL to 1 hour in nanoseconds
const ttlInNanoseconds = 1 * 60 * 60 * 1000000000; // 1 hour in nanoseconds
App(filePath, ttlInNanoseconds);
```
```rs title={"Rust"} startLine={35} maxLines={25}
use anduril_lattice_sdk::prelude::*;
use reqwest::Method;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box> {
let lattice_endpoint = env::var("LATTICE_ENDPOINT")
.expect("LATTICE_ENDPOINT environment variable not set");
let environment_token = env::var("ENVIRONMENT_TOKEN")
.expect("ENVIRONMENT_TOKEN environment variable not set");
// Remove sandboxes_token if you are not developing on Sandboxes.
let sandboxes_token = env::var("SANDBOXES_TOKEN")
.expect("SANDBOXES_TOKEN environment variable not set");
if environment_token.is_empty() || lattice_endpoint.is_empty() || sandboxes_token.is_empty() {
eprintln!("Missing required environment variables:");
eprintln!(" LATTICE_ENDPOINT");
eprintln!(" ENVIRONMENT_TOKEN");
eprintln!(" SANDBOXES_TOKEN");
std::process::exit(1);
}
let config = ClientConfig {
base_url: format!("https://{}", lattice_endpoint),
token: Some(environment_token),
// Remove custom_headers if you are not developing on Sandboxes.
custom_headers: HashMap::from([(
"anduril-sandbox-authorization".to_string(),
format!("Bearer {}", sandboxes_token),
)]),
..Default::default()
};
let client = Lattice::new(config)?;
// Set the TTL value to 1 hour, expressed in nanoseconds.
let time_to_live: u64 = 1 * 60 * 60 * 1_000_000_000;
// Replace with the file path to upload with a TTL.
let file_path = "";
let result = async {
let file_name = std::path::Path::new(file_path)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or(file_path);
let object_path = file_name.to_string();
let bytes = std::fs::read(file_path)?;
// Attach the time-to-live header via per-request options.
let options = RequestOptions::new().additional_header("time-to-live", time_to_live.to_string());
let metadata = client
.objects
.upload_object(&object_path, &bytes, Some(options))
.await?;
println!("Object path: {}", object_path);
// `upload_object` returns a typed `PathMetadata`, including the
// computed `expiry_time` derived from the time-to-live header, so the
// TTL is surfaced directly from the upload response.
println!(" Checksum: {}", metadata.content_identifier.checksum);
println!(" Size (bytes): {}", metadata.size_bytes);
match metadata.expiry_time {
Some(expiry) => println!(" Expires at: {}", expiry.to_rfc3339()),
None => println!(" Expires at: "),
}
// Confirm the object exists after upload and read the `Expires` header
// from the metadata (HEAD) response. `get_object_metadata` is a HEAD
// whose metadata is returned only in response headers, so we issue it
// through the public, already-authenticated `HttpClient` and read
// `RawResponse::headers` rather than the typed `()` return.
let path = format!("api/v1/objects/{}", object_path);
let head = client
.objects
.http_client
.execute_request_raw::<()>(Method::HEAD, &path, None, None, None)
.await?;
let expires = head
.headers
.get("Expires")
.and_then(|value| value.to_str().ok())
.unwrap_or("");
println!("Object uploaded with a 1-hour TTL. Expires header: {}", expires);
Ok::<(), Box>(())
}
.await;
if let Err(e) = result {
eprintln!("Exception: {}", e);
}
Ok(())
}
```
#### Verify the expiry time
If successful, Lattice sets an expiry time based on the value you specify in the
`Time-To-Live` header. The example from the previous steps confirms the result by
fetching the object's metadata and checking the `Expires` header:
```bash
Object expires on Mon, 01 Jan 2026 00:00:00 UTC
```
If you don't set a TTL, Lattice will use a default typically set to 90 days. This default TTL policy might vary,
based on your environment's configurations.
## Delete an object
In Lattice, an **object** is a data model that represents a single file or a piece of data. When you no longer need an object, you can delete it from Lattice
to free up storage space. Deleting an object is a permanent operation that cannot be undone.
#### Delete the object
When using the [DeleteObject](/reference/rest/objects/delete-object) API, you must specify
the object path of the object you want to delete.
Replace the object path with your information, then run the following code to delete the object:
```go title={"Go"} maxLines={25}
// Example code for deleting an object
package main
import (
"context"
"fmt"
"os"
Lattice "github.com/anduril/lattice-sdk-go/v5"
"github.com/anduril/lattice-sdk-go/v5/client"
"github.com/anduril/lattice-sdk-go/v5/option"
)
func main() {
// Get environment variables
latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes
sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
// Check required environment variables
if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
fmt.Println("Missing required environment variables")
os.Exit(1)
}
// Initialize headers for sandbox authorization
headers := make(map[string][]string)
headers["Anduril-Sandbox-Authorization"] = []string{fmt.Sprintf("Bearer %s", sandboxesToken)}
// Create the client
c := client.NewClient(
option.WithToken(environmentToken),
option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
option.WithHTTPHeader(headers),
)
// Set object path to delete
objectPath := ""
// Create context for the request
ctx := context.Background()
// Delete the object
err := c.Objects.DeleteObject(ctx, &Lattice.DeleteObjectRequest{ObjectPath: objectPath})
if err != nil {
fmt.Printf("Error deleting object: %v\n", err)
os.Exit(1)
}
fmt.Printf("Object deleted successfully: %s\n", objectPath)
// Try to access the object to verify it's deleted
_, err = c.Objects.WithRawResponse.GetObjectMetadata(ctx, &Lattice.GetObjectMetadataRequest{ObjectPath: objectPath})
if err != nil {
fmt.Println("Verification successful: Object no longer exists.")
fmt.Printf("Expected error: %v\n", err)
} else {
fmt.Println("Warning: Object still exists after deletion attempt.")
}
}
```
```java title={"Java"} maxLines={25}
package org.example;
import com.anduril.Lattice;
public class DeleteObject {
public static void main(String[] args) {
// Get environment variables
String endpoint = System.getenv("LATTICE_ENDPOINT");
String environmentToken = System.getenv("ENVIRONMENT_TOKEN");
String sandboxesToken = System.getenv("SANDBOXES_TOKEN");
// Check required variables and ensure URL has https://
if (endpoint == null || environmentToken == null || sandboxesToken == null) {
System.err.println("Missing required environment variables");
System.exit(1);
}
if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
try {
// Create Lattice client with Sandbox authentication
Lattice client = Lattice.builder()
.url(endpoint)
.token(environmentToken)
.addHeader("Anduril-Sandbox-Authorization", "Bearer " + sandboxesToken)
.build();
// Set the object path
String objectPath = "";
try {
// Delete the object
client.objects().deleteObject(objectPath);
System.out.println("Object deleted successfully: " + objectPath);
// Try to access the object to verify it's deleted
try {
client.objects().getObjectMetadata(objectPath);
System.out.println("Warning: Object still exists after deletion attempt.");
} catch (Exception e) {
System.out.println("Verification successful: Object no longer exists.");
System.out.println("Expected error: " + e.getMessage());
}
} catch (Exception e) {
System.err.println("Error deleting object: " + e.getMessage());
}
} catch (Exception e) {
System.err.println("Error initializing client: " + e.getMessage());
}
}
}
```
```py title={"Python"} maxLines={25}
from anduril import Lattice
import os
import sys
import asyncio
lattice_endpoint = os.getenv('LATTICE_ENDPOINT')
environment_token = os.getenv('ENVIRONMENT_TOKEN')
# Remove sandboxes_token from the following statements if you are not developing on Sandboxes.
sandboxes_token = os.getenv('SANDBOXES_TOKEN')
if not environment_token or not lattice_endpoint or not sandboxes_token:
print("Missing required environment variables.")
sys.exit(1)
client = Lattice(
base_url=f"https://{lattice_endpoint}",
token=lambda: str(environment_token),
# Remove the following if you are not developing on a Sandboxes.
headers={ "anduril-sandbox-authorization": f"Bearer {sandboxes_token}" }
)
async def app(object_path):
try:
# Delete the object
client.objects.delete_object(
object_path=object_path
)
print(f"Object deleted successfully: {object_path}")
try:
client.objects.get_object_metadata(
object_path=object_path
)
print("Object still exists after deletion attempt.")
except Exception as e:
print(f"NotFound: {e}")
except asyncio.CancelledError:
print(">>>Exiting...")
except Exception as error:
print(f"Exception: {error}")
if __name__ == "__main__":
# Replace with the path of the object you want to delete
asyncio.run(app(object_path=""))
```
```ts title={"Typescript"} maxLines={25}
import { LatticeClient } from "@anduril-industries/lattice-sdk";
const latticeEndpoint = process.env.LATTICE_ENDPOINT;
const environmentToken = process.env.ENVIRONMENT_TOKEN;
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
const sandboxesToken = process.env.SANDBOXES_TOKEN;
if (!latticeEndpoint || !environmentToken || !sandboxesToken) {
console.log('Missing required environment variables.');
process.exit(1);
}
const client = new LatticeClient(
{
baseUrl: `https://${latticeEndpoint}`,
token: environmentToken,
// Remove the header if you are not developing on Sandboxes.
headers: { "Anduril-Sandbox-Authorization": `Bearer ${sandboxesToken}` }
}
);
async function App(objectPath: string) {
try {
// Delete the object
await client.objects.deleteObject({ objectPath });
console.log(`Object deleted successfully: ${objectPath}`);
// Try to access the object to verify it's deleted
try {
await client.objects.getObjectMetadata({ objectPath });
console.log('Warning: Object still exists after deletion attempt.');
} catch {
console.log('Verification successful: Object no longer exists.');
}
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
console.log('Process interrupted. Exiting...');
process.exit(0);
} else {
console.log(`Encountered the following error: ${error}`);
process.exit(1);
}
}
}
// Replace objectPath with the path of the object you want to delete
const objectPath = "";
App(objectPath);
```
```rs title={"Rust"} startLine={35} maxLines={25}
use anduril_lattice_sdk::prelude::*;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box> {
let lattice_endpoint = env::var("LATTICE_ENDPOINT")
.expect("LATTICE_ENDPOINT environment variable not set");
let environment_token = env::var("ENVIRONMENT_TOKEN")
.expect("ENVIRONMENT_TOKEN environment variable not set");
// Remove sandboxes_token if you are not developing on Sandboxes.
let sandboxes_token = env::var("SANDBOXES_TOKEN")
.expect("SANDBOXES_TOKEN environment variable not set");
if environment_token.is_empty() || lattice_endpoint.is_empty() || sandboxes_token.is_empty() {
eprintln!("Missing required environment variables:");
eprintln!(" LATTICE_ENDPOINT");
eprintln!(" ENVIRONMENT_TOKEN");
eprintln!(" SANDBOXES_TOKEN");
std::process::exit(1);
}
let config = ClientConfig {
base_url: format!("https://{}", lattice_endpoint),
token: Some(environment_token),
// Remove custom_headers if you are not developing on Sandboxes.
custom_headers: HashMap::from([(
"anduril-sandbox-authorization".to_string(),
format!("Bearer {}", sandboxes_token),
)]),
..Default::default()
};
let client = Lattice::new(config)?;
// Replace with the path of the object you want to delete.
let object_path = "";
match client.objects.delete_object(object_path, None).await {
Ok(()) => {
println!("Object deleted successfully: {}", object_path);
// Verify deletion: a subsequent metadata lookup should fail with a
// NotFound error.
match client.objects.get_object_metadata(object_path, None).await {
Ok(()) => println!("Object still exists after deletion attempt."),
Err(e) => println!("NotFound: {}", e),
}
}
Err(e) => eprintln!("Exception: {}", e),
}
Ok(())
}
```
If successful, this produces an error with the following output:
the object no longer exists"
```bash
Object deleted successfully: test.jpg
Status: 404
```
#### (Optional) Unlink entity
When you delete an object, you must clean up any references to the object path in your environment.
For example, if the object is linked to an entity, using the entity's `Media` component, your app must submit an `Override`
to remove the object path from the list. Run the following example:
```go title={"Go (REST)"} maxLines={25}
package main
import (
"context"
"fmt"
"net/http"
"os"
"time"
Lattice "github.com/anduril/lattice-sdk-go/v5"
"github.com/anduril/lattice-sdk-go/v5/client"
"github.com/anduril/lattice-sdk-go/v5/option"
)
func main() {
// Get environment variables
latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
// Check required environment variables
if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
fmt.Println("Make sure your Lattice URL and bearer token have been set as system environment variables.")
os.Exit(1)
}
// Initialize headers for sandbox authorization
headers := http.Header{}
headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
// Create the client
LatticeClient := client.NewClient(
option.WithToken(environmentToken),
option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
option.WithHTTPHeader(headers),
)
// Set the entity ID
entityID := ""
// Create context for the request
ctx := context.Background()
// Create empty media array
media := Lattice.Media{
Media: []*Lattice.MediaItem{},
}
// Create a provenance object
latestTimestamp := time.Now().UTC()
// Create an entity with empty media
entityOverride := Lattice.EntityOverride{
EntityID: entityID,
FieldPath: "media.media",
Entity: &Lattice.Entity{
EntityID: &entityID,
Media: &media,
},
Provenance: &Lattice.Provenance{
IntegrationName: Lattice.String(""),
DataType: Lattice.String(""),
SourceUpdateTime: Lattice.Time(latestTimestamp),
},
}
// Override the entity's media field
_, err := LatticeClient.Entities.OverrideEntity(
ctx,
&entityOverride,
)
if err != nil {
fmt.Printf("Exception: %v\n", err)
return
}
// Get the entity to verify the media was cleared
entity, err := LatticeClient.Entities.GetEntity(
ctx,
&Lattice.GetEntityRequest{EntityID: entityID},
)
if err != nil {
fmt.Printf("Failed to get entity: %v\n", err)
return
}
fmt.Printf("Entity: %s\n", *entity.EntityID)
if entity.Media != nil && entity.Media.Media != nil {
fmt.Printf("Media: %v\n", entity.Media.Media)
} else {
fmt.Printf("Media: None\n")
}
}
```
```java title={"Java (REST)"} maxLines={25}
package org.example;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Collections;
import com.anduril.Lattice;
import com.anduril.resources.entities.requests.EntityOverride;
import com.anduril.types.Entity;
import com.anduril.types.Media;
import com.anduril.types.Provenance;
/**
* Example application that demonstrates how to clear media from an entity using the Lattice SDK.
*/
public class OverrideMediaClear {
public static void main(String[] args) {
// Get environment variables
String endpoint = System.getenv("LATTICE_ENDPOINT");
String environmentToken = System.getenv("ENVIRONMENT_TOKEN");
String sandboxesToken = System.getenv("SANDBOXES_TOKEN");
// Check required variables and ensure URL has https://
if (endpoint == null || environmentToken == null || sandboxesToken == null) {
System.err.println("Make sure your Lattice URL and bearer token have been set as system environment variables.");
System.exit(1);
}
if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
try {
// Create Lattice client with Sandbox authentication
Lattice client = Lattice.builder()
.url(endpoint)
.token(environmentToken)
.addHeader("Anduril-Sandbox-Authorization", "Bearer " + sandboxesToken)
.build();
// Set the entity ID
String entityId = "";
// Create empty Media object
Media media = Media.builder()
.media(Collections.emptyList())
.build();
// Create a provenance object
Provenance provenance = Provenance.builder()
.integrationName("")
.dataType("")
.sourceUpdateTime(OffsetDateTime.now(ZoneOffset.UTC))
.build();
// Create an entity with empty media
EntityOverride entityOverride = EntityOverride.builder()
.entity(Entity.builder()
.entityId(entityId)
.media(media)
.build())
.provenance(provenance)
.build();
// Override the entity's media field
client.entities().overrideEntity(
entityId,
"media.media",
entityOverride
);
// Get the entity to verify the media was cleared
Entity result = client.entities().getEntity(entityId);
System.out.println("Entity: " + result.getEntityId());
System.out.println("Media: " + result.getMedia());
} catch (Exception e) {
System.err.println("Exception: " + e.getMessage());
}
}
}
```
```py title={"Python (REST)"} maxLines={25}
from anduril import Lattice, Media, Entity, Provenance
from datetime import datetime, timezone
import os
import sys
import asyncio
import logging
lattice_endpoint = os.getenv('LATTICE_ENDPOINT')
environment_token = os.getenv('ENVIRONMENT_TOKEN')
sandboxes_token = os.getenv('SANDBOXES_TOKEN')
if not environment_token or not lattice_endpoint or not sandboxes_token:
print("Make sure your Lattice URL and bearer token " \
"have been set as system environment variables.")
sys.exit(1)
# Create an API stub to interact with Lattice.
client = Lattice(
# Set your environment URL, and provide both tokens.
base_url=f"https://{lattice_endpoint}",
token=lambda: str(environment_token),
headers={ "anduril-sandbox-authorization": f"Bearer {sandboxes_token}" }
)
async def app(entity_id):
try:
latest_timestamp = datetime.now(timezone.utc)
provenance = Provenance(
integration_name="",
data_type="",
source_update_time=latest_timestamp
)
media = Media(
media=[]
)
client.entities.override_entity(
entity_id=entity_id,
field_path="media.media",
entity=Entity(
entity_id=entity_id,
media=media
),
provenance=provenance
)
result = client.entities.get_entity(
entity_id=entity_id
)
print(f"Entity: {result.entity_id}")
print(f"Media: {result.media}")
except asyncio.CancelledError:
logging.info(">>>Exiting...")
except Exception as error:
logging.error(f"Exception: {error}")
if __name__ == "__main__":
# Set the integration name and the file path.
asyncio.run(app(entity_id=""))
```
```ts title={"Typescript (REST)"} maxLines={25}
import { LatticeClient } from "@anduril-industries/lattice-sdk";
const latticeEndpoint = process.env.LATTICE_ENDPOINT;
const environmentToken = process.env.ENVIRONMENT_TOKEN;
// Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
const sandboxesToken = process.env.SANDBOXES_TOKEN;
if (!latticeEndpoint || !environmentToken || !sandboxesToken) {
console.log('Make sure your Lattice URL and bearer token have been set as system environment variables.');
process.exit(1);
}
const client = new LatticeClient(
{
baseUrl: `https://${latticeEndpoint}`,
token: environmentToken,
// Remove the header if you are not developing on Sandboxes.
headers: { "Anduril-Sandbox-Authorization": `Bearer ${sandboxesToken}` }
}
);
async function App(entityId: string) {
const latestTimestamp = new Date().toISOString();
try {
// Override the nested media.media component of the entity with an empty array.
await client.entities.overrideEntity(
{
entityId,
fieldPath: 'media.media',
entity: {
entityId: entityId,
media: {
media: []
}
},
provenance: {
integrationName: "",
dataType: "",
sourceUpdateTime: latestTimestamp
}
}
);
// Get the entity to verify the media was cleared
const result = await client.entities.getEntity({ entityId });
console.log(`Entity: ${result.entityId}`);
console.log(`Media: ${result.media}`);
} catch (error) {
console.log(`Exception: ${error}`);
}
}
// Replace with the ID of the entity you want to clear media from.
const entityId = '';
App(entityId);
```
```rs title={"Rust (REST)"} startLine={31} maxLines={25}
use anduril_lattice_sdk::prelude::*;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box> {
let lattice_endpoint = env::var("LATTICE_ENDPOINT")
.expect("LATTICE_ENDPOINT environment variable not set");
let environment_token = env::var("ENVIRONMENT_TOKEN")
.expect("ENVIRONMENT_TOKEN environment variable not set");
let sandboxes_token = env::var("SANDBOXES_TOKEN")
.expect("SANDBOXES_TOKEN environment variable not set");
if environment_token.is_empty() || lattice_endpoint.is_empty() || sandboxes_token.is_empty() {
eprintln!("Make sure your Lattice URL and bearer token have been set as system environment variables.");
std::process::exit(1);
}
let config = ClientConfig {
base_url: format!("https://{}", lattice_endpoint),
token: Some(environment_token),
// Remove custom_headers if you are not developing on Sandboxes.
custom_headers: HashMap::from([(
"anduril-sandbox-authorization".to_string(),
format!("Bearer {}", sandboxes_token),
)]),
..Default::default()
};
let client = Lattice::new(config)?;
// Replace with the entity ID whose media you want to clear.
let entity_id = "";
let latest_timestamp = Utc::now().fixed_offset();
let provenance = Provenance {
integration_name: Some("".to_string()),
data_type: Some("".to_string()),
source_update_time: Some(latest_timestamp),
..Default::default()
};
// An empty media list clears the media component.
let media = Media {
media: Some(vec![]),
..Default::default()
};
let override_request = EntityOverride {
entity: Some(Entity {
entity_id: Some(entity_id.to_string()),
media: Some(media),
..Default::default()
}),
provenance: Some(provenance),
};
let result = async {
client
.entities
.override_entity(entity_id, "media.media", &override_request, None)
.await?;
let entity = client.entities.get_entity(entity_id, None).await?;
println!("Entity: {:?}", entity.entity_id);
println!("Media: {:?}", entity.media);
Ok::<(), ApiError>(())
}
.await;
if let Err(e) = result {
eprintln!("Exception: {}", e);
}
Ok(())
}
```
```go title={"Go (gRPC)"} maxLines={25}
// This Go example is compatible with artifacts generated using
// the following grpc/go plugin: https://buf.build/anduril/lattice-sdk/sdks/main:grpc/go
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"schema-registry.developer.anduril.com/gen/go/anduril/lattice-sdk/grpc/go/anduril/entitymanager/v1/entitymanagerv1grpc"
entitymanagerv1 "schema-registry.developer.anduril.com/gen/go/anduril/lattice-sdk/protocolbuffers/go/anduril/entitymanager/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/protobuf/types/known/timestamppb"
)
func main() {
// Get environment variables
environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
// Check required environment variables
if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
fmt.Println("Missing required environment variables")
os.Exit(1)
}
// Setup authentication
auth := &BearerTokenAuth{
Token: environmentToken,
SandboxesToken: sandboxesToken,
}
// Setup gRPC connection options
opts := []grpc.DialOption{
grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
grpc.WithPerRPCCredentials(auth),
}
// Create gRPC connection
conn, err := grpc.NewClient(latticeEndpoint, opts...)
if err != nil {
log.Fatalf("Did not connect: %v", err)
}
defer conn.Close()
// Create EntityManager client
client := entitymanagerv1grpc.NewEntityManagerAPIClient(conn)
// Set the entity ID
entityID := ""
// Create context for the request
ctx := context.Background()
// Create empty media array
emptyMediaItems := []*entitymanagerv1.MediaItem{}
media := &entitymanagerv1.Media{
Media: emptyMediaItems,
}
// Create a provenance object with current timestamp
latestTimestamp := time.Now().UTC()
provenance := &entitymanagerv1.Provenance{
IntegrationName: "",
DataType: "",
SourceUpdateTime: timestamppb.New(latestTimestamp),
}
// Create an entity with empty media
entity := &entitymanagerv1.Entity{
EntityId: entityID,
Media: media,
}
// Create the override entity request
request := &entitymanagerv1.OverrideEntityRequest{
Entity: entity,
FieldPath: []string{"media.media"},
Provenance: provenance,
}
// Call the OverrideEntity method
_, err = client.OverrideEntity(ctx, request)
// Handle errors
if err != nil {
fmt.Printf("Exception: %v\n", err)
return
}
}
```
```py title={"Python (gRPC)"} maxLines={25}
# This Python example is compatible with artifacts generated using the following
# Buf plugins: https://schema-registry.developer.anduril.com/anduril/lattice-sdk/sdks/main:bufbuild/py
# and https://schema-registry.developer.anduril.com/anduril/lattice-sdk/sdks/main:connectrpc/py
import os
import sys
from datetime import datetime, timezone
from bearer_auth import create_client
from protobuf.wkt import Timestamp
from anduril.entitymanager.v1.entity_pub_pb import Entity, Provenance
from anduril.entitymanager.v1.entity_manager_api_pub_pb import OverrideEntityRequest
from anduril.entitymanager.v1.entity_manager_api_pub_connect import EntityManagerAPIClientSync
from anduril.entitymanager.v1.media_pub_pb import Media
def main():
environment_token = os.getenv("ENVIRONMENT_TOKEN")
lattice_endpoint = os.getenv("LATTICE_ENDPOINT")
sandboxes_token = os.getenv("SANDBOXES_TOKEN")
if not environment_token or not lattice_endpoint or not sandboxes_token:
print("Missing required environment variables", file=sys.stderr)
sys.exit(1)
# Create the API client over Connect gRPC with authentication
client = create_client(EntityManagerAPIClientSync, lattice_endpoint, environment_token, sandboxes_token)
entity_id = ""
# Empty Media component clears the existing list
media = Media(media=[])
latest_timestamp = Timestamp.from_datetime(datetime.now(timezone.utc))
provenance = Provenance(
integration_name="",
data_type="",
source_update_time=latest_timestamp,
)
entity = Entity(entity_id=entity_id, media=media)
request = OverrideEntityRequest(
entity=entity,
field_path=["media.media"],
provenance=provenance,
)
try:
client.override_entity(request)
except Exception as error:
print(f"Exception: {error}", file=sys.stderr)
if __name__ == "__main__":
main()
```
```rs title={"Rust (gRPC)"} maxLines={25}
// This Rust example is compatible with artifacts generated using
// the following grpc/rust plugin: https://buf.build/anduril/lattice-sdk/sdks/main:community/neoeinstein-tonic
mod bearer_auth;
use anduril_lattice_sdk_community_neoeinstein_prost::anduril::entitymanager::v1::{
Entity, Media, OverrideEntityRequest, Provenance,
};
use anduril_lattice_sdk_community_neoeinstein_tonic::anduril::entitymanager::v1::tonic::entity_manager_api_client::EntityManagerApiClient;
use bearer_auth::EnvironmentTokenAuth;
use prost_types::Timestamp;
use tonic::metadata::MetadataValue;
use tonic::transport::{Channel, ClientTlsConfig};
use tonic::Request;
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};
fn now_timestamp() -> Timestamp {
let d = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
Timestamp {
seconds: d.as_secs() as i64,
nanos: d.subsec_nanos() as i32,
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let environment_token = env::var("ENVIRONMENT_TOKEN")
.expect("ENVIRONMENT_TOKEN environment variable not set");
let lattice_endpoint = env::var("LATTICE_ENDPOINT")
.expect("LATTICE_ENDPOINT environment variable not set");
let sandboxes_token = env::var("SANDBOXES_TOKEN")
.expect("SANDBOXES_TOKEN environment variable not set");
let auth = EnvironmentTokenAuth::new(
environment_token,
sandboxes_token,
);
let tls_config = ClientTlsConfig::new().with_native_roots();
let channel = Channel::from_shared(format!("https://{}", lattice_endpoint))?
.tls_config(tls_config)?
.connect()
.await?;
let access_token = auth.get_token().await?;
let sandboxes_token = auth.sandboxes_token();
let auth_header: MetadataValue<_> = format!("Bearer {}", access_token).parse()?;
let sandbox_header: MetadataValue<_> = format!("Bearer {}", sandboxes_token).parse()?;
let mut client = EntityManagerApiClient::with_interceptor(
channel,
move |mut req: Request<()>| {
req.metadata_mut()
.insert("authorization", auth_header.clone());
req.metadata_mut()
.insert("anduril-sandbox-authorization", sandbox_header.clone());
Ok(req)
},
);
let entity_id = "".to_string();
// Create the override entity request with an empty media array
let request = Request::new(OverrideEntityRequest {
entity: Some(Entity {
entity_id,
media: Some(Media { media: vec![] }),
..Default::default()
}),
field_path: vec!["media.media".to_string()],
provenance: Some(Provenance {
integration_name: "".to_string(),
data_type: "".to_string(),
source_update_time: Some(now_timestamp()),
..Default::default()
}),
});
if let Err(e) = client.override_entity(request).await {
println!("Exception: {}", e);
}
Ok(())
}
```
If successful, you'll see an output similar to the following, confirming that the entity's `Media` component
is empty
```bash
Entity:
Media: None
```
## What's next?
* Learn more about the [Objects API](/reference/rest/objects/list-objects).
* Explore how to use objects with [Entities](/guides/entities/overview) to associate binary data with your Lattice entities.
> Getting metadata, and managing the lifecycle of objects using the Lattice SDK