az-creates
自动收集自
crates/api/az-creates/README.md。
把 addzero-lib-jvm/lib/tool-jvm/network-call 里适合公开、适合沉淀为 Rust 工具库的常见 HTTP API,统一收口成一个可复用的创建器 crate。
其中音乐领域能力已经独立抽到 az-music,这里保留兼容创建入口,避免上层调用一次性断裂。
当前已落下这些常见能力:
- Maven Central 检索与文件下载
- 网易云音乐搜索与歌词查询
- Suno 音乐生成任务
- 天眼查普通接口
- 天眼查华为云签名接口
- 临时邮箱:Cloudflare Worker、mail.tm、Emailnator,以及 provider factory 注入入口
- 短信接码:5sim、Grizzly SMS,以及 provider factory 注入入口
- 邮件发送:SMTP sender,以及 sender factory 注入入口
添加依赖
如果你在这个 workspace 里直接使用:
[dependencies]
az-creates = { path = "../../api/az-creates" }
如果你从仓库外部引用当前本地 checkout:
[dependencies]
az-creates = { path = "/absolute/path/to/addzero-lib-rust/crates/api/az-creates" }
基础用法
use az_creates::Creates;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let maven = Creates::maven_central()?;
let latest = maven.get_latest_version("com.google.guava", "guava")?;
println!("latest guava version: {latest:?}");
let music = Creates::music_search()?;
let songs = music.search_songs("晴天", 5, 0)?;
println!("songs: {}", songs.len());
let temp_mail = Creates::temp_mail_mail_tm()?;
let mailbox = temp_mail.create_mailbox_and_login("demo", 12)?;
println!("mailbox: {}", mailbox.address);
Ok(())
}
Maven Central
use az_creates::Creates;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::maven_central()?;
let artifacts = api.search_by_group_id("com.google.guava", 5)?;
for artifact in artifacts {
println!(
"{}:{} -> {:?}",
artifact.group_id,
artifact.artifact_id,
artifact.resolved_version()
);
}
let pom = api.download_file(
"com.google.guava",
"guava",
"33.2.1-jre",
"guava-33.2.1-jre.pom",
)?;
println!("downloaded {} bytes", pom.len());
Ok(())
}
已封装的方法:
search_by_group_idsearch_by_artifact_idsearch_by_coordinatessearch_all_versionssearch_by_full_coordinatessearch_by_class_namesearch_by_fully_qualified_class_namesearch_by_sha1search_by_tagsearch_by_keywordget_latest_versionget_latest_version_by_group_iddownload_file
网易云音乐搜索
use az_creates::Creates;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::music_search()?;
let songs = api.search_songs("晴天", 5, 0)?;
let artists = api.search_artists("周杰伦", 3, 0)?;
let lyric = api.get_lyric(186016)?;
println!("songs: {}", songs.len());
println!("artists: {}", artists.len());
println!("lyric: {:?}", lyric.lrc.and_then(|item| item.lyric));
Ok(())
}
已封装的方法:
searchsearch_songssearch_artistssearch_albumssearch_playlistsget_lyricget_song_detailsearch_by_song_and_artistsearch_by_lyricget_lyric_by_song_nameget_lyrics_by_fragment
Suno
use az_creates::{Creates, SunoMusicRequest};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::suno("your-suno-token")?;
let task_id = api.generate_music(&SunoMusicRequest {
prompt: "写一首中文电子流行歌".to_owned(),
title: Some("电子晚风".to_owned()),
tags: Some("electropop, chinese".to_owned()),
..Default::default()
})?;
let task = api.wait_for_completion(task_id)?;
println!("audio url: {:?}", task.audio_url);
Ok(())
}
已封装的方法:
generate_musicgenerate_lyricsconcat_songsfetch_taskbatch_fetch_taskswait_for_completionwait_for_completion_withwait_for_batch_completionwait_for_batch_completion_with
天眼查
use az_creates::Creates;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::tianyancha("your-authorization", "your-x-auth-token")?;
let search = api.search_company("河南中洛佳科技有限公司", 1, 10, "0")?;
let detail = api.get_base_info(3398690435)?;
println!("search total: {:?}", search.company_total);
println!("detail name: {}", detail.name);
Ok(())
}
已封装的方法:
search_companyget_base_info
天眼查华为云签名版
这个版本会在 Rust 侧真实生成 SDK-HMAC-SHA256 签名头,而不是简单拼 URL。
use az_creates::Creates;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::tianyancha_huawei("your-ak", "your-sk")?;
let result = api.search_companies("洛阳古城机械有限公司", 1, 10)?;
println!("records: {}", result.company_list.len());
Ok(())
}
已封装的方法:
search_companies
Temp Mail
use az_creates::{Creates, TempMailNewAddressRequest, TempMailPageRequest};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = Creates::temp_mail_cloudflare("https://mail.example.com")?;
let address = api.new_address(&TempMailNewAddressRequest::new("az", "example.com"))?;
println!("address: {}", address.address);
let messages = api.list_parsed_mails(&address.jwt, TempMailPageRequest::default())?;
for message in messages.results {
println!("message: {}", message.subject);
}
Ok(())
}
Provider factory 注入:
use az_creates::{
Creates, TempMailApiConfig, TempMailProviderConfig, TempMailProviderKind,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let provider = Creates::temp_mail_provider(TempMailProviderConfig::MailTm(
TempMailApiConfig::builder("https://api.mail.tm").build()?,
))?;
assert_eq!(provider.provider_kind(), TempMailProviderKind::MailTm);
Ok(())
}
已封装的方法:
temp_mail_cloudflaretemp_mail_cloudflare_with_configtemp_mail_mail_tmtemp_mail_mail_tm_with_configtemp_mail_emailnatortemp_mail_emailnator_with_configtemp_mail_providertemp_mail_provider_with_factory
SMS provider
use az_creates::{
BuiltinSmsProviderFactory, Creates, FivesimConfig, SmsProviderConfig, SmsProviderFactory,
SmsProviderKind,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = FivesimConfig::builder("token").build()?;
let provider = Creates::sms_provider(SmsProviderConfig::from(config))?;
assert_eq!(provider.provider_kind(), SmsProviderKind::Fivesim);
let factory: &dyn SmsProviderFactory = &BuiltinSmsProviderFactory;
let provider = Creates::fivesim_sms_with_factory(factory, "token")?;
assert_eq!(provider.provider_kind(), SmsProviderKind::Fivesim);
Ok(())
}
已封装的方法:
sms_providersms_provider_with_factoryfivesim_smsfivesim_sms_with_factory
Email sender
use az_creates::{
BuiltinEmailSenderFactory, Creates, EmailConfig, EmailSenderConfig, EmailSenderFactory,
EmailSenderKind,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = EmailConfig::builder("smtp.example.com", "user@example.com", "secret").build()?;
let sender_config = EmailSenderConfig::from(config.clone());
assert_eq!(sender_config.kind(), EmailSenderKind::Smtp);
assert_eq!(EmailSenderKind::Smtp.code(), "smtp");
let sender = Creates::email_sender(sender_config)?;
drop(sender);
let factory: &dyn EmailSenderFactory = &BuiltinEmailSenderFactory;
let sender = Creates::smtp_email_with_factory(factory, config)?;
drop(sender);
Ok(())
}
已封装的方法:
email_senderemail_sender_with_factorysmtp_emailsmtp_email_with_factory
自定义配置
use std::time::Duration;
use az_creates::{ApiConfig, Creates};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ApiConfig::builder("https://api.vectorengine.ai")
.connect_timeout(Duration::from_secs(5))
.request_timeout(Duration::from_secs(15))
.user_agent("my-app/1.0.0")
.build()?;
let api = Creates::suno_with_config("your-suno-token", config)?;
let lyrics = api.generate_lyrics("写一段中文民谣歌词")?;
println!("lyrics: {lyrics}");
Ok(())
}
测试覆盖
当前 crate 已用本地 fake server 覆盖这些真实请求流程:
- Maven 检索与下载
- 网易云音乐搜索、歌词、详情与二次过滤
- Suno 创建任务、查任务与轮询完成
- 天眼查 header 注入
- 天眼查华为云查询参数与签名头生成
范围说明
这次没有直接把 network-call 全量照搬到 Rust:
- 浏览器自动化、支付、私有供应商接入这类模块,不适合在当前仓库做一层“看起来统一、实际不可复用”的硬迁移
az-api-weather这类依赖特定站点抓取细节和 cookie 的实现,稳定性不足,不适合作为通用公开 API 默认暴露- 后续如果确认某个接口长期稳定,再按 crate 继续补进
az-creates