- 数据工程
- 数据湖
- 大数据
- 对象存储
- 后端
【免费下载链接】lakeFS
lakeFS - Data version control for your data lake | Git for data
导读
ObjectsApi是 lakeFS Rust 客户端(lakefs_sdk)中负责对象(Object)级数据操作的 API 集合,覆盖对象的上传、下载、复制、删除、元数据查询与修改等完整生命周期。本文以clients/rust/docs/ObjectsApi.md为核心骨架,结合clients/rust/src/apis/objects_api.rs的实现代码与服务端pkg/api/controller.go的对应逻辑,逐一剖析全部 10 个端点的函数签名、参数语义、认证与返回类型,并给出可直接运行的 Rust 调用示例。读完本文,你将能够用 Rust 实现对 lakeFS 分支对象的全链路读写与版本管理操作。
一、API 概览:方法与端点速查
ObjectsApi中所有 URI 均以/api/v1为基准(base path)。文档中列出的全部端点如下表:
| Method(Rust 函数) | HTTP 请求 | 说明 |
|---|---|---|
| copy_object | POST /repositories/{repository}/branches/{branch}/objects/copy | 创建对象的副本 |
| delete_object | DELETE /repositories/{repository}/branches/{branch}/objects | 删除对象,对象缺失时不会返回 NotFound 错误 |
| delete_objects | POST /repositories/{repository}/branches/{branch}/objects/delete | 批量删除对象,缺失对象不返回 NotFound 错误 |
| get_object | GET /repositories/{repository}/refs/{ref}/objects | 获取对象内容 |
| get_underlying_properties | GET /repositories/{repository}/refs/{ref}/objects/underlyingProperties | 获取对象在底层存储上的属性 |
| head_object | HEAD /repositories/{repository}/refs/{ref}/objects | 检查对象是否存在 |
| list_objects | GET /repositories/{repository}/refs/{ref}/objects/ls | 列出指定前缀下的对象 |
| stat_object | GET /repositories/{repository}/refs/{ref}/objects/stat | 获取对象元数据 |
| update_object_user_metadata | PUT /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | 重写(全部)对象元数据 |
| upload_object | POST /repositories/{repository}/branches/{branch}/objects | 上传对象 |
所有端点均支持三种认证方式:basic_auth(HTTP Basic)、cookie_auth(会话 Cookie)与jwt_token(Bearer Token)。从 Rust 实现看,认证实际通过Configuration中的basic_auth与bearer_access_token字段注入请求头(见 clients/rust/src/apis/configuration.rs)。
在函数签名中,repository、branch、ref、path等路径/查询参数在实现中都会经过crate::apis::urlencode进行 URL 编码后拼接到请求行,因此仓库名、分支名中包含特殊字符时无需手动转义(见 clients/rust/src/apis/objects_api.rs)。
一个重要的语义区分:ref与branch
- 只读端点(
get_object、head_object、list_objects、stat_object、get_underlying_properties)的路径参数是ref,文档明确说明“a reference (could be either a branch or a commit ID)”,即既可以传分支名,也可以传提交 ID(Commit ID),实现对历史版本的只读访问; - 写端点(
copy_object、delete_object、delete_objects、upload_object、update_object_user_metadata)的路径参数是branch,因为写入必须发生在可变的分支之上。
二、copy_object:创建对象的副本
pub async fn copy_object( configuration: &configuration::Configuration, repository: &str, branch: &str, // 目标分支 dest_path: &str, // 目标路径(相对分支) object_copy_creation: models::ObjectCopyCreation, // 复制参数(请求体) ) -> Result<models::ObjectStats, Error<CopyObjectError>>- HTTP 请求:
POST /repositories/{repository}/branches/{branch}/objects/copy,dest_path以查询参数传递,请求体为 JSON。 - Content-Type:
application/json;Accept:application/json。 - 返回类型:
models::ObjectStats,即复制后新对象的统计信息。
ObjectCopyCreation 请求体结构
ObjectCopyCreation(见 clients/rust/src/models/object_copy_creation.rs)包含以下字段:
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
src_path | String | 必填 | 源对象路径(相对 ref) |
src_ref | Option<String> | 可选 | 源引用,为空时默认使用目标分支作为源 ref |
force | Option<bool> | 可选 | 是否强制覆盖目标路径上已存在的对象 |
shallow | Option<bool> | 可选 | 创建浅拷贝(不复制实际数据)。目前仅支持同一仓库、同一分支内的浅拷贝;浅拷贝对象可能与垃圾回收(GC)和分支保留策略产生冲突,需谨慎使用 |
构造请求体示例
let copy_creation = models::ObjectCopyCreation { src_path: "data/raw.parquet".to_string(), src_ref: Some("main".to_string()), force: Some(true), shallow: Some(false), }; let stats = objects_api::copy_object(&config, "my-repo", "feature-1", "data/copied.parquet", copy_creation).await?; println!("copied to: {}", stats.path);服务端行为印证
在服务端 pkg/api/controller.go 中,CopyObject做了以下校验与处理:
- 权限校验:调用方必须同时拥有源路径的
fs:ReadObject权限和目标路径的fs:WriteObject权限(对应 pkg/permissions/actions.go 中定义的ReadObjectAction与WriteObjectAction); - 分支存在性检查:目标
branch不存在时返回404 branch not found; - 默认源 ref:
src_ref为空时回退为branch本身(与 SDK 文档描述一致); - 最终调用
Catalog.CopyEntry完成复制,并将源对象的 checksum、size、content_type、物理地址等打包成ObjectStats返回。
需要说明:从 SDK 生成的代码看,copy_object的请求体是整体 JSON 序列化发送的,且src_path为必填;而shallow、force等为可选字段,序列化时会通过skip_serializing_if = "Option::is_none"自动省略空值。
三、delete_object 与 delete_objects:删除对象
3.1 单个删除 delete_object
pub async fn delete_object( configuration: &configuration::Configuration, repository: &str, branch: &str, path: &str, // 相对分支的路径 force: Option<bool>, // 默认 false no_tombstone: Option<bool>, // 默认 false,实验性 ) -> Result<(), Error<DeleteObjectError>>- HTTP 请求:
DELETE /repositories/{repository}/branches/{branch}/objects,path、force、no_tombstone均为查询参数。 - 返回类型:空响应体(成功时返回
Ok(()))。 - 文档特别注明:对象缺失时不会返回 NotFound 错误(删除是幂等的)。
3.2 批量删除 delete_objects
pub async fn delete_objects( configuration: &configuration::Configuration, repository: &str, branch: &str, path_list: models::PathList, // 请求体:待删除路径列表 force: Option<bool>, no_tombstone: Option<bool>, ) -> Result<models::ObjectErrorList, Error<DeleteObjectsError>>- HTTP 请求:
POST /repositories/{repository}/branches/{branch}/objects/delete,请求体为 JSON,查询参数为force、no_tombstone。 - Content-Type:
application/json;Accept:application/json。 - 返回类型:
models::ObjectErrorList,即逐个路径的操作错误列表。
参数说明与请求体构造
force:类型Option<bool>,默认false。从服务端实现看,它控制删除时的强制程度(例如绕过对象的不可删除保护);传入Some(true)时才会在查询串中携带force=true(见 objects_api.rs)。no_tombstone:类型Option<bool>,默认false,文档标注EXPERIMENTAL,语义为“在可能的情况下无 tombstone 删除条目”。PathList(见 clients/rust/src/models/path_list.rs)只有一个字段paths: Vec<String>:
let path_list = models::PathList::new(vec![ "logs/2024/01.log".to_string(), "logs/2024/02.log".to_string(), ]); let errors = objects_api::delete_objects(&config, "my-repo", "main", path_list, Some(false), None).await?; // ObjectErrorList.errors: Vec<ObjectError>ObjectError 结构
批量删除的返回类型ObjectErrorList由Vec<ObjectError>组成(见 clients/rust/src/models/object_error.rs):
| 字段 | 类型 | 说明 |
|---|---|---|
status_code | i32 | 该路径操作对应的 HTTP 状态码 |
message | String | 状态码的简短说明 |
path | Option<String> | 受影响的路径 |
四、get_object:下载对象内容
pub async fn get_object( configuration: &configuration::Configuration, repository: &str, r#ref: &str, // 分支名或提交 ID path: &str, // 相对 ref 的路径 range: Option<&str>, // 要获取的字节范围(Range 头) if_none_match: Option<&str>, // 仅当对象 ETag 不匹配时返回响应(If-None-Match 头) presign: Option<bool>, // 是否返回预签名 URL ) -> Result<std::path::PathBuf, Error<GetObjectError>>- HTTP 请求:
GET /repositories/{repository}/refs/{ref}/objects,path、presign为查询参数;range通过Range请求头传递,if_none_match通过If-None-Match请求头传递(见 objects_api.rs)。 - Accept:
application/octet-stream, application/json。 - 返回类型:
std::path::PathBuf。
使用说明
presign:当传入Some(true)时,响应返回的是一个预签名 HTTP URL(而非内容本身);从ObjectStats模型的定义可知,预签名 URL 具有过期时间,且可能因认证 token 即将过期而被截短(见 clients/rust/src/models/object_stats.rs)。SDK 层此模式下返回的PathBuf代表下载后保存到本地文件系统的路径。range:支持 HTTP Range 语义,例如Some("bytes=0-1023"),用于断点续传或只读部分数据。if_none_match:用于条件请求,例如传入对象当前 ETag,可避免重复下载未变更的内容。
五、head_object:检查对象是否存在
pub async fn head_object( configuration: &configuration::Configuration, repository: &str, r#ref: &str, path: &str, range: Option<&str>, ) -> Result<(), Error<HeadObjectError>>- HTTP 请求:
HEAD /repositories/{repository}/refs/{ref}/objects,path为查询参数,range为Range请求头。 - 返回类型:空响应体(
Ok(())表示对象存在;Err(Error::ResponseError(...))表示不存在或请求失败)。 - 该端点是
get_object的轻量版,只校验对象的存在性与元数据,不传输内容,适合作为批处理任务前的存在性检查。从 SDK 生成的错误枚举看,HeadObjectError覆盖 400/401/404/410/416/429 等状态码(objects_api.rs)。
六、get_underlying_properties:查询底层存储属性
pub async fn get_underlying_properties( configuration: &configuration::Configuration, repository: &str, r#ref: &str, path: &str, ) -> Result<models::UnderlyingObjectProperties, Error<GetUnderlyingPropertiesError>>- HTTP 请求:
GET /repositories/{repository}/refs/{ref}/objects/underlyingProperties,path为查询参数。 - 返回类型:
models::UnderlyingObjectProperties。 - Accept:
application/json。
该端点用于查询对象在底层对象存储(S3、GS、Azure Blob 等)上的原生属性。UnderlyingObjectProperties(见 clients/rust/src/models/underlying_object_properties.rs)当前只有一个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
storage_class | Option<Option<String>> | 底层存储上的存储类别(双层 Option 用于区分“未返回”与“显式 null”,由serde_with::rust::double_option处理) |
注意:该端点返回的是底层存储的属性,与stat_object返回的 lakeFS 元数据(ObjectStats)不同。
七、list_objects:列出前缀下的对象
pub async fn list_objects( configuration: &configuration::Configuration, repository: &str, r#ref: &str, user_metadata: Option<bool>, // 默认 true presign: Option<bool>, after: Option<&str>, // 返回此值之后的条目 amount: Option<i32>, // 返回条目数量,默认 100 delimiter: Option<&str>, // 用于按公共前缀分组的分隔符 prefix: Option<&str>, // 只返回以该值为前缀的条目 ) -> Result<models::ObjectStatsList, Error<ListObjectsError>>- HTTP 请求:
GET /repositories/{repository}/refs/{ref}/objects/ls,全部以查询参数传递。 - 返回类型:
models::ObjectStatsList。 - Accept:
application/json。
参数语义详解
| 参数 | 默认值 | 作用 |
|---|---|---|
user_metadata | true | 结果中是否包含用户自定义元数据(ObjectStats.metadata) |
presign | 无 | 结果中的physical_address是否返回预签名 HTTP URL |
after | 无 | 分页游标,返回该值之后的条目(配合Pagination.next_offset使用) |
amount | 100 | 每页返回的最大条目数 |
delimiter | 无 | 类似 S3 ListObjects 的分隔符(如/),将公共前缀折叠为path_type = common_prefix的条目 |
prefix | 无 | 前缀过滤,只列出以该前缀开头的对象 |
返回结构 ObjectStatsList
ObjectStatsList(见 clients/rust/src/models/object_stats_list.rs)包含pagination: Pagination与results: Vec<ObjectStats>。Pagination(见 clients/rust/src/models/pagination.rs)提供:
| 字段 | 类型 | 说明 |
|---|---|---|
has_more | bool | 是否还有下一页 |
next_offset | String | 用于获取下一页的游标值 |
results | i32 | 本页结果数量 |
max_per_page | i32 | 每页最大条目数 |
分页遍历示例
let mut after: Option<String> = None; loop { let page = objects_api::list_objects( &config, "my-repo", "main", Some(true), None, after.as_deref(), Some(100), Some("/"), Some("data/"), ).await?; for obj in &page.results { println!("{} ({:?})", obj.path, obj.path_type); } if !page.pagination.has_more { break; } after = Some(page.pagination.next_offset.clone()); }关于 path_type 与 ObjectStats
ObjectStats(见 clients/rust/src/models/object_stats.rs)是对象操作中最核心的返回模型,字段包括:path、path_type(common_prefix/object)、physical_address(底层存储原生 URI,如s3://...、gs://...;presign 时则为 HTTP URL)、physical_address_expiry(预签名 URL 过期时间,Unix 秒)、checksum、size_bytes、mtime、metadata(用户自定义元数据 Map)、content_type。其中size_bytes、metadata、content_type在返回时通常都会填充,但在客户端上传等场景下允许缺省。
八、stat_object:获取对象元数据
pub async fn stat_object( configuration: &configuration::Configuration, repository: &str, r#ref: &str, path: &str, user_metadata: Option<bool>, // 默认 true presign: Option<bool>, ) -> Result<models::ObjectStats, Error<StatObjectError>>- HTTP 请求:
GET /repositories/{repository}/refs/{ref}/objects/stat,path、user_metadata、presign为查询参数。 - 返回类型:
models::ObjectStats(结构详见上文)。 - Accept:
application/json。
典型用途
- 读取对象大小、checksum、mtime,用于增量同步判断;
- 携带
presign=true获取可直接下载的预签名 URL 并交给其他工具消费; - 结合
head_object实现“先 stat 再决定是否下载”的缓存策略。
九、update_object_user_metadata:重写对象元数据
pub async fn update_object_user_metadata( configuration: &configuration::Configuration, repository: &str, branch: &str, // 要更新的分支 path: &str, // 相对分支的对象路径 update_object_user_metadata: models::UpdateObjectUserMetadata, // 请求体 ) -> Result<(), Error<UpdateObjectUserMetadataError>>- HTTP 请求:
PUT /repositories/{repository}/branches/{branch}/objects/stat/user_metadata,path为查询参数,请求体为 JSON。 - Content-Type:
application/json;Accept:application/json。 - 返回类型:空响应体。
- 语义为rewrite (all) object metadata:即整体重写对象的用户元数据,而非增量合并。
UpdateObjectUserMetadata(见 clients/rust/src/models/update_object_user_metadata.rs)只有一个字段set: HashMap<String, String>,表示要设置的完整元数据键值集合:
let mut metadata = std::collections::HashMap::new(); metadata.insert("owner".to_string(), "data-team".to_string()); metadata.insert("stage".to_string(), "prod".to_string()); let req = models::UpdateObjectUserMetadata::new(metadata); objects_api::update_object_user_metadata(&config, "my-repo", "main", "data/raw.parquet", req).await?;由于是“整体重写”,调用前应先用stat_object获取现有元数据,再在内存中合并修改后整体提交,避免丢失已有键值。
十、upload_object:上传对象
pub async fn upload_object( configuration: &configuration::Configuration, repository: &str, branch: &str, path: &str, // 相对分支的路径 if_none_match: Option<&str>, // "*":仅在路径尚不存在时允许上传 if_match: Option<&str>, // 对象的 ETag:仅当当前 ETag 匹配时允许操作 storage_class: Option<&str>, // 已弃用,未来版本不再支持 force: Option<bool>, // 默认 false content: Option<std::path::PathBuf>, // 单文件上传,必须命名为 "content" ) -> Result<models::ObjectStats, Error<UploadObjectError>>- HTTP 请求:
POST /repositories/{repository}/branches/{branch}/objects,path、storageClass、force为查询参数;if_none_match通过If-None-Match请求头、if_match通过If-Match请求头传递。 - Content-Type:
multipart/form-data或application/octet-stream;Accept:application/json。 - 返回类型:
models::ObjectStats(上传完成后对象的统计信息)。
参数语义与注意事项
| 参数 | 说明 |
|---|---|
if_none_match | 设为"*"可实现原子性“仅当该路径尚无对象时才允许上传”(即 create-if-absent);其他值不支持。服务端在 pkg/api/controller.go 中对该值做了专门处理:若路径已存在则返回412 Precondition Failed,并将条件封装为 graveler 的WithCondition参与写入 |
if_match | 设为对象当前 ETag,可实现 compare-and-set 式原子更新,防止并发覆盖 |
storage_class | 文档明确标注Deprecated,未来版本将移除该能力 |
force | 默认false,用于控制是否强制覆盖已有对象 |
content | 单文件上传,multipart 表单中的文件字段必须命名为"content" |
服务端双通道实现
服务端UploadObject(pkg/api/controller.go)根据Content-Type走两条路径:
application/octet-stream(非 multipart):直接把请求体作为对象内容写入底层存储(upload.WriteBlob),适合流式上传;multipart/form-data:解析 multipart 中的content字段,逐段读取并上传。
同时服务端会先校验调用方对目标路径是否拥有fs:WriteObject权限、仓库与分支是否存在(分支不存在直接返回404 branch not found,避免在错误分支上白白上传大文件)。
注意:当前 SDK 生成的
upload_object对content参数只创建了空 multipart form,代码中留有// TODO: support file upload for 'content' parameter(见 objects_api.rs)。因此在当前生成版本中,若需要携带文件内容上传,可改用application/octet-stream方式直传(自行构造请求),或关注该 TODO 的后续实现。
十一、错误处理与认证配置
类型化错误枚举
objects_api.rs为每个端点定义了对应的类型化错误枚举(如CopyObjectError、UploadObjectError、GetObjectError等),每个枚举通过#[serde(untagged)]反序列化服务端返回的 JSON 错误体,并覆盖该端点可能的 HTTP 状态码。例如:
GetObjectError:400 / 401 / 404 / 410 / 416 / 429(410 Gone 与 416 Range Not Satisfiable 常见于对象过期与非法 Range);UploadObjectError:400 / 401 / 403 / 404 / 412 / 429 / 501(412 对应If-None-Match: *冲突;501 对应未支持的能力,如已弃用的 storage class 相关操作);- 所有端点均包含
429 Too Many Requests(限流)与DefaultResponse(未预期错误)。
调用时通过Error<XxxError>的ResponseError变体即可拿到status、content与反序列化后的错误实体:
match objects_api::stat_object(&config, "my-repo", "main", "nope.txt", Some(true), None).await { Ok(stats) => println!("{} bytes", stats.size_bytes.unwrap_or(0)), Err(e) => match e { apis::Error::ResponseError(resp) => { eprintln!("HTTP {}: {}", resp.status, resp.content); } _ => eprintln!("transport error: {:?}", e), }, }配置与认证
所有端点共享同一个Configuration(clients/rust/src/apis/configuration.rs),默认base_path为/api/v1。在真实部署中应将其替换为完整的 lakeFS 服务地址,例如http://localhost:8000/api/v1,并配置认证:
let config = apis::configuration::Configuration { base_path: "http://localhost:8000/api/v1".to_owned(), basic_auth: Some(( "AKIAIOSFODNN7EXAMPLE".to_owned(), Some("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".to_owned()), )), ..Default::default() };lakeFS 的访问密钥对(Access Key / Secret Key)即对应 HTTP Basic 认证的用户名/密码;若使用 Bearer Token(如jwt_token),则设置bearer_access_token字段。每次调用传入&config即可,reqwest::Client在内部复用连接。
十二、对象操作的最佳实践小结
综合文档与源码,用ObjectsApi构建对象工作流时有几点值得注意:
- 读写分离的 ref 语义:查询/下载一律走
ref(分支名或 Commit ID),实现“读历史版本”;写入走branch,保证数据只落在可变的当前分支上。 - 原子写保护:需要“不存在才创建”时用
upload_object(if_none_match=Some("*"));需要“防并发覆盖”时用if_match=Some(etag)(配合stat_object先取 ETag)。 - 分页与前缀:
list_objects用prefix过滤 +after/Pagination.next_offset游标翻页,delimiter可模拟目录层级(common_prefix)。 - 预签名访问:
get_object、stat_object、list_objects都支持presign=true,可将底层对象存储的访问以临时 URL 形式安全地交给第三方消费。 - 幂等删除:
delete_object/delete_objects对缺失对象不报错,适合在清理任务中直接使用;批量删除返回ObjectErrorList,可针对每个路径的错误单独处理。 - 元数据整体重写:
update_object_user_metadata是“全量替换”语义,修改前先stat_object拉取现值,避免误丢键值。
以上即为ObjectsApi的完整端点图谱与实战要点。进一步可参考 SDK 目录下的模型文档(如 ObjectStats、ObjectCopyCreation)以及服务端实现 pkg/api/controller.go,以便在需要时深入定制行为。
- 数据工程
- 数据湖
- 大数据
- 对象存储
- 后端
【免费下载链接】lakeFS
lakeFS - Data version control for your data lake | Git for data
相关推荐
lakeFS Java SDK ObjectsApi 完全指南:对象读写、复制、删除与元数据操作实战
lakeFS Java SDK ObjectsApi 完全指南:对象读写、复制、删除与元数据操作实战 本指南以 lakeFS 官方 Java SDK( io.l
数据工程数据湖大数据对象存储后端lakeFS Python SDK 数据对象操作完全指南:ObjectsApi 十个 API 的实战用法与源码解析
lakeFS Python SDK 数据对象操作完全指南:ObjectsApi 十个 API 的实战用法与源码解析 本文以 lakeFS 官方 Python S
数据工程数据湖大数据对象存储后端lakeFS Rust SDK 对象复制:ObjectCopyCreation 模型详解与 copy_object 实战
lakeFS Rust SDK 对象复制:ObjectCopyCreation 模型详解与 copy_object 实战 导读 本文围绕 lakeFS Rust
数据工程数据湖大数据对象存储后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考