appwrite-dart

安装量: 54
排名: #13735

安装

npx skills add https://github.com/appwrite/agent-skills --skill appwrite-dart

Appwrite Dart SDK Installation

Flutter (client-side)

flutter pub add appwrite

Dart (server-side)

dart pub add dart_appwrite Setting Up the Client Client-side (Flutter) import 'package:appwrite/appwrite.dart' ; final client = Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) ; Server-side (Dart) import 'package:dart_appwrite/dart_appwrite.dart' ; final client = Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( Platform . environment [ 'APPWRITE_PROJECT_ID' ] ! ) . setKey ( Platform . environment [ 'APPWRITE_API_KEY' ] ! ) ; Code Examples Authentication (client-side) final account = Account ( client ) ; // Signup await account . create ( userId : ID . unique ( ) , email : 'user@example.com' , password : 'password123' , name : 'User Name' ) ; // Login final session = await account . createEmailPasswordSession ( email : 'user@example.com' , password : 'password123' ) ; // OAuth login await account . createOAuth2Session ( provider : OAuthProvider . google ) ; // Get current user final user = await account . get ( ) ; // Logout await account . deleteSession ( sessionId : 'current' ) ; User Management (server-side) final users = Users ( client ) ; // Create user final user = await users . create ( userId : ID . unique ( ) , email : 'user@example.com' , password : 'password123' , name : 'User Name' ) ; // List users final list = await users . list ( queries : [ Query . limit ( 25 ) ] ) ; // Get user final fetched = await users . get ( userId : '[USER_ID]' ) ; // Delete user await users . delete ( userId : '[USER_ID]' ) ; Database Operations Note: Use TablesDB (not the deprecated Databases class) for all new code. Only use Databases if the existing codebase already relies on it or the user explicitly requests it. Tip: Prefer named parameters (e.g., databaseId: '...' ) for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it. final tablesDB = TablesDB ( client ) ; // Create database (server-side only) final db = await tablesDB . create ( databaseId : ID . unique ( ) , name : 'My Database' ) ; // Create table (server-side only) final col = await tablesDB . createTable ( databaseId : '[DATABASE_ID]' , tableId : ID . unique ( ) , name : 'My Table' ) ; // Create row final doc = await tablesDB . createRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : ID . unique ( ) , data : { 'title' : 'Hello' , 'done' : false } , ) ; // Query rows final results = await tablesDB . listRows ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , queries : [ Query . equal ( 'done' , false ) , Query . limit ( 10 ) ] , ) ; // Get row final row = await tablesDB . getRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' ) ; // Update row await tablesDB . updateRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' , data : { 'done' : true } , ) ; // Delete row await tablesDB . deleteRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' , ) ; String Column Types Note: The legacy string type is deprecated. Use explicit column types for all new columns. Type Max characters Indexing Storage varchar 16,383 Full index (if size ≤ 768) Inline in row text 16,383 Prefix only Off-page mediumtext 4,194,303 Prefix only Off-page longtext 1,073,741,823 Prefix only Off-page varchar is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers. text , mediumtext , and longtext are stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget. size is not required for these types. // Create table with explicit string column types await tablesDB . createTable ( databaseId : '[DATABASE_ID]' , tableId : ID . unique ( ) , name : 'articles' , columns : [ { 'key' : 'title' , 'type' : 'varchar' , 'size' : 255 , 'required' : true } , // inline, fully indexable { 'key' : 'summary' , 'type' : 'text' , 'required' : false } , // off-page, prefix index only { 'key' : 'body' , 'type' : 'mediumtext' , 'required' : false } , // up to ~4 M chars { 'key' : 'raw_data' , 'type' : 'longtext' , 'required' : false } , // up to ~1 B chars ] , ) ; Query Methods // Filtering Query . equal ( 'field' , 'value' ) // == (or pass list 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 ( [ 'field1' , 'field2' ] ) // return only specified fields Query . or ( [ Query . equal ( 'a' , 1 ) , Query . equal ( 'b' , 2 ) ] ) // OR Query . and ( [ Query . greaterThan ( 'age' , 18 ) , Query . lessThan ( 'age' , 65 ) ] ) // AND (default) File Storage final storage = Storage ( client ) ; // Upload file final file = await storage . createFile ( bucketId : '[BUCKET_ID]' , fileId : ID . unique ( ) , file : InputFile . fromPath ( path : '/path/to/file.png' , filename : 'file.png' ) , ) ; // Get file preview final preview = storage . getFilePreview ( bucketId : '[BUCKET_ID]' , fileId : '[FILE_ID]' , width : 300 , height : 300 ) ; // List files final files = await storage . listFiles ( bucketId : '[BUCKET_ID]' ) ; // Delete file await storage . deleteFile ( bucketId : '[BUCKET_ID]' , fileId : '[FILE_ID]' ) ; InputFile Factory Methods // Client-side (Flutter) InputFile . fromPath ( path : '/path/to/file.png' , filename : 'file.png' ) // from path InputFile . fromBytes ( bytes : uint8List , filename : 'file.png' ) // from Uint8List // Server-side (Dart) InputFile . fromPath ( path : '/path/to/file.png' , filename : 'file.png' ) InputFile . fromBytes ( bytes : uint8List , filename : 'file.png' ) Teams final teams = Teams ( client ) ; // Create team final team = await teams . create ( teamId : ID . unique ( ) , name : 'Engineering' ) ; // List teams final list = await teams . list ( ) ; // Create membership (invite user by email) final membership = await teams . createMembership ( teamId : '[TEAM_ID]' , roles : [ 'editor' ] , email : 'user@example.com' , ) ; // List memberships final members = await teams . listMemberships ( teamId : '[TEAM_ID]' ) ; // Update membership roles await teams . updateMembership ( teamId : '[TEAM_ID]' , membershipId : '[MEMBERSHIP_ID]' , roles : [ 'admin' ] ) ; // Delete team await teams . delete ( teamId : '[TEAM_ID]' ) ; Role-based access: Use Role.team('[TEAM_ID]') for all team members or Role.team('[TEAM_ID]', 'editor') for a specific team role when setting permissions. Real-time Subscriptions (client-side) final realtime = Realtime ( client ) ; // Subscribe to row changes final subscription = realtime . subscribe ( [ Channel . tablesdb ( '[DATABASE_ID]' ) . table ( '[TABLE_ID]' ) . row ( ) , ] ) ; subscription . stream . listen ( ( response ) { print ( response . events ) ; // e.g. ['tablesdb..tables..rows.*.create'] print ( response . payload ) ; // the affected resource } ) ; // Subscribe to multiple channels final multi = realtime . subscribe ( [ Channel . tablesdb ( '[DATABASE_ID]' ) . table ( '[TABLE_ID]' ) . row ( ) , Channel . bucket ( '[BUCKET_ID]' ) . file ( ) , ] ) ; // Cleanup subscription . close ( ) ; Available channels: Channel Description account Changes to the authenticated user's account tablesdb.[DB_ID].tables.[TABLE_ID].rows All rows in a table tablesdb.[DB_ID].tables.[TABLE_ID].rows.[ROW_ID] A specific row buckets.[BUCKET_ID].files All files in a bucket buckets.[BUCKET_ID].files.[FILE_ID] A specific file teams Changes to teams the user belongs to teams.[TEAM_ID] A specific team memberships The user's team memberships memberships.[MEMBERSHIP_ID] A specific membership functions.[FUNCTION_ID].executions Function execution updates Response fields: events (array), payload (resource), channels (matched), timestamp (ISO 8601). Serverless Functions (server-side) final functions = Functions ( client ) ; // Execute function final execution = await functions . createExecution ( functionId : '[FUNCTION_ID]' , body : '{"key": "value"}' ) ; // List executions final executions = await functions . listExecutions ( functionId : '[FUNCTION_ID]' ) ; Writing a Function Handler (Dart runtime) // lib/main.dart — Appwrite Function entry point Future < dynamic

