use backstage_client::{entities::Entity, BackstageClient, ClientError};
use log::{error, info, warn};
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("INFO")).init();
let base_url =
env::var("BACKSTAGE_URL").unwrap_or_else(|_| "https://demo.backstage.io".to_string());
let token =
env::var("BACKSTAGE_TOKEN").expect("BACKSTAGE_TOKEN environment variable must be set");
info!("Connecting to Backstage at: {}", base_url);
let client = BackstageClient::new(&base_url, &token)?;
info!("\n=== Getting specific component ===");
let entity_name = env::var("ENTITY_NAME").unwrap_or_else(|_| "my-service".to_string());
match client
.get_entity::<Entity>("Component", None, &entity_name)
.await
{
Ok(entity) => {
display_entity_details(&entity);
}
Err(ClientError::ApiError { status: 404, .. }) => {
warn!("Component '{}' not found in default namespace", entity_name);
info!("Try setting ENTITY_NAME environment variable to an existing component");
}
Err(e) => {
error!("Error fetching component '{}': {}", entity_name, e);
}
}
info!("\n=== Getting specific API with namespace ===");
match client
.get_entity::<Entity>("API", Some("default"), "petstore-api")
.await
{
Ok(entity) => {
display_entity_details(&entity);
}
Err(ClientError::ApiError { status: 404, .. }) => {
warn!("API 'petstore-api' not found in 'default' namespace");
}
Err(e) => {
error!("Error fetching API: {}", e);
}
}
info!("\n=== Getting specific user ===");
let username = env::var("USERNAME").unwrap_or_else(|_| "guest".to_string());
match client
.get_entity::<Entity>("User", Some("default"), &username)
.await
{
Ok(entity) => {
display_entity_details(&entity);
}
Err(ClientError::ApiError { status: 404, .. }) => {
warn!("User '{}' not found", username);
info!("Try setting USERNAME environment variable to an existing user");
}
Err(e) => {
error!("Error fetching user '{}': {}", username, e);
}
}
info!("\n=== Getting specific system ===");
match client
.get_entity::<Entity>("System", Some("default"), "payment-system")
.await
{
Ok(entity) => {
display_entity_details(&entity);
}
Err(ClientError::ApiError { status: 404, .. }) => {
warn!("System 'payment-system' not found");
}
Err(e) => {
error!("Error fetching system: {}", e);
}
}
info!("\n=== Testing error handling ===");
match client
.get_entity::<Entity>("", Some("default"), "test")
.await
{
Ok(_) => {
warn!("Unexpected success with empty kind");
}
Err(ClientError::InvalidFilter(msg)) => {
info!("Correctly caught validation error: {}", msg);
}
Err(e) => {
error!("Unexpected error: {}", e);
}
}
info!("\n=== Get Specific Entity Examples Complete ===");
info!("You can customize the examples by setting these environment variables:");
info!(" ENTITY_NAME - Name of component to fetch (default: my-service)");
info!(" USERNAME - Name of user to fetch (default: guest)");
Ok(())
}
fn display_entity_details(entity: &Entity) {
info!("📋 Entity Details:");
info!(" Kind: {}", entity.kind());
info!(" Name: {}", entity.name());
info!(" Namespace: {}", entity.namespace());
info!(" Entity Ref: {}", entity.entity_ref());
if let Some(description) = entity.description() {
info!(" Description: {}", description);
}
let metadata = entity.metadata();
if let Some(uid) = &metadata.uid {
info!(" UID: {}", uid);
}
if let Some(tags) = entity.tags() {
if !tags.is_empty() {
info!(" Tags: {}", tags.join(", "));
}
}
if let Some(annotations) = entity.annotations() {
if !annotations.is_empty() {
info!(" Annotations:");
for (key, value) in annotations.iter().take(5) {
info!(" {}: {}", key, value);
}
if annotations.len() > 5 {
info!(" ... and {} more annotations", annotations.len() - 5);
}
}
}
if let Some(relations) = entity.relations() {
if !relations.is_empty() {
info!(" Relations:");
for relation in relations.iter().take(3) {
info!(
" {} -> {}:{}/{}",
relation.r#type,
relation.target.kind,
relation.target.namespace,
relation.target.name
);
}
if relations.len() > 3 {
info!(" ... and {} more relations", relations.len() - 3);
}
}
}
if let Some(view_url) = entity.get_annotation("backstage.io/view-url") {
info!(" 🔗 View URL: {}", view_url);
}
if let Some(source_location) = entity.get_annotation("backstage.io/managed-by-location") {
info!(" 📍 Source: {}", source_location);
}
info!(""); }