mcpField
A
appwrite-rust

appwrite-rust

github.com/appwrite開発28406 回インストール1 週間前に更新
リポジトリ

appwrite-rust について

サーバーサイドのRust開発者向けに、Appwriteの非同期SDKの使い方を案内します。ユーザー、データベース、ストレージ、関数などを扱います。

主な機能

  1. 01非同期のサーバーサイドクライアント
  2. 02ユーザー管理
  3. 03TablesDBのデータ操作
  4. 04ファイルストレージと関数呼び出し
  5. 05クエリ、権限、エラー処理

活用シーン

  1. 01RustサービスでAppwriteのユーザーを管理
  2. 02テーブルを作成してデータを検索
  3. 03ファイルをアップロードしてアクセス権を管理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/appwrite/skills --skill appwrite-rust

インストール後、Claude Code で/appwrite-rustを入力して読み込まれたか確認します。

詳細

Appwrite Rust SDK

インストール

cargo add appwrite
cargo add tokio --features full
cargo add serde_json

クライアントのセットアップ

Rust SDK は非同期です。Tokio ランタイムから使用し、サーバー側では API キーで認証してください。

use appwrite::Client;
use std::env;

let client = Client::new()
    .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
    .set_project(env::var("APPWRITE_PROJECT_ID")?)
    .set_key(env::var("APPWRITE_API_KEY")?);
サーバーの完全なスケルトン
use appwrite::query::Query;
use appwrite::services::Users;
use appwrite::Client;
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new()
        .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
        .set_project(env::var("APPWRITE_PROJECT_ID")?)
        .set_key(env::var("APPWRITE_API_KEY")?);

    let users = Users::new(&client);
    let _list = users
        .list(Some(vec![Query::limit(25).to_string()]), None, Some(true))
        .await?;

    Ok(())
}

コード例

ユーザー管理
use appwrite::id::ID;
use appwrite::query::Query;
use appwrite::services::Users;

let users = Users::new(&client);

// Create user
let _user = users
    .create(
        ID::unique(),
        Some("[email protected]"),
        None,
        Some("password123"),
        Some("User Name"),
    )
    .await?;

// List users
let _list = users
    .list(Some(vec![Query::limit(25).to_string()]), None, Some(true))
    .await?;

// Get user
let _fetched = users.get("[USER_ID]").await?;

// Delete user
users.delete("[USER_ID]").await?;
データベース操作

注記: 新しいコードでは TablesDB を使用してください。既存のプロジェクトがレガシーの Databases API に明示的に依存している場合に限り、Databases を使用してください。

Rust SDK の呼び出し規約: メソッドは非同期で、位置引数を使用し、オプションの API パラメーターは Option<T> として表します。設定しないオプション値には None を渡してください。

use appwrite::id::ID;
use appwrite::permission::Permission;
use appwrite::query::Query;
use appwrite::role::Role;
use appwrite::services::TablesDB;
use serde_json::json;

let tables_db = TablesDB::new(&client);

// Create database
let _database = tables_db
    .create(ID::unique(), "My Database", Some(true))
    .await?;

// Create table
let _table = tables_db
    .create_table(
        "[DATABASE_ID]",
        ID::unique(),
        "articles",
        Some(vec![
            Permission::read(Role::any()).to_string(),
            Permission::create(Role::users(None)).to_string(),
        ]),
        Some(true),
        Some(true),
        None,
        None,
    )
    .await?;

// Create row
let _row = tables_db
    .create_row(
        "[DATABASE_ID]",
        "[TABLE_ID]",
        ID::unique(),
        json!({
            "title": "Hello World",
            "done": false
        }),
        None,
        None,
    )
    .await?;

// Query rows
let _rows = tables_db
    .list_rows(
        "[DATABASE_ID]",
        "[TABLE_ID]",
        Some(vec![
            Query::equal("done", false).to_string(),
            Query::limit(10).to_string(),
        ]),
        None,
        Some(true),
        None,
    )
    .await?;

// Get row
let _row = tables_db
    .get_row("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]", None, None)
    .await?;

// Update row
let _updated = tables_db
    .update_row(
        "[DATABASE_ID]",
        "[TABLE_ID]",
        "[ROW_ID]",
        Some(json!({ "done": true })),
        None,
        None,
    )
    .await?;

