You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Rust查询DynamoDB指定属性并返回JSON响应

代码里的核心问题

你的代码跑不通是几个硬伤导致的:

  • query_user 签名声明返回空值Result<(), Error>,最后却试图返回DynamoDB条目,返回类型和实际返回值完全不匹配,编译直接报错
  • 查询时写了.projection_expression("user_email"),只请求返回邮箱字段,根本没查用户名,就算解析成功也拿不到user_name
  • DynamoDB返回的条目是HashMap<String, AttributeValue>格式,不是直接带字段的结构体,不能直接用.user_name这种点号取值,得先从AttributeValue枚举里把字符串解出来
  • 你连续两次调用resp.items.unwrap_or_default(),第一次打印取第0个元素,第二次调用pop()会触发Rust的所有权规则报错,因为第一次调用已经把items的所有权拿走了
  • 每次请求都重新初始化AWS SDK客户端,冷启动延迟会高很多,应该在main里初始化一次,复用客户端
  • 空user_id的判断只打了错误日志,没有提前返回,代码会继续往下执行无效查询
修正后的可运行实现

不需要改现有依赖,补全缺失的导入、修正返回类型、修复解析逻辑即可:

use aws_sdk_dynamodb::{model::AttributeValue, Client, Region};
use aws_sdk_dynamodb::region::RegionProviderChain;
use lambda_runtime::{handler_fn, Context, Error};
use log::error;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Clone)]
struct CustomEvent {
    #[serde(rename = "user_id")]
    user_id: String,
}

#[derive(Serialize, Clone)]
struct CustomOutput {
    user_name: String,
    user_email: String,
}

#[tokio::main]
async fn main() -> std::result::Result<(), Error> {
    // SDK客户端只初始化一次,所有请求复用
    let region_provider = RegionProviderChain::first_try(Region::new("ap-south-1")).or_default_provider();
    let shared_config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&shared_config);

    // 通过clone把客户端传入handler,底层是Arc实现,clone成本极低
    let func = handler_fn(move |e, c| get_user_details(e, c, client.clone()));
    lambda_runtime::run(func).await?;
    Ok(())
}

async fn get_user_details(
    e: CustomEvent,
    _c: Context,
    client: Client,
) -> std::result::Result<CustomOutput, Error> {
    // 空参数直接返回错误,不往下执行无效查询
    if e.user_id.is_empty() {
        error!("User Id must be specified as user_id in the request");
        return Err("missing required parameter: user_id".into());
    }

    let user_info = query_user(&client, &e.user_id).await?;
    Ok(user_info)
}

async fn query_user(
    client: &Client,
    user_id: &str,
) -> Result<CustomOutput, Error> {
    let user_id_av = AttributeValue::S(user_id.to_string());

    let resp = client
        .query()
        .table_name("users")
        .key_condition_expression("#key = :value")
        .expression_attribute_names("#key", "id")
        // 明确指定要返回的两个字段,减少不必要的读容量消耗
        .projection_expression("user_name,user_email")
        .expression_attribute_values(":value", user_id_av)
        .send()
        .await?;

    // 只取一次items,避免所有权移动错误
    let mut items = resp.items.unwrap_or_default();
    // 处理用户不存在的场景
    if items.is_empty() {
        return Err("user not found".into());
    }
    let user_item = items.pop().unwrap();

    // 从AttributeValue枚举中解出字符串值,同时处理字段缺失/类型错误的情况
    let user_name = match user_item.get("user_name") {
        Some(AttributeValue::S(name)) => name.clone(),
        _ => return Err("invalid or missing field: user_name".into())
    };
    let user_email = match user_item.get("user_email") {
        Some(AttributeValue::S(email)) => email.clone(),
        _ => return Err("invalid or missing field: user_email".into())
    };

    Ok(CustomOutput {
        user_name,
        user_email
    })
}
优化提示

如果不想每次手动写match解析AttributeValue,可以新增依赖serde_dynamo = "3",给结构体加对应派生宏后,直接把DynamoDB返回的条目反序列化成自定义结构体,不需要逐字段解析:

// 加依赖后解析部分可以简化为一行
let user_info: CustomOutput = serde_dynamo::from_item(user_item)?;

lambda_runtime会自动把你返回的CustomOutput结构体序列化为JSON格式返回给调用方,不需要手动做JSON转换。注意字段名要和DynamoDB表里的实际字段名完全一致,DynamoDB字段名大小写敏感。

内容的提问来源于stack exchange,提问作者snipedown21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 04:03:25