main ( final context ) async { // context.req.body — raw body (String) // context.req.bodyJson — parsed JSON (Map or null) // context.req.headers — headers (Map) // context.req.method — HTTP method // context.req.path — URL path // context.req.query — query params (Map) context . log ( 'Processing: ${ context . req . method } ${ context . req . path } ' ) ; if ( context . req . method == 'GET' ) { return context . res . json ( { 'message' : 'Hello from Appwrite Function!' } ) ; } return context . res . json ( { 'success' : true } ) ; // JSON // return context.res.text('Hello'); // plain text // return context.res.empty(); // 204 // return context.res.redirect('https://...'); // 302 } Server-Side Rendering (SSR) Authentication SSR apps using server-side Dart (Dart Frog, Shelf, etc.) use the server SDK ( dart_appwrite ) 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) import 'package:dart_appwrite/dart_appwrite.dart' ; // Admin client (reusable) final adminClient = Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) . setKey ( Platform . environment [ 'APPWRITE_API_KEY' ] ! ) ; // Session client (create per-request) final sessionClient = Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) ; final session = request . cookies [ 'a_session_[PROJECT_ID]' ] ; if ( session != null ) { sessionClient . setSession ( session ) ; } Email/Password Login final account = Account ( adminClient ) ; final session = await account . createEmailPasswordSession ( email : body [ 'email' ] , password : body [ 'password' ] , ) ; // Cookie name must be a_session_ response . headers . add ( 'Set-Cookie' , 'a_session_[PROJECT_ID]= ${ session . secret } ; ' 'HttpOnly; Secure; SameSite=Strict; ' 'Expires= ${ HttpDate . format ( DateTime . parse ( session . expire ) ) } ; Path=/' ) ; Authenticated Requests final session = request . cookies [ 'a_session_[PROJECT_ID]' ] ; if ( session == null ) { return Response ( statusCode : 401 , body : 'Unauthorized' ) ; } final sessionClient = Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) . setSession ( session ) ; final account = Account ( sessionClient ) ; final user = await account . get ( ) ; OAuth2 SSR Flow // Step 1: Redirect to OAuth provider final account = Account ( adminClient ) ; final redirectUrl = await account . createOAuth2Token ( provider : OAuthProvider . github , success : 'https://example.com/oauth/success' , failure : 'https://example.com/oauth/failure' , ) ; return Response ( statusCode : 302 , headers : { 'Location' : redirectUrl } ) ; // Step 2: Handle callback — exchange token for session final account = Account ( adminClient ) ; final session = await account . createSession ( userId : request . uri . queryParameters [ 'userId' ] ! , secret : request . uri . queryParameters [ 'secret' ] ! , ) ; // Set session cookie as above Cookie security: Always use HttpOnly , Secure , and SameSite=Strict to prevent XSS. The cookie name must be a_session_ . Forwarding user agent: Call sessionClient.setForwardedUserAgent(request.headers['user-agent']) to record the end-user's browser info for debugging and security. Error Handling import 'package:appwrite/appwrite.dart' ; // AppwriteException is included in the main import try { final row = await tablesDB . getRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' ) ; } on AppwriteException catch ( e ) { print ( e . message ) ; // human-readable message print ( e . code ) ; // HTTP status code (int) print ( e . type ) ; // error type (e.g. 'document_not_found') print ( e . response ) ; // full response body (Map) } Common error codes: Code Meaning 401 Unauthorized — missing or invalid session/API key 403 Forbidden — insufficient permissions 404 Not found — resource does not exist 409 Conflict — duplicate ID or unique constraint 429 Rate limited — too many requests Permissions & Roles (Critical) Appwrite uses permission strings to control access to resources. Each permission pairs an action ( read , update , delete , create , or write 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 Permission and Role helpers. import 'package:appwrite/appwrite.dart' ; // Permission and Role are included in the main package import Database Row with Permissions final doc = await tablesDB . createRow ( databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : ID . unique ( ) , data : { 'title' : 'Hello World' } , permissions : [ 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 ] , ) ; File Upload with Permissions final file = await storage . createFile ( bucketId : '[BUCKET_ID]' , fileId : ID . unique ( ) , file : InputFile . fromPath ( path : '/path/to/file.png' , filename : 'file.png' ) , permissions : [ 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) Role.any() with write / update / delete — allows any user, including unauthenticated guests, to modify or remove the resource Permission.read(Role.any()) on sensitive data — makes the resource publicly readable

返回排行榜