// Delete row
tables_db
    .delete_row("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]", None)
    .await?;
文字列カラムの型

注記: レガシーの string カラム型は非推奨です。新しいテーブルでは、明示的な文字列型を使用してください。

型最大文字数インデックス作成ストレージ
varchar16,383フルインデックス(サイズが 768 以下の場合)行内
text16,383プレフィックスのみ行外
mediumtext4,194,303プレフィックスのみ行外
longtext1,073,741,823プレフィックスのみ行外
  • varchar は行内に保存され、64 KB の行サイズ上限にカウントされます。名前、スラッグ、識別子など、短くインデックスを作成するフィールドに適しています。
  • text、mediumtext、longtext は行外に保存されるため、行サイズの上限を消費しません。これらの型では size は不要です。
use appwrite::enums::{OrderBy, TablesDBIndexType};

// Short, indexed string
let _title = tables_db
    .create_varchar_column(
        "[DATABASE_ID]",
        "[TABLE_ID]",
        "title",
        255,
        true,
        None,
        None,
        None,
    )
    .await?;

// Off-page longer text
let _summary = tables_db
    .create_text_column("[DATABASE_ID]", "[TABLE_ID]", "summary", false, None, None, None)
    .await?;

let _body = tables_db
    .create_mediumtext_column("[DATABASE_ID]", "[TABLE_ID]", "body", false, None, None, None)
    .await?;

let _raw_data = tables_db
    .create_longtext_column("[DATABASE_ID]", "[TABLE_ID]", "raw_data", false, None, None, None)
    .await?;

// Index only the varchar column fully.
let _index = tables_db
    .create_index(
        "[DATABASE_ID]",
        "[TABLE_ID]",
        "title_idx",
        TablesDBIndexType::Key,
        vec!["title"],
        Some(vec![OrderBy::Asc]),
        Some(vec![255]),
    )
    .await?;
クエリメソッド

TablesDB メソッドは、クエリに Option<Vec<String>> を受け取ります。各 Query を文字列に変換してください。

use appwrite::query::Query;
use serde_json::Value;

let queries = vec![
    Query::equal("status", "published").to_string(),
    Query::not_equal("archived", true).to_string(),
    Query::greater_than("views", 100).to_string(),
    Query::less_than_equal("priority", 5).to_string(),
    Query::between("score", 1, 100).to_string(),
    Query::is_not_null("publishedAt").to_string(),
    Query::search("title", "rust appwrite").to_string(),
    Query::contains("tags", "rust").to_string(),
    Query::order_desc("$createdAt").to_string(),
    Query::limit(25).to_string(),
    Query::offset(50).to_string(),
];

let multi_value = Query::equal(
    "status",
    Value::Array(vec![
        Value::String("draft".to_string()),
        Value::String("published".to_string()),
    ]),
)
.to_string();

let related = Query::relationship(
    "comments",
    vec![
        Query::equal("approved", true).to_string(),
        Query::limit(25).to_string(),
    ],
)
.to_string();

// Aggregations (pass "" for no alias)
let aggregations = vec![
    Query::count("*", "total").to_string(),
    Query::sum("amount", "revenue").to_string(),
    Query::avg("score", "avgScore").to_string(),
    Query::min("price", "minPrice").to_string(),
    Query::max("price", "maxPrice").to_string(),
];

// Grouping
let grouping = vec![
    Query::group_by(["status", "year"]).to_string(),
    Query::having([Query::greater_than("total", 1).to_string()]).to_string(),
    Query::distinct().to_string(),
];

// Joins (table id, left key, right key, operator, alias; "" for no alias)
let joins = vec![
    Query::join("orders", "$id", "customerId", "=", "").to_string(),
    Query::left_join("orders", "$id", "customerId", "=", "ord").to_string(),
    Query::left_join_on(
        "orders",
        "ord",
        [
            Query::on("$id", "customerId", "=").to_string(),
            Query::equal("ord.status", "paid").to_string(),
        ],
    )
    .to_string(),
];

