appwrite-go
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAppwrite Go SDK
Appwrite Go SDK
Installation
安装
bash
go get github.com/appwrite/sdk-for-gobash
go get github.com/appwrite/sdk-for-goSetting Up the Client
客户端配置
go
import (
"os"
"github.com/appwrite/sdk-for-go/client"
"github.com/appwrite/sdk-for-go/id"
"github.com/appwrite/sdk-for-go/users"
"github.com/appwrite/sdk-for-go/tablesdb"
"github.com/appwrite/sdk-for-go/storage"
)
clt := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithKey(os.Getenv("APPWRITE_API_KEY")),
)go
import (
"os"
"github.com/appwrite/sdk-for-go/client"
"github.com/appwrite/sdk-for-go/id"
"github.com/appwrite/sdk-for-go/users"
"github.com/appwrite/sdk-for-go/tablesdb"
"github.com/appwrite/sdk-for-go/storage"
)
clt := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithKey(os.Getenv("APPWRITE_API_KEY")),
)Code Examples
代码示例
User Management
用户管理
go
service := users.New(clt)
// Create user
user, err := service.Create(
id.Unique(),
"user@example.com",
"password123",
users.WithCreateName("User Name"),
)
// List users
list, err := service.List()
// Get user
fetched, err := service.Get("[USER_ID]")
// Delete user
_, err = service.Delete("[USER_ID]")go
service := users.New(clt)
// Create user
user, err := service.Create(
id.Unique(),
"user@example.com",
"password123",
users.WithCreateName("User Name"),
)
// List users
list, err := service.List()
// Get user
fetched, err := service.Get("[USER_ID]")
// Delete user
_, err = service.Delete("[USER_ID]")Database Operations
数据库操作
Note: Use(not the deprecatedTablesDBclass) for all new code. Only useDatabasesif the existing codebase already relies on it or the user explicitly requests it.DatabasesTip: Prefer explicit functional option parameters (e.g.,) over bare positional arguments where available. Only use positional-only style if the existing codebase already uses it or the user explicitly requests it.tablesdb.WithUpdateRowData(...)
go
service := tablesdb.New(clt)
// Create database
db, err := service.Create(id.Unique(), "My Database")
// Create row
doc, err := service.CreateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
id.Unique(),
map[string]interface{}{"title": "Hello World"},
)
// List rows
results, err := service.ListRows("[DATABASE_ID]", "[TABLE_ID]")
// Get row
row, err := service.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")
// Update row
_, err = service.UpdateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
"[ROW_ID]",
tablesdb.WithUpdateRowData(map[string]interface{}{"title": "Updated"}),
)
// Delete row
_, err = service.DeleteRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")注意: 所有新代码请使用(而非已弃用的TablesDB类)。仅当现有代码库已依赖Databases或用户明确要求时,才使用它。Databases提示: 优先使用显式的函数选项参数(如),而非裸位置参数。仅当现有代码库已使用位置参数风格或用户明确要求时,才使用该风格。tablesdb.WithUpdateRowData(...)
go
service := tablesdb.New(clt)
// Create database
db, err := service.Create(id.Unique(), "My Database")
// Create row
doc, err := service.CreateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
id.Unique(),
map[string]interface{}{"title": "Hello World"},
)
// List rows
results, err := service.ListRows("[DATABASE_ID]", "[TABLE_ID]")
// Get row
row, err := service.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")
// Update row
_, err = service.UpdateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
"[ROW_ID]",
tablesdb.WithUpdateRowData(map[string]interface{}{"title": "Updated"}),
)
// Delete row
_, err = service.DeleteRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")String Column Types
字符串列类型
Note: The legacytype is deprecated. Use explicit column types for all new columns.string
| Type | Max characters | Indexing | Storage |
|---|---|---|---|
| 16,383 | Full index (if size ≤ 768) | Inline in row |
| 16,383 | Prefix only | Off-page |
| 4,194,303 | Prefix only | Off-page |
| 1,073,741,823 | Prefix only | Off-page |
- is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers.
varchar - ,
text, andmediumtextare stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget.longtextis not required for these types.size
go
// Create table with explicit string column types
_, err = service.CreateTable(
"[DATABASE_ID]",
id.Unique(),
"articles",
tablesdb.WithCreateTableColumns([]map[string]interface{}{
{"key": "title", "type": "varchar", "size": 255, "required": true},
{"key": "summary", "type": "text", "required": false},
{"key": "body", "type": "mediumtext", "required": false},
{"key": "raw_data", "type": "longtext", "required": false},
}),
)注意: 旧版类型已弃用。所有新列请使用显式列类型。string
| 类型 | 最大字符数 | 索引方式 | 存储方式 |
|---|---|---|---|
| 16,383 | 全索引(若长度 ≤ 768) | 行内存储 |
| 16,383 | 仅前缀索引 | 行外存储 |
| 4,194,303 | 仅前缀索引 | 行外存储 |
| 1,073,741,823 | 仅前缀索引 | 行外存储 |
- 存储在行内,占用64KB行大小限制的配额。适用于名称、短链接或标识符等短小且需要索引的字段。
varchar - 、
text和mediumtext存储在行外(行中仅保留一个20字节的指针),因此不会占用行大小配额。这些类型无需指定longtext参数。size
go
// Create table with explicit string column types
_, err = service.CreateTable(
"[DATABASE_ID]",
id.Unique(),
"articles",
tablesdb.WithCreateTableColumns([]map[string]interface{}{
{"key": "title", "type": "varchar", "size": 255, "required": true},
{"key": "summary", "type": "text", "required": false},
{"key": "body", "type": "mediumtext", "required": false},
{"key": "raw_data", "type": "longtext", "required": false},
}),
)Query Methods
查询方法
go
import "github.com/appwrite/sdk-for-go/query"
// Filtering
query.Equal("field", "value") // == (or pass slice for IN)
query.NotEqual("field", "value") // !=
query.LessThan("field", 100) // <
query.LessThanEqual("field", 100) // <=
query.GreaterThan("field", 100) // >
query.GreaterThanEqual("field", 100) // >=
query.Between("field", 1, 100) // 1 <= field <= 100
query.IsNull("field") // is null
query.IsNotNull("field") // is not null
query.StartsWith("field", "prefix") // starts with
query.EndsWith("field", "suffix") // ends with
query.Contains("field", "sub") // contains
query.Search("field", "keywords") // full-text search (requires index)
// Sorting
query.OrderAsc("field")
query.OrderDesc("field")
// Pagination
query.Limit(25) // max rows (default 25, max 100)
query.Offset(0) // skip N rows
query.CursorAfter("[ROW_ID]") // cursor pagination (preferred)
query.CursorBefore("[ROW_ID]")
// Selection & Logic
query.Select([]string{"field1", "field2"})
query.Or([]string{query.Equal("a", 1), query.Equal("b", 2)}) // OR
query.And([]string{query.GreaterThan("age", 18), query.LessThan("age", 65)}) // AND (default)go
import "github.com/appwrite/sdk-for-go/query"
// Filtering
query.Equal("field", "value") // == (或传入切片实现IN查询)
query.NotEqual("field", "value") // !=
query.LessThan("field", 100) // <
query.LessThanEqual("field", 100) // <=
query.GreaterThan("field", 100) // >
query.GreaterThanEqual("field", 100) // >=
query.Between("field", 1, 100) // 1 <= field <= 100
query.IsNull("field") // is null
query.IsNotNull("field") // is not null
query.StartsWith("field", "prefix") // starts with
query.EndsWith("field", "suffix") // ends with
query.Contains("field", "sub") // contains
query.Search("field", "keywords") // 全文搜索(需提前创建索引)
// Sorting
query.OrderAsc("field")
query.OrderDesc("field")
// Pagination
query.Limit(25) // 最大行数(默认25,上限100)
query.Offset(0) // 跳过N行
query.CursorAfter("[ROW_ID]") // 游标分页(推荐使用)
query.CursorBefore("[ROW_ID]")
// Selection & Logic
query.Select([]string{"field1", "field2"})
query.Or([]string{query.Equal("a", 1), query.Equal("b", 2)}) // OR
query.And([]string{query.GreaterThan("age", 18), query.LessThan("age", 65)}) // AND(默认逻辑)File Storage
文件存储
go
import "github.com/appwrite/sdk-for-go/file"
service := storage.New(clt)
// Upload file
f, err := service.CreateFile(
"[BUCKET_ID]",
"[FILE_ID]",
file.NewInputFile("/path/to/file.png", "file.png"),
)
// List files
files, err := service.ListFiles("[BUCKET_ID]")
// Delete file
_, err = service.DeleteFile("[BUCKET_ID]", "[FILE_ID]")go
import "github.com/appwrite/sdk-for-go/file"
service := storage.New(clt)
// Upload file
f, err := service.CreateFile(
"[BUCKET_ID]",
"[FILE_ID]",
file.NewInputFile("/path/to/file.png", "file.png"),
)
// List files
files, err := service.ListFiles("[BUCKET_ID]")
// Delete file
_, err = service.DeleteFile("[BUCKET_ID]", "[FILE_ID]")InputFile Factory Methods
InputFile 工厂方法
go
import "github.com/appwrite/sdk-for-go/file"
file.NewInputFile("/path/to/file.png", "file.png") // from filesystem path
file.NewInputFileFromReader(reader, "file.png", size) // from io.Reader (size required)
file.NewInputFileFromBytes(data, "file.png") // from []bytego
import "github.com/appwrite/sdk-for-go/file"
file.NewInputFile("/path/to/file.png", "file.png") // 从文件系统路径创建
file.NewInputFileFromReader(reader, "file.png", size) // 从io.Reader创建(需指定size)
file.NewInputFileFromBytes(data, "file.png") // 从[]byte创建Teams
团队管理
go
import "github.com/appwrite/sdk-for-go/teams"
svc := teams.New(clt)
// Create team
team, err := svc.Create(id.Unique(), "Engineering")
// List teams
list, err := svc.List()
// Create membership (invite user by email)
membership, err := svc.CreateMembership(
"[TEAM_ID]",
[]string{"editor"},
teams.WithCreateMembershipEmail("user@example.com"),
)
// List memberships
members, err := svc.ListMemberships("[TEAM_ID]")
// Update membership roles
_, err = svc.UpdateMembership("[TEAM_ID]", "[MEMBERSHIP_ID]", []string{"admin"})
// Delete team
_, err = svc.Delete("[TEAM_ID]")Role-based access: Usefor all team members orrole.Team("[TEAM_ID]")for a specific team role when setting permissions.role.Team("[TEAM_ID]", "editor")
go
import "github.com/appwrite/sdk-for-go/teams"
svc := teams.New(clt)
// Create team
team, err := svc.Create(id.Unique(), "Engineering")
// List teams
list, err := svc.List()
// Create membership (invite user by email)
membership, err := svc.CreateMembership(
"[TEAM_ID]",
[]string{"editor"},
teams.WithCreateMembershipEmail("user@example.com"),
)
// List memberships
members, err := svc.ListMemberships("[TEAM_ID]")
// Update membership roles
_, err = svc.UpdateMembership("[TEAM_ID]", "[MEMBERSHIP_ID]", []string{"admin"})
// Delete team
_, err = svc.Delete("[TEAM_ID]")基于角色的访问控制: 设置权限时,使用表示所有团队成员,或使用role.Team("[TEAM_ID]")表示特定团队角色。role.Team("[TEAM_ID]", "editor")
Serverless Functions
无服务器函数
go
import "github.com/appwrite/sdk-for-go/functions"
svc := functions.New(clt)
// Execute function
execution, err := svc.CreateExecution(
"[FUNCTION_ID]",
functions.WithCreateExecutionBody(`{"key": "value"}`),
)
// List executions
executions, err := svc.ListExecutions("[FUNCTION_ID]")go
import "github.com/appwrite/sdk-for-go/functions"
svc := functions.New(clt)
// Execute function
execution, err := svc.CreateExecution(
"[FUNCTION_ID]",
functions.WithCreateExecutionBody(`{"key": "value"}`),
)
// List executions
executions, err := svc.ListExecutions("[FUNCTION_ID]")Writing a Function Handler (Go runtime)
编写函数处理器(Go 运行时)
go
// src/main.go — Appwrite Function entry point
package handler
import (
"github.com/open-runtimes/types-for-go/v4/openruntimes"
)
func Main(context openruntimes.Context) openruntimes.Response {
// context.Req.Body — raw body (string)
// context.Req.BodyJson — parsed JSON (map[string]interface{})
// context.Req.Headers — headers (map[string]string)
// context.Req.Method — HTTP method
// context.Req.Path — URL path
// context.Req.Query — query params (map[string]string)
context.Log("Processing: " + context.Req.Method + " " + context.Req.Path)
if context.Req.Method == "GET" {
return context.Res.Json(map[string]interface{}{"message": "Hello!"})
}
return context.Res.Json(map[string]interface{}{"success": true})
// context.Res.Text("Hello") // plain text
// context.Res.Empty() // 204
// context.Res.Redirect("https://...") // 302
}go
// src/main.go — Appwrite Function 入口点
package handler
import (
"github.com/open-runtimes/types-for-go/v4/openruntimes"
)
func Main(context openruntimes.Context) openruntimes.Response {
// context.Req.Body — 原始请求体(字符串)
// context.Req.BodyJson — 解析后的JSON(map[string]interface{})
// context.Req.Headers — 请求头(map[string]string)
// context.Req.Method — HTTP方法
// context.Req.Path — URL路径
// context.Req.Query — 查询参数(map[string]string)
context.Log("Processing: " + context.Req.Method + " " + context.Req.Path)
if context.Req.Method == "GET" {
return context.Res.Json(map[string]interface{}{"message": "Hello!"})
}
return context.Res.Json(map[string]interface{}{"success": true})
// context.Res.Text("Hello") // 纯文本响应
// context.Res.Empty() // 204 空响应
// context.Res.Redirect("https://...") // 302 重定向
}Server-Side Rendering (SSR) Authentication
服务端渲染(SSR)认证
SSR apps using Go frameworks (net/http, Gin, Echo, Chi, etc.) use the server SDK to handle auth. You need two clients:
- Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton)
- Session client — uses a session cookie, acts on behalf of a user (create per-request, never share)
go
import (
"github.com/appwrite/sdk-for-go/client"
"github.com/appwrite/sdk-for-go/account"
)
// Admin client (reusable)
adminClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithKey(os.Getenv("APPWRITE_API_KEY")),
)
// Session client (create per-request)
sessionClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
)
cookie, err := r.Cookie("a_session_[PROJECT_ID]")
if err == nil {
sessionClient.SetSession(cookie.Value)
}使用Go框架(net/http、Gin、Echo、Chi等)的SSR应用通过服务端SDK处理认证,需要两个客户端:
- 管理员客户端:使用API密钥,可创建会话,绕过速率限制(可复用单例)
- 会话客户端:使用会话Cookie,代表用户执行操作(每个请求创建一个,不可共享)
go
import (
"github.com/appwrite/sdk-for-go/client"
"github.com/appwrite/sdk-for-go/account"
)
// Admin client (reusable)
adminClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithKey(os.Getenv("APPWRITE_API_KEY")),
)
// Session client (create per-request)
sessionClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
)
cookie, err := r.Cookie("a_session_[PROJECT_ID]")
if err == nil {
sessionClient.SetSession(cookie.Value)
}Email/Password Login
邮箱/密码登录
go
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
session, err := svc.CreateEmailPasswordSession(r.FormValue("email"), r.FormValue("password"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Cookie name must be a_session_<PROJECT_ID>
http.SetCookie(w, &http.Cookie{
Name: "a_session_[PROJECT_ID]",
Value: session.Secret,
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
Path: "/",
})
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success": true}`))
})go
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
session, err := svc.CreateEmailPasswordSession(r.FormValue("email"), r.FormValue("password"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Cookie name must be a_session_<PROJECT_ID>
http.SetCookie(w, &http.Cookie{
Name: "a_session_[PROJECT_ID]",
Value: session.Secret,
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
Path: "/",
})
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success": true}`))
})Authenticated Requests
已认证请求
go
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("a_session_[PROJECT_ID]")
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
sessionClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithSession(cookie.Value),
)
svc := account.New(sessionClient)
user, err := svc.Get()
// Marshal user to JSON and write response
})go
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("a_session_[PROJECT_ID]")
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
sessionClient := client.New(
client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
client.WithProject(os.Getenv("APPWRITE_PROJECT_ID")),
client.WithSession(cookie.Value),
)
svc := account.New(sessionClient)
user, err := svc.Get()
// 将user序列化为JSON并写入响应
})OAuth2 SSR Flow
OAuth2 SSR 流程
go
// Step 1: Redirect to OAuth provider
http.HandleFunc("/oauth", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
redirectURL, err := svc.CreateOAuth2Token(
"github",
account.WithCreateOAuth2TokenSuccess("https://example.com/oauth/success"),
account.WithCreateOAuth2TokenFailure("https://example.com/oauth/failure"),
)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, redirectURL, http.StatusFound)
})
// Step 2: Handle callback — exchange token for session
http.HandleFunc("/oauth/success", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
session, err := svc.CreateSession(r.URL.Query().Get("userId"), r.URL.Query().Get("secret"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.SetCookie(w, &http.Cookie{
Name: "a_session_[PROJECT_ID]", Value: session.Secret,
HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, Path: "/",
})
w.Write([]byte(`{"success": true}`))
})Cookie security: Always use,HttpOnly, andSecureto prevent XSS. The cookie name must beSameSiteStrictMode.a_session_<PROJECT_ID>
Forwarding user agent: Callto record the end-user's browser info for debugging and security.sessionClient.SetForwardedUserAgent(r.Header.Get("User-Agent"))
go
// Step 1: Redirect to OAuth provider
http.HandleFunc("/oauth", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
redirectURL, err := svc.CreateOAuth2Token(
"github",
account.WithCreateOAuth2TokenSuccess("https://example.com/oauth/success"),
account.WithCreateOAuth2TokenFailure("https://example.com/oauth/failure"),
)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, redirectURL, http.StatusFound)
})
// Step 2: Handle callback — exchange token for session
http.HandleFunc("/oauth/success", func(w http.ResponseWriter, r *http.Request) {
svc := account.New(adminClient)
session, err := svc.CreateSession(r.URL.Query().Get("userId"), r.URL.Query().Get("secret"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.SetCookie(w, &http.Cookie{
Name: "a_session_[PROJECT_ID]", Value: session.Secret,
HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, Path: "/",
})
w.Write([]byte(`{"success": true}`))
})Cookie 安全: 始终使用、HttpOnly和Secure以防止XSS攻击。Cookie名称必须为SameSiteStrictMode。a_session_<PROJECT_ID>
转发用户代理: 调用以记录终端用户的浏览器信息,用于调试和安全审计。sessionClient.SetForwardedUserAgent(r.Header.Get("User-Agent"))
Error Handling
错误处理
go
import "github.com/appwrite/sdk-for-go/apperr"
doc, err := service.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")
if err != nil {
var appErr *apperr.AppwriteException
if errors.As(err, &appErr) {
fmt.Println(appErr.Message) // human-readable message
fmt.Println(appErr.Code) // HTTP status code (int)
fmt.Println(appErr.Type) // error type (e.g. "document_not_found")
}
}Common error codes:
| Code | Meaning |
|---|---|
| Unauthorized — missing or invalid session/API key |
| Forbidden — insufficient permissions |
| Not found — resource does not exist |
| Conflict — duplicate ID or unique constraint |
| Rate limited — too many requests |
go
import "github.com/appwrite/sdk-for-go/apperr"
doc, err := service.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]")
if err != nil {
var appErr *apperr.AppwriteException
if errors.As(err, &appErr) {
fmt.Println(appErr.Message) // 人类可读的错误信息
fmt.Println(appErr.Code) // HTTP状态码(整数)
fmt.Println(appErr.Type) // 错误类型(例如"document_not_found")
}
}常见错误码:
| 状态码 | 含义 |
|---|---|
| 未授权 — 缺少或无效的会话/API密钥 |
| 禁止访问 — 权限不足 |
| 未找到 — 资源不存在 |
| 冲突 — 重复ID或唯一约束冲突 |
| 请求受限 — 请求过于频繁 |
Permissions & Roles (Critical)
权限与角色(重点)
Appwrite uses permission strings to control access to resources. Each permission pairs an action (, , , , or which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the document/file level or inherited from the collection/bucket settings. Permissions are arrays of strings built with the and helpers.
readupdatedeletecreatewritepermissionrolego
import (
"github.com/appwrite/sdk-for-go/permission"
"github.com/appwrite/sdk-for-go/role"
)Appwrite 使用权限字符串控制资源访问。每个权限将操作(、、、,或,后者包含create+update+delete)与角色目标配对。默认情况下,所有用户均无访问权限,除非在文档/文件级别显式设置权限,或从集合/存储桶设置继承权限。权限是使用和工具构建的字符串数组。
readupdatedeletecreatewritepermissionrolego
import (
"github.com/appwrite/sdk-for-go/permission"
"github.com/appwrite/sdk-for-go/role"
)Database Row with Permissions
带权限的数据库行
go
doc, err := service.CreateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
"[ROW_ID]",
map[string]interface{}{"title": "Hello World"},
tablesdb.WithCreateRowPermissions([]string{
permission.Read(role.User("[USER_ID]")), // specific user can read
permission.Update(role.User("[USER_ID]")), // specific user can update
permission.Read(role.Team("[TEAM_ID]")), // all team members can read
permission.Read(role.Any()), // anyone (including guests) can read
}),
)go
doc, err := service.CreateRow(
"[DATABASE_ID]",
"[TABLE_ID]",
"[ROW_ID]",
map[string]interface{}{"title": "Hello World"},
tablesdb.WithCreateRowPermissions([]string{
permission.Read(role.User("[USER_ID]")), // 指定用户可读取
permission.Update(role.User("[USER_ID]")), // 指定用户可更新
permission.Read(role.Team("[TEAM_ID]")), // 所有团队成员可读取
permission.Read(role.Any()), // 任何人(包括访客)可读取
}),
)File Upload with Permissions
带权限的文件上传
go
f, err := service.CreateFile(
"[BUCKET_ID]",
"[FILE_ID]",
file.NewInputFile("/path/to/file.png", "file.png"),
storage.WithCreateFilePermissions([]string{
permission.Read(role.Any()),
permission.Update(role.User("[USER_ID]")),
permission.Delete(role.User("[USER_ID]")),
}),
)When to set permissions: Set document/file-level permissions when you need per-resource access control. If all documents in a collection share the same rules, configure permissions at the collection/bucket level and leave document permissions empty.
Common mistakes:
- Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
withrole.Any()/write/update— allows any user, including unauthenticated guests, to modify or remove the resourcedelete on sensitive data — makes the resource publicly readablepermission.Read(role.Any())
go
f, err := service.CreateFile(
"[BUCKET_ID]",
"[FILE_ID]",
file.NewInputFile("/path/to/file.png", "file.png"),
storage.WithCreateFilePermissions([]string{
permission.Read(role.Any()),
permission.Update(role.User("[USER_ID]")),
permission.Delete(role.User("[USER_ID]")),
}),
)何时设置权限: 当需要按资源粒度控制访问时,设置文档/文件级权限。如果集合中的所有文档共享相同规则,请在集合/存储桶级别配置权限,而文档权限留空。
常见错误:
- 忘记设置权限 — 资源对所有用户(包括创建者)均不可访问
- 对
/write/update使用delete— 允许任何用户(包括未认证访客)修改或删除资源role.Any()- 对敏感数据使用
— 使资源公开可读permission.Read(role.Any())