// Fluent builder. Pass build() into list methods.
let queries = Query::builder()
    .equal("status", "published")
    .left_join("orders", "$id", "customerId", "=", "ord")
    .count("*", "total")
    .group_by(["status"])
    .limit(25)
    .build();

let _rows = tables_db
    .list_rows("[DATABASE_ID]", "[TABLE_ID]", Some(queries), None, None, None)
    .await?;
ファイルストレージ
use appwrite::id::ID;
use appwrite::input_file::InputFile;
use appwrite::permission::Permission;
use appwrite::query::Query;
use appwrite::role::Role;
use appwrite::services::Storage;

let storage = Storage::new(&client);

// Create bucket
let _bucket = storage
    .create_bucket(
        ID::unique(),
        "Uploads",
        Some(vec![
            Permission::read(Role::any()).to_string(),
            Permission::create(Role::users(None)).to_string(),
        ]),
        Some(true),
        Some(true),
        Some(30_000_000),
        Some(vec!["jpg".to_string(), "png".to_string(), "pdf".to_string()]),
        None,
        Some(true),
        Some(true),
        Some(true),
    )
    .await?;

// Upload from disk
let input = InputFile::from_path("avatar.png", Some("image/png")).await?;
let _file = storage
    .create_file(
        "[BUCKET_ID]",
        ID::unique(),
        input,
        Some(vec![Permission::read(Role::any()).to_string()]),
    )
    .await?;

// Upload from bytes
let input = InputFile::from_bytes(b"hello".to_vec(), "hello.txt", Some("text/plain"));
let _file = storage.create_file("[BUCKET_ID]", ID::unique(), input, None).await?;

// List files
let _files = storage
    .list_files("[BUCKET_ID]", Some(vec![Query::limit(10).to_string()]), None, Some(true))
    .await?;

// Download file bytes
let _content = storage
    .get_file_download("[BUCKET_ID]", "[FILE_ID]", None)
    .await?;

// Delete file
storage.delete_file("[BUCKET_ID]", "[FILE_ID]").await?;
関数
use appwrite::enums::ExecutionMethod;
use appwrite::query::Query;
use appwrite::services::Functions;
use serde_json::json;

let functions = Functions::new(&client);

// List functions
let _functions = functions
    .list(Some(vec![Query::limit(25).to_string()]), None, Some(true))
    .await?;

// Execute function
let _execution = functions
    .create_execution(
        "[FUNCTION_ID]",
        Some(r#"{"hello":"world"}"#),
        Some(false),
        Some("/jobs/sync"),
        Some(ExecutionMethod::POST),
        Some(json!({ "content-type": "application/json" })),
        None,
    )
    .await?;

// Get execution
let _execution = functions
    .get_execution("[FUNCTION_ID]", "[EXECUTION_ID]")
    .await?;
権限
use appwrite::permission::Permission;
use appwrite::role::Role;

let permissions = vec![
    Permission::read(Role::any()).to_string(),
    Permission::create(Role::users(None)).to_string(),
    Permission::update(Role::user("[USER_ID]", None)).to_string(),
    Permission::delete(Role::team("[TEAM_ID]", Some("owner"))).to_string(),
];
エラー処理
match users.get("[USER_ID]").await {
    Ok(user) => {
        let _user = user;
    }
    Err(error) if error.status_code() == 404 => {
        eprintln!("User not found: {}", error.get_message());
    }
    Err(error) => {
        eprintln!("Appwrite error {}: {}", error.status_code(), error.get_message());
        return Err(Box::new(error) as Box<dyn std::error::Error>);
    }
}

よくある落とし穴

  • 現在、Rust SDK はサーバー側 SDK です。ブラウザー/モバイルのクライアント認証フローでは、TypeScript/Web、Flutter、Apple、Android、または React Native SDK を使用してください。
  • サービス呼び出しは必ず await してください。
  • 使用しないオプションパラメーターには None を渡してください。
  • 新しいデータベースコードでは、レガシーの Databases ではなく TablesDB を使用してください。
  • Option<Vec<String>> を受け取る API に渡す前に、クエリを .to_string() で変換してください。
  • 行データと JSON 本文には serde_json::json!({...}) を使用してください。
  • アップロードには InputFile::from_path(...).await? または InputFile::from_bytes(...) を使用してください。

コメント