diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml new file mode 100644 index 000000000..97aa74381 --- /dev/null +++ b/app/views/docs/authentication-anonymous.phtml @@ -0,0 +1,120 @@ +

+ Anonymous sessions allow you to implement guest users. + Guest users let you store user information like items in their cart or theme preferences before they create an account. + This reduces the friction for your users to get started with your app. +

+ +

+ If a user later creates an account, their information will be inherited by the newly created account. +

+ +

Create Anonymous Session

+

+ Create an anonymous session with Create Anonymous Session route. +

+ + + + +

Attaching an Account

+

+ Anonymous users cannot sign back in. + If the session expires, they move to another computer, or they clear their browser data, they won't be able to log in again. + Remember to prompt the user to create an account to not lose their data. +

+ +

+ Create an account with any of these methods to transition from an anonymous session to a user account session. +

+ + +

+Email and password +

+

+Phone (SMS) +

+

+Magic URL +

+

+OAuth2 +

diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml new file mode 100644 index 000000000..2f6604c93 --- /dev/null +++ b/app/views/docs/authentication-email-pass.phtml @@ -0,0 +1,614 @@ +

+ Email and password login is the most commonly used authentication method. + Appwrite Authentication promotes a safer internet by providing secure APIs and promoting better password choices to end users. + Appwrite supports added security features like blocking personal info in passwords, password dictionary, and password history to help users choose good passwords. +

+ +

Sign Up

+ +

+ You can use the Appwrite Client SDKs to create an account using email and password. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account, ID } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');               // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.create('[USER_ID]', 'email@example.com', '');
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');               // Your project ID
    +
    +final account = Account(client);
    +
    +final user = await account.create(
    +    userId: ID.unique(),
    +    email: 'email@example.com',
    +    password: 'password',
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +import io.appwrite.ID
    +
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                // Your project ID
    +
    +val account = Account(client)
    +
    +val user = account.create(
    +    userId = ID.unique(),
    +    email = "email@example.com",
    +    password = "password"
    +)
    +
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                // Your project ID
    +
    +let account = Account(client)
    +
    +let user = try await account.create(
    +    userId: ID.unique(),
    +    email: "email@example.com",
    +    password: "password"
    +)
    +
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountCreate(userId: "unique()", email: "email@example.com", password: "password") {
    +        _id
    +        email
    +        name
    +    }
    +}
    +
    +
  • +
+ +

+ Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. +

+ +

Verification

+ +

+ After an account is created, it can be verified through the account create verification route. + The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions through the user([USER_ID], "verified") role. +

+ +

+ First, send a verification email. + Specify a redirect URL which users will be redirected to. + The verification secrets will be appended as query parameters to the redirect URL. + In this example, the redirect URL is https://example.com/verify. +

+
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.createVerification('https://example.com');
    +
    +promise.then(function (response) {
    +    console.log(response);
    +}, function (error) {
    +    console.log(error);
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2');                // Your project ID
    +
    +final account = Account(client);
    +
    +final token = await account.createVerification(
    +    url: 'https://example.com',
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(applicationContext)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +
    +val account = Account(client)
    +
    +val token = account.createVerification(
    +    url = "https://example.com"
    +)
    +
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +
    +let account = Account(client)
    +
    +let token = try await account.createVerification(
    +    url: "https://example.com"
    +)
    +
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountCreateVerification(
    +        url: "https://example.com"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        secret
    +        expire
    +    }
    +}
    +
    +
  • +
+ +

+ Next, implement the verification page in your app. + This page will parse the secrets passed in through the userId and secret query parameters. + In this example, the code below will be found in the page served at https://example.com/verify. +

+ +

+ Since the secrets are passed in through url params, it will be easiest to perform this step in the browser. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const urlParams = new URLSearchParams(window.location.search);
    +const secret = urlParams.get('secret');
    +const userId = urlParams.get('userId');
    +
    +const promise = account.updateVerification(userId, secret);
    +
    +promise.then(function (response) {
    +    console.log(response);
    +}, function (error) {
    +    console.log(error);
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2');                // Your project ID
    +
    +final account = Account(client);
    +
    +final result = account.updateVerification(
    +    userId: '[USER_ID]',
    +    secret: '[SECRET]',
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +
    +val account = Account(client)
    +
    +val response = account.updateVerification(
    +    userId = "[USER_ID]",
    +    secret = "[SECRET]"
    +)
    +
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +
    +let account = Account(client)
    +
    +let token = try await account.updateVerification(
    +    userId: "[USER_ID]",
    +    secret: "[SECRET]"
    +)
    +
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountUpdateVerification(
    +        userId: "[USER_ID]",
    +        secret: "[SECRET]"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        secret
    +        expire
    +    }
    +}
    +
    +
  • +
+ + +

Log In

+ +

+ After you've created your account, users can be logged in using the Create Email Session route. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.createEmailSession('email@example.com', 'password');
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +final account = Account(client);
    +
    +final session = await account.createEmailSession(
    +    email: 'email@example.com',
    +    password: 'password'
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +val session = account.createEmailSession(
    +    email = "email@example.com",
    +    password = "password"
    +)
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +let account = Account(client)
    +
    +let session = try await account.createEmailSession(
    +    email: "email@example.com",
    +    password: "password"
    +)
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountCreateEmailSession(email: "email@example.com", password: "password") {
    +        _id
    +        userId
    +        provider
    +        expire
    +    }
    +}
    +
    +
  • +
+ +

Password Recovery

+

+ If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. +

+ +

+ Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const promise = account.createRecovery('email@example.com', 'https://example.com');
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +final account = Account(client);
    +
    +final user = account.createRecovery(
    +    email: 'email@example.com',
    +    url: 'https://example.com',
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +val response = account.createRecovery(
    +    email = "email@example.com",
    +    url = "https://example.com"
    +)
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +let account = Account(client)
    +
    +let token = try await account.createRecovery(
    +    email: "email@example.com",
    +    url: "https://example.com"
    +)
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountCreateRecovery(
    +        email: "email@example.com",
    +        url: "https://example.com"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        secret
    +        expire
    +    }
    +}
    +
    +
  • +
+ +

+After receiving an email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const promise = account.updateRecovery(
    +    '[USER_ID]',
    +    '[SECRET]',
    +    'password',
    +    'password'
    +);
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +final account = Account(client);
    +
    +final user = await account.updateRecovery(
    +    userId: '[USER_ID]',
    +    secret: '[SECRET]',
    +    password: 'password'
    +    passwordAgain: 'password'
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +val token = account.updateRecovery(
    +    userId = "[USER_ID]",
    +    secret = "[SECRET]",
    +    password = "password",
    +    passwordAgain = "password"
    +)
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +let account = Account(client)
    +
    +let token = try await account.updateRecovery(
    +    userId: "[USER_ID]",
    +    secret: "[SECRET]",
    +    password: "password",
    +    passwordAgain: "password"
    +)
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountUpdateRecovery(
    +        userId: "[USER_ID]",
    +        secret: "[SECRET]",
    +        password: "password",
    +        passwordAgain: "password"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        secret
    +        expire
    +    }
    +}
    +
    +
  • +
+ +

Security

+

+ Appwrite's security first mindset goes beyond a securely implemented of authentication API. + You can enable features like password dictionary, password history, and disallow personal data in passwords to encourage users to pick better passwords. + By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place. +

+

+ + Learn more about security features + +

\ No newline at end of file diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml new file mode 100644 index 000000000..d126549c6 --- /dev/null +++ b/app/views/docs/authentication-magic.phtml @@ -0,0 +1,97 @@ +

+ Magic URL is a password-less way to authenticate users. + When a user logs in by providing their email, they will receive an email with a "magic" link that contains a secret used to log in the user. + The user can simply click the link to be logged in. +

+ +

Send Email

+ +

+ Initialize the log in process with the Create Magic URL Session route. + If the email has never been used, a new account is generated, then the user will receive an email. + If the email is already attached to an account, the user ID is ignored and the user will receive a link in their email. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account, ID } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.createMagicURLSession(ID.unique(), 'email@example.com');
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountCreateMagicURLSession(
    +        userId: "ID.unique()",
    +        email: "email@example.com"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        secret
    +        expire
    +    }
    +}
    +
    +
  • +
+ +

Log In

+ +

+ After receiving your secret from an email, you can create a session. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                // Your project ID
    +
    +const account = new Account(client);
    +
    +const urlParams = new URLSearchParams(window.location.search);
    +const secret = urlParams.get('secret');
    +const userId = urlParams.get('userId');
    +
    +const user = await account.updateMagicURLSession(userId, secret);
    +
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountUpdateMagicURLSession(
    +        userId: "unique()",
    +        secret: "[SECRET]"
    +    ) {
    +        _id
    +        _createdAt
    +        userId
    +        expire
    +        provider
    +    }
    +}
    +
    +
  • +
\ No newline at end of file diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml new file mode 100644 index 000000000..e9a083910 --- /dev/null +++ b/app/views/docs/authentication-management.phtml @@ -0,0 +1,420 @@ +

+ Appwrite has built-in features to help manage user accounts. + Users can be organized into teams and be given labels, so they can be given different permissions and access different resources. + Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings. +

+ + +

User Preferences

+

+ You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. + You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices. +

+

+ Preferences are stored as a key-value JSON object. + The maximum allowed size for preferences is 64kB, and an error will be thrown if this limit is exceeded. +

+
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.updatePrefs({darkTheme: true, language: 'en'});
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +final account = Account(client);
    +
    +final user = await account.updatePrefs(
    +    prefs: {
    +        "darkTheme": true,
    +        "language": "en",
    +    }
    +);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +val user = account.updatePrefs(
    +    prefs = mapOf(
    +        "darkTheme" to true, 
    +        "language" to "en"
    +    )
    +)
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +let account = Account(client)
    +
    +let user = try await account.updatePrefs(
    +    prefs: [
    +        "darkTheme": true, 
    +        "language": "en"
    +    ]
    +)
    +
  • +
  • +

    GraphQL

    +
    +
    mutation {
    +    accountUpdatePrefs(
    +        prefs: "{\"darkTheme\": true, \"language\": \"en\"}"
    +    ) {
    +        _id
    +        name
    +        prefs {
    +            data
    +        }
    +    }
    +}
    +
    +
  • +
+ +

After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +const promise = account.getPrefs();
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +final account = Account(client);
    +
    +final prefs = await account.getPrefs();
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +val prefs = account.getPrefs()
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +let account = Account(client)
    +
    +let prefs = try await account.getPrefs()
    +
  • +
  • +

    GraphQL

    +
    +
    query {
    +    accountGetPrefs {
    +        data
    +    }
    +}
    +
    +
  • +
+ +

Users API

+

+ The Users API is a dedicated API for managing users from an admin's perspective. + You'll notice that the Account API doesn't allow you to view or make changes to other users. + This is by design and for security reasons. +

+ +

+ You can use the Users API with an API key authenticated Server SDK to manage users. + If you must expose parts of the Users API to normal users, we suggest doing so through an Appwrite Function. + Exposing API keys to users is dangerous and a security risk, by using an Appwrite Function, you can add your own validation to prevent malicious behavior. +

+ +

+ + Learn more about the Users API + +

+ +

Labels

+

+ Labels are a good way to flag a user to grant them access to resources. + For example, a subscriber label can be added to a user once they've purchased a subscription. +

+ +
    +
  • +

    Node.js

    +
    +
    const sdk = require('node-appwrite');
    +                    
    +const client = new sdk.Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
    +
    +const users = new sdk.Users(client);
    +
    +const promise = users.updateLabels(
    +    '[USER_ID]',
    +    [ Role.label('subscriber') ]
    +);
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    PHP

    + +
    +
    use Appwrite\Client;
    +use Appwrite\Services\Users;
    +use Appwrite\Role;
    +
    +$client = new Client();
    +
    +$client
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
    +
    +$users = new Users($client);
    +
    +$result = $users->updateLabels(
    +    '[USER_ID]', 
    +    [ Role.label('subscriber') ]
    +);
    +
    +
  • +
  • +

    Python

    +
    +
    from appwrite.client import Client
    +from appwrite.services.users import Users
    +from appwrite.role import Role
    +
    +client = Client()
    +
    +(client
    +  .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint
    +  .set_project('5df5acd0d48c2')                 # Your project ID
    +  .set_key('98fd4...a2ad2')                     # Your secret API key
    +)
    + 
    +users = Users(client)
    +
    +result = users.update_labels(
    +    '[USER_ID]',
    +    [ Role.label('subscriber') ]
    +)
    +
    +
  • +
  • +

    Ruby

    +
    +
    require 'appwrite'
    +
    +include Appwrite
    +
    +client = Client.new
    +    .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint
    +    .set_project('5df5acd0d48c2')                 # Your project ID
    +    .set_key('98fd4...a2ad2')                     # Your secret API key
    +
    +users = Users.new(client)
    +
    +response = users.update_labels(
    +    user_id: '[USER_ID]',
    +    labels: [ Role.label('subscriber') ]
    +)
    +
    +
  • +
  • +

    Deno

    +
    +
    import * as sdk from "https://deno.land/x/appwrite/mod.ts";
    +
    +let client = new sdk.Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
    +
    +let users = new sdk.Users(client);
    +
    +const promise = users.updateLabels(
    +    '[USER_ID]',
    +    [ Role.label('subscriber') ]
    +);
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Dart

    +
    +
    import 'package:dart_appwrite/dart_appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
    +
    +final users = Users(client);
    +
    +final result = await users.updateLabels(
    +    userId: '[USER_ID]',
    +    labels: [ Role.label('subscriber') ],
    +);
    +
    +
  • +
  • +

    Kotlin

    +
    +
    import io.appwrite.Client
    +import io.appwrite.Role
    +import io.appwrite.services.Users
    +
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +    .setKey("98fd4...a2ad2")                     // Your secret API key
    +
    +val users = Users(client)
    +
    +val response = users.updateLabels(
    +    userId = "[USER_ID]",
    +    labels = [ Role.label('subscriber') ]
    +)
    +
    +
  • +
  • +

    Swift

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +    .setKey("98fd4...a2ad2")                     // Your secret API key
    +
    +let users = Users(client)
    +
    +let response = try await users.updateLabels(
    +    userId: "[USER_ID]",
    +    labels: [ Role.label('subscriber') ]
    +)
    +
    +
  • +
  • +

    .NET

    +
    +
    using Appwrite;
    +
    +var client = new Client()
    +    .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .SetProject("5df5acd0d48c2")                 // Your project ID
    +    .SetKey("98fd4...a2ad2");                    // Your secret API key
    +
    +var users = new Users(client);
    +
    +var response = await users.UpdateLabels(
    +    userId: "[USER_ID]",
    +    labels: [ Role.Label('subscriber') ]
    +);
    +
    +
  • +
+ +

+ This would correspond with the permissions Permissions.read(Role.label('subscriber')), Permissions.update(Role.label('subscriber')), Permissions.delete(Role.label('subscriber')), and Permissions.create(Role.label('subscriber')). +

+ + +

+ Learn more about permissions +

+ +

Teams

+

+ Teams are a good way to allow users to share access to resources. +

+ +

+ For example, in a todo app, a user can create a team for one of their todo lists and invite another user to the team to grant the other user access. + The invited user can accept the invitation to gain access. + If the user's ever removed from the team, they'll lose access again. +

diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml new file mode 100644 index 000000000..b2937de3c --- /dev/null +++ b/app/views/docs/authentication-oauth.phtml @@ -0,0 +1,369 @@ +

+ OAuth authentication allows users to log in using accounts from other popular services. + This can be convenient for users because they can start using your app without creating a new account. + It can also be more secure, because the user has one less password that could become vulnerable. +

+ +

+ When using OAuth to authenticate, the authentication request is initiated from the client application. + The user is then redirected to an OAuth 2 provider to complete the authentication step, and finally, the user is redirected back to the client application. +

+ +

Configure OAuth 2 Login

+

+ Before using OAuth 2 login, you need to enable and configure an OAuth 2 login provider. +

+ +
    +
  1. Navigate to your Appwrite project.
  2. +
  3. Navigate to Auth > Settings.
  4. +
  5. Find and open the OAuth provider.
  6. +
  7. In the OAuth 2 settings modal, use the toggle to enable the provider.
  8. +
  9. Create and OAuth 2 app on the provider's developer platform.
  10. +
  11. Copy information from your OAuth2 provider's developer platform to fill the OAuth2 Settings modal in the Appwrite Console.
  12. +
  13. Configure redirect URL in your OAuth 2 provider's developer platform. Set it to URL provided to you by OAuth2 Settings modal in Appwrite Console.
  14. +
+ + +

Initialize OAuth 2 Login

+ +

+ To initialize the OAuth 2 login process, use the Create OAuth 2 Session route. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');                 // Your project ID
    +
    +const account = new Account(client);
    +
    +// Go to OAuth provider login page
    +account.createOAuth2Session('amazon', [LINK_ON_SUCCESS], [LINK_ON_FAILURE]);
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');               // Your project ID
    +
    +final account = Account(client);
    +
    +// Go to OAuth provider login page
    +await account.createOAuth2Session(provider: 'amazon');
    +
    +
  • +
  • +

    Android

    +

    In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the <application> tag, along side the existing <activity> tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

    + +
    +
    escape('
    +  ...
    +  
    +    ...
    +    
    +    
    +      
    +        
    +        
    +        
    +        
    +      
    +    
    +  
    +'); ?>
    +
    +
    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +
    +val account = Account(client)
    +
    +// Go to OAuth provider login page
    +account.createOAuth2Session(provider = "amazon")
    +
    +
  • +
  • +

    Apple

    +

    In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your Info.plist.

    + +
    +
    escape('CFBundleURLTypes
    +
    +
    +    CFBundleTypeRole
    +    Editor
    +    CFBundleURLName
    +    io.appwrite
    +    CFBundleURLSchemes
    +    
    +        appwrite-callback-[PROJECT_ID]
    +    
    +
    +
    +');?>
    +
    + +

    If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

    + +
    +
    escape('
    +func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
    +    guard let url = URLContexts.first?.url,
    +        url.absoluteString.contains("appwrite-callback") else {
    +        return
    +    }
    +    WebAuthComponent.handleIncomingCookie(from: url)
    +}
    +');?>
    +
    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                // Your project ID
    +
    +let account = Account(client)
    +
    +// Go to OAuth provider login page
    +try await account.createOAuth2Session(provider: "amazon")
    +
    +
  • +
  • +

    GraphQL

    +
    +

    OAuth 2 is not available through the GraphQL API. You can use the REST API or any Client SDK instead.

    +
    +
  • +
+ +

+ You'll be redirected to the OAuth 2 provider's login page to log in. + Once complete, your user will be redirected back to your app. +

+ +

+ You can optionally configure success or failure redirect links on web to handle success and failure scenarios. +

+ +

OAuth 2 Profile

+

+After authenticating a user through their OAuth 2 provider, you can fetch their profile information such as their avatar image or name. +To do this you can use the access token from the OAuth 2 provider and make API calls to the provider. +

+ +

+After creating an OAuth 2 session, you can fetch the session to get information about the provider. +

+ +
    +
  • +

    Web

    +
    +
    import { Client, Account } from "appwrite";
    +
    +const client = new Client();
    +
    +const account = new Account(client);
    +
    +const session = await account.getSession('current');
    +
    +// Provider information
    +console.log(session.provider);
    +console.log(session.providerUid);
    +console.log(session.providerAccessToken);
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]');               // Your project ID
    +
    +final account = Account(client);
    +
    +final session = await getSession(
    +    sessionId : "[SESSION_ID]"
    +);
    +
    +// Provider information
    +print(session.provider);
    +print(session.providerUid);
    +print(session.providerAccessToken);
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2") // Your project ID
    +
    +val account = Account(client)
    +
    +val response = account.getSession(
    +    sessionId = "[SESSION_ID]"
    +)
    +
    +// Provider information
    +print(session.provider);
    +print(session.providerUid);
    +print(session.providerAccessToken);
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2") // Your project ID
    +
    +let account = Account(client)
    +
    +let session = try await account.getSession(
    +    sessionId: "[SESSION_ID]"
    +)
    +
    +// Provider information
    +print(session.provider);
    +print(session.providerUid);
    +print(session.providerAccessToken);
    +
  • +
+ +

+ An OAuth 2 session will have the following attributes. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
propertyDescription
providerThe OAuth2 Provider.
providerUid User ID from the OAuth 2 Provider.
providerAccessTokenAccess token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal data.
providerAccessTokenExpiryCheck this value to know if an access token is about to expire.
+ +

+ You can use the providerAccessToken to make requests to your OAuth 2 provider. + Refer to the docs for the OAuth 2 provider you're using to learn about making API calls with the access token. +

+ +

Refresh Tokens

+

+ OAuth 2 sessions expire to protect from security risks. + OAuth 2 sessions should be refreshed periodically, so access tokens don't expire. + Check value of providerAccessTokenExpiry to know if the token is expired or is about to expire. + Refreshing before every request might cause rate limit problems. + You can do this by calling the Update OAuth Session endpoint when ever your user visits your app. +

+ +
    +
  • +

    Web

    +
    +
    const promise = account.updateSession('[SESSION_ID]');
    +
    +promise.then(function (response) {
    +    console.log(response); // Success
    +}, function (error) {
    +    console.log(error); // Failure
    +});
    +
    +
  • +
  • +

    Flutter

    +
    +
    import 'package:appwrite/appwrite.dart';
    +
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2');                // Your project ID
    +
    +Account account = Account(client);
    +
    +final result = await account.updateSession(
    +    sessionId: '[SESSION_ID]'
    +);
    +
    +
  • +
  • +

    Android

    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Account
    +
    +val client = Client(context)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +
    +val account = Account(client)
    +
    +val response = account.updateSession(
    +    sessionId = "[SESSION_ID]"
    +)
    +
    +
  • +
  • +

    Apple

    +
    +
    import Appwrite
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2") // Your project ID
    +
    +let account = Account(client)
    +
    +let session = try await account.updateSession(
    +    sessionId: "[SESSION_ID]"
    +)
    +
    +
  • +
  • +

    GraphQL

    +
    +

    OAuth 2 is not available through the GraphQL API. You can use the REST API or any Client SDK instead.

    +
    +
  • +
\ No newline at end of file diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 241e6893e..d9d840c1c 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -10,7 +10,7 @@

Best Practice

-

Only keep user sessions active as long as needed and only maintain one instance of the Client SDK in your app to avoid conflicting session data.

+

Only keep user sessions active as long as needed and maintain exactly one instance of the Client SDK in your app to avoid conflicting session data.

@@ -74,23 +74,32 @@

Session Limits

-

In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit deletes the oldest session.

+

In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit delete the oldest session.

You can change the session limit in the Security tab of the Auth Service in your Appwrite Console. The default session limit is 10 with a maximum configurable limit of 100.

-

Security

+

Permissions

- Security is very important to protect users' data and privacy. Appwrite uses a permissions model coupled with user sessions to ensure users need correct permissions to access resources. With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. + Security is very important to protect users' data and privacy. + Appwrite uses a permissions model coupled with user sessions to ensure users need correct permissions to access resources. + With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. + These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key.

-

Password History

-

Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password everytime it's changed.

+

Password History

+

Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password every time it's changed.

-

Password history can be enabled in the Auth service's Security tab on the Appwrite console. You can choose how many previous passwords to remember up to a maximum of 20 and block users from reusing them.

+

Password history can be enabled in the Auth service's Security tab on the Appwrite Console. You can choose how many previous passwords to remember up to a maximum of 20 and block users from reusing them.

-

Password Dictionary

+

Password Dictionary

Password dictionary protects users from using bad passwords. It compares the user's password to the 10,000 most common passwords and throws an error if there's a match. Together with rate limits, password dictionary will significantly reduce the chance of a malicious actor from guessing user passwords.

+

Password dictionary can be enabled in the Auth service's Security tab on the Appwrite Console.

-

Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

\ No newline at end of file +

Personal Data

+

+ Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal data. + Personal data includes the user's name, email, and phone number. +

+

Disallowing personal data can be enabled in the Auth service's Security tab on the Appwrite Console.

\ No newline at end of file diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 186b5eb5b..52c2e1ff9 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -7,12 +7,12 @@

Proof of Identity

-

Before making requests to your backend APIs, your client application needs to first create a session directly with Appwrite using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will only receive information accessible to the user based on the resources's permissions.

+

Before making requests to your backend APIs, your client application needs to first create a session directly with Appwrite using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will only receive information accessible to the user based on the resources' permissions.

When you build backend APIs to extend Appwrite's functionality, these APIs should still respect access permissions to keep user data secure. Appwrite's backend SDKs allows you to securely act on behalf of a user with the same permissions by using JWT authentication.

JWT Authentication

-

JSON Web Tokens (JWTs) are a secure means to transfer information or claims between two parties. JWT act like temporary copies of the user's ID card that allow Appwrite's Server SDKs to access information oh behalf of a user.

+

JSON Web Tokens (JWTs) are a secure means to transfer information or claims between two parties. JWTs act like temporary copies of the user's ID card that allow Appwrite's Server SDKs to access information on behalf of a user.

You need to create a session using the Client SDKs before generating a JWT. The JWT will be a stateless proof of claim for the identity of the authenticated user and expire after 15 minutes or when the session is deleted.

@@ -26,17 +26,11 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); -const promise = account.createJWT(); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createJWT();
  • @@ -46,7 +40,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -62,7 +56,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -75,7 +69,7 @@ val jwt = account.createJWT() let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -101,12 +95,10 @@ let jwt = try await account.createJWT()
    const { Client } = require('node-appwrite');
     
    -const client = new Client();
    -
    -client
    +const client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
  • @@ -115,12 +107,10 @@ client
    use Appwrite\Client;
     
    -$client = new Client();
    -
    -$client
    +$client = (new Client())
         ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
    -    ->setProject('[PROJECT_ID]')                           // Your project ID
    -    ->setJWT('eyJJ9.eyJ...886ca');                          // Your secret JSON Web Token
    + ->setProject('[PROJECT_ID]') // Your project ID + ->setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
  • @@ -131,9 +121,9 @@ $client client = Client() (client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token )
  • @@ -145,11 +135,9 @@ client = Client() include Appwrite client = Client.new - -client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token
  • @@ -157,12 +145,10 @@ client
    import { Client } from "https://deno.land/x/appwrite/mod.ts";
     
    -let client = new Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                            // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');                           // Your secret JSON Web Token
    +let client = new Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
  • @@ -170,12 +156,10 @@ client
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -final client = Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    +final client = Client() + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
  • @@ -184,11 +168,9 @@ client
    import io.appwrite.Client
     
     val client = Client()
    -
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                // Your project ID
    -    .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
    + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
  • @@ -197,11 +179,9 @@ client
    import Appwrite
     
     let client = Client()
    -
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                // Your project ID
    -    .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
    + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
  • @@ -209,12 +189,10 @@ client
    using Appwrite;
     
    -var client = new Client();
    -
    -client
    -    .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -    .SetProject("[PROJECT_ID]")                // Your project ID
    -    .SetJWT("eyJJ9.eyJ...886ca");               // Your secret JSON Web Token
    +var client = new Client() + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token
  • @@ -269,16 +247,17 @@ client
    const { Client } = require('node-appwrite');
     
    -const client = new Client();
    -
    -client
    +const client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    +    .setProject('[PROJECT_ID]')                  // Your project ID
    +    .setJWT('eyJJ9.eyJ...886ca');                // Your secret JSON Web Token
     
     const databases = new sdk.Databases(client);
     
    -const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +const documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -288,16 +267,17 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592
    use Appwrite\Client;
     
    -$client = new Client();
    -
    -$client
    +$client = (new Client())
         ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
         ->setProject('[PROJECT_ID]')                           // Your project ID
         ->setJWT('eyJJ9.eyJ...886ca');                          // Your secret JSON Web Tokens
     
     $databases = new Databases($client);
     
    -$result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +$documents = $databases->listDocuments(
    +    databaseId: '642f358bf4084c662590',
    +    collectionId: '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -316,7 +296,10 @@ client = Client() databases = Databases(client) -result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id='642f358bf4084c662590', + collection_id='642f3592aa5fc856ad1e' +) # ... More code to manipulate the results @@ -328,16 +311,17 @@ result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e' include Appwrite -client = Client - -client.new +client = Client.new .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint .set_project('[PROJECT_ID]') # Your project ID .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token databases = Databases.new(client) -response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id: '642f358bf4084c662590', + collection_id: '642f3592aa5fc856ad1e' +) # ... More code to manipulate the results @@ -346,16 +330,17 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35
    import { Client } from "https://deno.land/x/appwrite/mod.ts";
     
    -let client = new Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                            // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');                           // Your secret JSON Web Token
    +let client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
    +    .setProject('[PROJECT_ID]')                     // Your project ID
    +    .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
     
     let databases = new sdk.Databases(client);
     
    -let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +let documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -364,16 +349,14 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -final client = Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
    +    .setProject('[PROJECT_ID]')                     // Your project ID
    +    .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
     
    -Databases databases = Databases(client);
    +final databases = Databases(client);
     
    -Future result = databases.listDocuments(
    +final documents = await databases.listDocuments(
         databaseId: '642f358bf4084c662590',
         collectionId: '642f3592aa5fc856ad1e',
     );
    @@ -386,15 +369,13 @@ Future result = databases.listDocuments(
                 
    import io.appwrite.Client
     
     val client = Client()
    -
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                // Your project ID
    -    .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
    +    .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                     // Your project ID
    +    .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
     
     val databases = Databases(client)
     
    -val response = databases.listDocuments(
    +val documents = databases.listDocuments(
         databaseId = "642f358bf4084c662590",
         collectionId = "642f3592aa5fc856ad1e",
     )
    @@ -407,19 +388,17 @@ val response = databases.listDocuments(
                 
    import Appwrite
     
     let client = Client()
    -
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                // Your project ID
    -    .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
    +    .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                     // Your project ID
    +    .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
         
     let databases = Databases(client)
     
    -let documentList = try await databases.listDocuments(
    +let documents = try await databases.listDocuments(
         databaseId: "642f358bf4084c662590",
         collectionId: "642f3592aa5fc856ad1e"
     )
    -/ ... More code to manipulate the results
    +// ... More code to manipulate the results
  • @@ -429,16 +408,14 @@ let documentList = try await databases.listDocuments( using Appwrite.Services; using Appwrite.Models; -var client = new Client(); - -client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("[PROJECT_ID]") // Your project ID - .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token +var client = new Client() + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token var databases = new Databases(client); -var documentList = await databases.ListDocuments( +var documents = await databases.ListDocuments( databaseId: "642f358bf4084c662590", collectionId: "642f3592aa5fc856ad1e"); @@ -447,7 +424,7 @@ var documentList = await databases.ListDocuments(
  • -

    Only the birthday of Kevin is returned and documents where user-A has no permissions to access are not returned.

    +

    Only Kevin's birthday is returned and documents where user-A has no permissions to access are not returned.

    {
       "total": 1,
    @@ -467,23 +444,24 @@ var documentList = await databases.ListDocuments(
     }
    -

    If the same request is made where the Server SDK's client is authenticate with an API key instead of a JWT, the results returned will be different.

    +

    If the same request is made where the Server SDK's client is authenticated with an API key instead of a JWT, the results returned will be different.

    • Node.js

      const { Client } = require('node-appwrite');
       
      -const client = new Client();
      -
      -client
      +const client = new Client()
           .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      -    .setProject('[PROJECT_ID]')                // Your project ID
      -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key
      +    .setProject('[PROJECT_ID]')                  // Your project ID
      +    .setKey('98fd4...a2ad2');                    // Your secret API key
       
       const databases = new sdk.Databases(client);
       
      -const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
      +const documents = await databases.listDocuments(
      +    '642f358bf4084c662590',
      +    '642f3592aa5fc856ad1e'
      +);
       // ... More code to manipulate the results
    • @@ -493,16 +471,17 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592
      use Appwrite\Client;
       
      -$client = new Client();
      -
      -$client
      -    ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
      -    ->setProject('[PROJECT_ID]')                           // Your project ID
      -    ->setKey('919c2d18fb5d4...a2ae413da83346ad2')           // Your secret API key
      +$client = (new Client())
      +    ->setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      +    ->setProject('[PROJECT_ID]')                  // Your project ID
      +    ->setKey('98fd4...a2ad2');                    // Your secret API key
       
       $databases = new Databases($client);
       
      -$result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
      +$documents = $databases->listDocuments(
      +    databaseId: '642f358bf4084c662590',
      +    collectionId: '642f3592aa5fc856ad1e'
      +);
       // ... More code to manipulate the results
      @@ -514,15 +493,19 @@ $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1 client = Client() (client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key
      + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key ) databases = Databases(client) -result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id='642f358bf4084c662590', + collection_id='642f3592aa5fc856ad1e' +) # ... More code to manipulate the results +
    • @@ -532,16 +515,17 @@ result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e' include Appwrite -client = Client - -client.new - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key databases = Databases.new(client) -response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id: '642f358bf4084c662590', + collection_id: '642f3592aa5fc856ad1e' +) # ... More code to manipulate the results
    • @@ -550,16 +534,17 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35
      import { Client } from "https://deno.land/x/appwrite/mod.ts";
       
      -let client = new Client();
      -
      -client
      -    .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
      -    .setProject('[PROJECT_ID]')                            // Your project ID
      -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')            // Your secret API key
      +let client = new Client()
      +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      +    .setProject('[PROJECT_ID]')                  // Your project ID
      +    .setKey('98fd4...a2ad2');                    // Your secret API key
       
       let databases = new sdk.Databases(client);
       
      -let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
      +let documents = await databases.listDocuments(
      +    '642f358bf4084c662590',
      +    '642f3592aa5fc856ad1e'
      +);
       // ... More code to manipulate the results
      @@ -568,16 +553,14 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a
      import 'package:dart_appwrite/dart_appwrite.dart';
       
      -final client = Client();
      -
      -client
      +final client = Client()
           .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      -    .setProject('[PROJECT_ID]')                // Your project ID
      -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key
      +    .setProject('[PROJECT_ID]')                  // Your project ID
      +    .setKey('98fd4...a2ad2');                    // Your secret API key
       
      -Databases databases = Databases(client);
      +final databases = Databases(client);
       
      -Future result = databases.listDocuments(
      +final documents = await databases.listDocuments(
           databaseId: '642f358bf4084c662590',
           collectionId: '642f3592aa5fc856ad1e',
       );
      @@ -590,15 +573,13 @@ Future result = databases.listDocuments(
                   
      import io.appwrite.Client
       
       val client = Client()
      -
      -client
           .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
      -    .setProject("[PROJECT_ID]")                // Your project ID
      -    .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key
      +    .setProject("[PROJECT_ID]")                  // Your project ID
      +    .setKey('98fd4...a2ad2');                    // Your secret API key
       
       val databases = Databases(client)
       
      -val response = databases.listDocuments(
      +val documents = databases.listDocuments(
           databaseId = "642f358bf4084c662590",
           collectionId = "642f3592aa5fc856ad1e",
       )
      @@ -611,19 +592,17 @@ val response = databases.listDocuments(
                   
      import Appwrite
       
       let client = Client()
      -
      -client
           .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
      -    .setProject("[PROJECT_ID]")                // Your project ID
      -    .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key
      -    
      -    let databases = Databases(client)
      -    
      -    let documentList = try await databases.listDocuments(
      -        databaseId: "642f358bf4084c662590",
      -        collectionId: "642f3592aa5fc856ad1e"
      -    )
      -    // ... More code to manipulate the results
      + .setProject("[PROJECT_ID]") // Your project ID + .setKey('98fd4...a2ad2'); // Your secret API key + +let databases = Databases(client) + +let documents = try await databases.listDocuments( + databaseId: "642f358bf4084c662590", + collectionId: "642f3592aa5fc856ad1e" +) +// ... More code to manipulate the results
    • @@ -633,16 +612,14 @@ client using Appwrite.Services; using Appwrite.Models; -var client = new Client(); - -client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint +var client = new Client() + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint .SetProject("[PROJECT_ID]") // Your project ID - .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + .SetKey('98fd4...a2ad2'); // Your secret API key var databases = new Databases(client); -var documentList = await databases.ListDocuments( +var documents = await databases.ListDocuments( databaseId: "642f358bf4084c662590", collectionId: "642f3592aa5fc856ad1e"); diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml new file mode 100644 index 000000000..8322f92b1 --- /dev/null +++ b/app/views/docs/authentication-sms.phtml @@ -0,0 +1,203 @@ +

      + Phone authentication lets users create accounts using their phone numbers and log in through SMS messages. +

      + + +

      Send SMS Message

      + +

      + Phone authentication is done using a two-step authentication process. + When using phone authentication, the authentication request is initiated from the client application and an SMS message is sent to the user's phone. + The SMS message will contain a secret the user can use to log in. +

      + +

      + Send an SMS message to initiate the authentication process. + A new account will be created for this phone number if it has never been used before. +

      + +
        +
      • +

        Web

        +
        +
        import { Client, Account, ID } from "appwrite";
        +
        +const client = new Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('[PROJECT_ID]');                 // Your project ID
        +
        +const account = new Account(client);
        +
        +const sessionToken = await account.createPhoneSession(
        +    ID.unique(),
        +    '+14255550123'
        +);
        +
        +const userId = sessionToken.userId; // Store this somewhere to use later when logging in
        +
        +
      • +
      • +

        Flutter

        +
        +
        import 'package:appwrite/appwrite.dart';
        +
        +final client = Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('[PROJECT_ID]');                 // Your project ID
        +
        +final account = Account(client);
        +
        +final sessionToken = await account.createPhoneSession(
        +    userId: ID.unique(),
        +    phone: '+14255550123'
        +);
        +
        +final userId = sessionToken.userId; // Store this somewhere to use later when logging in
        +
      • +
      • +

        Android

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Account
        +import io.appwrite.ID
        +
        +val client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("[PROJECT_ID]")                  // Your project ID
        +
        +val account = Account(client)
        +
        +val sessionToken = account.createPhoneSession(
        +    userId = ID.unique(),
        +    phone = "+14255550123"
        +)
        +
        +val userId = sessionToken.userId // Store this somewhere to use later when logging in
        +
      • +
      • +

        Apple

        +
        +
        import Appwrite
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("[PROJECT_ID]")                  // Your project ID
        +
        +let account = Account(client)
        +
        +let sessionToken = try await account.createPhoneSession(
        +    userId: ID.unique(),
        +    phone: "+14255550123"
        +)
        +
        +let userId = sessionToken.userId // Store this somewhere to use later when logging in
        +
      • +
      • +

        GraphQL

        +
        +
        mutation {
        +    accountCreatePhoneSession(userId: "unique()", phone: "+14255550123") {
        +        _id
        +        userId
        +        secret
        +        expire
        +    }
        +}
        +
        +
      • +
      + + +

      Log In

      +

      + After initiating the phone authentication process, the returned user ID and secret are used to confirm the user. + The secret will usually be a 6-digit number in the SMS message sent to the user. +

      + +
        +
      • +

        Web

        +
        +
        import { Client, Account, ID } from "appwrite";
        +
        +const client = new Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('[PROJECT_ID]');                 // Your project ID
        +
        +const account = new Account(client);
        +
        +const session = await account.updatePhoneSession(
        +    userId,    // From when you called createPhoneSession
        +    '[SECRET]' // The 6-digit code from the SMS message
        +);
        +
        +
      • +
      • +

        Flutter

        +
        +
        import 'package:appwrite/appwrite.dart';
        +
        +final client = Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('[PROJECT_ID]');                 // Your project ID
        +
        +final account = Account(client);
        +
        +final session = await account.updatePhoneSession(
        +    userId: userId,    // From when you called createPhoneSession
        +    secret: '[SECRET]' // The 6-digit code from the SMS message
        +);
        +
      • +
      • +

        Android

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Account
        +import io.appwrite.ID
        +
        +val client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("[PROJECT_ID]")                  // Your project ID
        +
        +val account = Account(client)
        +
        +val session = account.updatePhoneSession(
        +    userId = userId,    // From when you called createPhoneSession
        +    secret = "[SECRET]" // The 6-digit code from the SMS message
        +)
        +
      • +
      • +

        Apple

        +
        +
        import Appwrite
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("[PROJECT_ID]")                  // Your project ID
        +
        +let account = Account(client)
        +
        +let session = try await account.updatePhoneSession(
        +    userId: userId,    // From when you called createPhoneSession
        +    secret: "[SECRET]" // The 6-digit code from the SMS message
        +)
        +
      • +
      • +

        GraphQL

        +
        +
        
        +mutation {
        +    accountUpdatePhoneSession(userId: "[USER_ID]", secret: "[SECRET]") {
        +        _id
        +        userId
        +        provider
        +        expire
        +    }
        +}
        +
        +
      • +
      + +

      + After the secret is verified, a session will be created. +

      \ No newline at end of file diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 9910bc286..05e44aa9c 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -1,37 +1,16 @@

      - Appwrite provides authentication for many different use cases to fit the needs of developers. - Appwrite manages authentication with a combination of accounts and sessions. - Accounts can be created in many different ways, such as through an anonymous session, email and password, OAuth authentication, magic URLs, and more. -

      - -

      Account vs Users API

      - -

      - The Account API operates in the scope of the currently logged-in account and is usually used in a frontend or mobile app. The Users API is used in backend integrations and uses an API key with access to all your project users. -

      - -

      - Some of the Account API methods are available from Server SDKs when you authenticate with a JWT. This allows your Server SDK to perform actions on behalf of a user. -

      - -

      Create An Account

      - -

      - A user account in Appwrite is the primary way to access information for a given project. Accounts can be created in many different ways, including email & password, anonymous sessions, OAuth2, phone authentication, and more. Applications can create and manage sessions through the REST API or Client SDKs. -

      - -

      Email

      - -

      - Creating an account via email and password is one of the most common ways to sign up for an application. Appwrite provides email and password authentication out of the box. Using one of Appwrite's Client SDKs, or the REST APIs directly, you can create an account using an email address and password in your application. + Appwrite Authentication delivers more than just user sign up and log in. + Authentication makes it easy to build secure and robust authentication with support for many different authentication methods.

      - Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. + You can manage user accounts with user preferences, user labeling, or organizing users into teams. + Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manage users.

      +

      Getting Started

      - The example below shows you how to create an account: + Adding Appwrite Authentication to your apps can be as easy as these lines of code.

        @@ -46,17 +25,11 @@ const client = new Client() const account = new Account(client); -const promise = account.create( +const user = await account.create( ID.unique(), - 'team@appwrite.io', + 'email@example.com', 'password' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
      • @@ -72,7 +45,7 @@ final account = Account(client); final user = await account.create( userId: ID.unique(), - email: 'team@appwrite.io', + email: 'email@example.com', password: 'password', );
      • @@ -91,7 +64,7 @@ val account = Account(client) val user = account.create( userId = ID.unique(), - email = "team@appwrite.io", + email = "email@example.com", password = "password" ) @@ -109,7 +82,7 @@ let account = Account(client) let user = try await account.create( userId: ID.unique(), - email: "team@appwrite.io", + email: "email@example.com", password: "password" ) @@ -119,7 +92,7 @@ let user = try await account.create(
        
         mutation {
        -    accountCreate(userId: "unique()", email: "team@appwrite.io", password: "password") {
        +    accountCreate(userId: "unique()", email: "email@example.com", password: "password") {
                 _id
                 email
                 name
        @@ -130,1139 +103,78 @@ mutation {
         

      - After an account is created, it can be verified through the account verification route provided by the Appwrite Accounts API. The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions. + Use email and password authentication as a starting point and explore the many powerful features of Appwrite authentication.

      -

      Anonymous User

      +

      Account vs Users API

      -Anonymous authentication allows users of your application to create a temporary valid session without creating an account. The session has an expiration time of one year. If an account is created while an anonymous session is active, it will be attached to the existing anonymous session. + Appwrite has two auth APIs for different purposes, which are Account and Users. + Here's how you choose between the two, depending on your needs.

      -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.createAnonymousSession();
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = await account.createAnonymousSession();
        -
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val user = account.createAnonymousSession()
        -
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        +

        Account API

        +

        + Use the Account API when acting on behalf of individual users when building client applications, like websites or mobile apps. + The Account API is authenticated through secure cookies that store session information, so Appwrite knows which authenticated user is accessing data. + The Account API is safe to expose to end users, because their access to data and resources is limited by Appwrite's permission system. +

        -let user = try await account.createAnonymousSession()
        -
        -
      • -
      • -

        GraphQL

        -
        -
        
        -mutation {
        -    accountCreateAnonymousSession {
        -        _id
        -        userId
        -        provider
        -        expire
        -    }
        -}
        -
        -
      • -
      +

      Users API

      +

      + Use the Users API when acting as an administrator in use cases like building admin consoles or server integrations. + The Users API uses API keys to authenticate, which means Appwrite only knows which API key is accessing data. + API keys don't respect permissions, which means they can access all data, and should never be shared with end users in client applications. + The Users API also has batch operations, letting you query and manage users from an admin's perspective. +

      -

      OAuth

      +

      Explore

      +

      Explore Appwrite Authentication's features.

      - OAuth is another way to authenticate a user using a multistep process. When using OAuth to authenticate, the authentication request is initiated from the client application. The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. This provides integration with many third-party services that provide their own OAuth integration as a more secure approach than providing a username/password directly. + + Log in with email and password +

      - In applications with first-party redirects, using OAuth2 for authentication is preferred. + + Log in with SMS messages +

      - The example below shows you how to authenticate with OAuth2 using Amazon's OAuth system. + + Log in with Magic URL +

      -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -// Go to OAuth provider login page
        -account.createOAuth2Session('amazon');
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -// Go to OAuth provider login page
        -await account.createOAuth2Session(provider: 'amazon');
        -
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -// Go to OAuth provider login page
        -account.createOAuth2Session(provider = "amazon")
        -
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -// Go to OAuth provider login page
        -try await account.createOAuth2Session(provider: "amazon")
        -
        -
      • -
      • -

        GraphQL

        -
        -

        OAuth is not available through the GraphQL API. You can use the REST API or any Client SDK instead.

        -
        -
      • -
      - -

      - If there is already an active anonymous session, the new session will be attached to it. If there are no active sessions, the server will attempt to look for an account with the same email address as the email received from the OAuth2 provider and attach the new session to the existing account. If no matching account is found - the server will create a new account. +

      + + Log in with OAuth 2 +

      -

      Phone

      -

      - Phone authentication is done using a two-step authentication process. When using phone authentication, the authentication request is initiated from the client application and an SMS is sent to the user with a secret key for creating a session. + + Log in as a guest (anonymous) +

      - The example below shows you how to initiate a phone authentication request. + + Manage users +

      -
        -
      • -

        Web

        -
        -
        import { Client, Account, ID } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.createPhoneSession(
        -    ID.unique(),
        -    '+16171234567'
        -);
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final session = await account.createPhoneSession(
        -    userId: ID.unique(),
        -    phone: '+16171234567'
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -import io.appwrite.ID
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val session = account.createPhoneSession(
        -    userId = ID.unique(),
        -    phone = "+16171234567"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let session = try await account.createPhoneSession(
        -    userId: ID.unique(),
        -    phone: "+16171234567"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountCreatePhoneSession(userId: "unique()", phone: "+16171234567") {
        -        _id
        -        userId
        -        secret
        -        expire
        -    }
        -}
        -
        -
      • -
      -

      - After initiation, the returned user ID and secret are used to confirm the user. The secret will be a 6-digit number in the SMS message sent to the user. + + Server integrations +

      -
        -
      • -

        Web

        -
        -
        import { Client, Account, ID } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.updatePhoneSession(
        -    '[USER_ID]',
        -    '[SECRET]'
        -);
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final session = await account.updatePhoneSession(
        -    userId: '[USER_ID]',
        -    secret: '[SECRET]'
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -import io.appwrite.ID
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val session = account.updatePhoneSession(
        -    userId = "[USER_ID]",
        -    secret = "[SECRET]"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let session = try await account.updatePhoneSession(
        -    userId: "[USER_ID]",
        -    secret: "[SECRET]"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        
        -mutation {
        -    accountUpdatePhoneSession(userId: "[USER_ID]", secret: "[SECRET]") {
        -        _id
        -        userId
        -        provider
        -        expire
        -    }
        -}
        -
        -
      • -
      - -

      - After the secret is verified, a session will be created. -

      - - -

      Magic URL

      -

      - Magic URL authentication allows a user to sign in without a password. Magic URL authentication sends the user an email with a secret key for creating a new session. If the provided email does not belong to an existing user, the provided user ID is used to create a new user. If the account already exists, the provided user ID is ignored -

      - -

      - Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

      - - -

      - Magic URL authentication can be initiated like this: -

      - - -
        -
      • -

        Web

        -
        -
        import { Client, Account, ID } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.createMagicURLSession(ID.unique(), 'email@example.com');
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = await account.createMagicURLSession(
        -    userId: ID.unique(),
        -    email: 'email@example.com',
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client(context)
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val user = account.createMagicURLSession(
        -    userId = ID.unique(),
        -    email = "email@example.com"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let user = try await account.createMagicURLSession(
        -    userId: ID.unique(),
        -    email: "email@example.com"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountCreateMagicURLSession(
        -        userId: "unique()",
        -        email: "email@example.com"
        -    ) {
        -        _id
        -        _createdAt
        -        userId
        -        secret
        -        expire
        -    }
        -}
        -
        -
      • -
      - -

      - After receiving your secret from an email, you can create a new Magic URL session like this: -

      - - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.updateMagicURLSession('[USER_ID]', '[SECRET]');
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = await account.updateMagicURLSession(
        -    userId: '[USER_ID]',
        -    secret: '[SECRET]',
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client(context)
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val user = account.updateMagicURLSession(
        -    userId = '[USER_ID]',
        -    secret = '[SECRET]'
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let user = try await account.updateMagicURLSession(
        -    userId: '[USER_ID]',
        -    secret: "[SECRET]"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountUpdateMagicURLSession(
        -        userId: "[USER_ID]",
        -        secret: "[SECRET]"
        -    ) {
        -        _id
        -        _createdAt
        -        userId
        -        expire
        -        provider
        -    }
        -}
        -
        -
      • -
      - -

      Login

      - -

      - Logging in with an email and password is one of the most common ways to login into an application. -

      - -

      - The example below shows you how to create a session: -

      - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.createEmailSession(
        -    'team@appwrite.io',
        -    'password'
        -);
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final session = await account.createEmailSession(
        -    email: 'team@appwrite.io',
        -    password: 'password'
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val session = account.createEmailSession(
        -    email = "team@appwrite.io",
        -    password = "password"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let session = try await account.createEmailSession(
        -    email: "team@appwrite.io",
        -    password: "password"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountCreateEmailSession(email: "team@appwrite.io", password: "password") {
        -        _id
        -        userId
        -        provider
        -        expire
        -    }
        -}
        -
        -
      • -
      - -

      - When a user tries to access restricted resources, you can check if they have a valid, active session. The Account Service provides a get() method that checks whether the current user session is active and returns the account information if successful. -

      - -

      - The example below shows you how to check whether there is an active session: -

      - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.get();
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final session = await account.get();
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val session = account.get()
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let session = try await account.get()
        -
      • -
      • -

        GraphQL

        -
        -
        query {
        -    accountGet {
        -        _id
        -        email
        -        name
        -        status
        -    }
        -}
        -
        -
      • -
      - -

      - An authenticated session in Appwrite lasts for 1 year and is then automatically expired. -

      - - -

      Password Recovery

      -

      - If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. -

      - -

      - Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

      - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.createPasswordRecovery('email@example.com', 'https://example.com');
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = account.createRecovery(
        -    email: 'email@example.com',
        -    url: 'https://example.com',
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client(context)
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val response = account.createRecovery(
        -    email = "email@example.com",
        -    url = "https://example.com"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let token = try await account.createRecovery(
        -    email: "email@example.com",
        -    url: "https://example.com"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountCreateRecovery(
        -        email: "email@example.com",
        -        url: "https://example.com"
        -    ) {
        -        _id
        -        _createdAt
        -        userId
        -        secret
        -        expire
        -    }
        -}
        -
        -
      • -
      -

      -After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. -

      - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password');
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = await account.updateRecovery(
        -    userId: '[USER_ID]',
        -    secret: '[SECRET]',
        -    password: 'password'
        -    passwordAgain: 'password'
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client(context)
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val token = account.updateRecovery(
        -    userId = "[USER_ID]",
        -    secret = "[SECRET]",
        -    password = "password",
        -    passwordAgain = "password"
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let token = try await account.updateRecovery(
        -    userId: "[USER_ID]",
        -    secret: "[SECRET]",
        -    password: "password",
        -    passwordAgain: "password"
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountUpdateRecovery(
        -        userId: "[USER_ID]",
        -        secret: "[SECRET]",
        -        password: "password",
        -        passwordAgain: "password"
        -    ) {
        -        _id
        -        _createdAt
        -        userId
        -        secret
        -        expire
        -    }
        -}
        -
        -
      • -
      - - -

      User Preferences

      -

      You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

      -

      Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

      -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.updatePrefs({darkTheme: true, language: 'en'});
        -
        -promise.then(function (response) {
        -    console.log(response);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final user = await account.updatePrefs(
        -    prefs: {
        -        "darkTheme": true,
        -        "language": "en",
        -    }
        -);
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val user = account.updatePrefs(
        -    prefs = mapOf("darkTheme" to true, "language" to "en")
        -)
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let user = try await account.updatePrefs(
        -    prefs: ["darkTheme": true, "language": "en"]
        -)
        -
      • -
      • -

        GraphQL

        -
        -
        mutation {
        -    accountUpdatePrefs(
        -        prefs: "{\"darkTheme\": true, \"language\": \"en\"}"
        -    ) {
        -        _id
        -        _createdAt
        -        _updatedAt
        -        name
        -        registration
        -        status
        -        passwordUpdate
        -        email
        -        phone
        -        emailVerification
        -        phoneVerification
        -        prefs {
        -            data
        -        }
        -    }
        -}
        -
        -
      • -
      - -

      After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

      - -
        -
      • -

        Web

        -
        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -const account = new Account(client);
        -
        -const promise = account.getPrefs();
        -
        -promise.then(function (prefs) {
        -    console.log(prefs);
        -}, function (error) {
        -    console.log(error);
        -});
        -
        -
      • -
      • -

        Flutter

        -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -final client = Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]');               // Your project ID
        -
        -final account = Account(client);
        -
        -final prefs = await account.getPrefs();
        -
      • -
      • -

        Android

        -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Account
        -
        -val client = Client(context)
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -val account = Account(client)
        -
        -val prefs = account.getPrefs()
        -
      • -
      • -

        Apple

        -
        -
        import Appwrite
        -
        -let client = Client()
        -    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        -    .setProject("[PROJECT_ID]")                // Your project ID
        -
        -let account = Account(client)
        -
        -let prefs = try await account.getPrefs()
        -
      • -
      • -

        GraphQL

        -
        -
        query {
        -    accountGetPrefs {
        -        data
        -    }
        -}
        -
        -
      • -
      + + Security + +

      \ No newline at end of file diff --git a/app/views/docs/command-line-deployment.phtml b/app/views/docs/command-line-deployment.phtml index 79487ed3f..79e12b86d 100644 --- a/app/views/docs/command-line-deployment.phtml +++ b/app/views/docs/command-line-deployment.phtml @@ -27,7 +27,7 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,

      Deploying Appwrite Functions

      -

      The CLI also handles the creation and deployment of Appwrite Functions. You can initialize a new function using:

      +

      The CLI also handles the creation and deployment of Appwrite Functions. Run this command in the folder holding your appwrite.json file.

      appwrite init function
      @@ -36,7 +36,9 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,
       ✓ Success
      -

      This command creates a new function My Awesome Function in your current Appwrite project and also creates a template function for you to get started. You can now deploy this function using:

      +

      This command creates a new function My Awesome Function in your current Appwrite project and also creates a template function for you to get started.

      + +

      You can now deploy this function by running this command in the folder holding your appwrite.json file.

      appwrite deploy function
      @@ -47,7 +49,16 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,
       
       

      Deploying Databases and Collections

      -

      The Appwrite CLI also helps you migrate your project's databases and collections from a development server to a production server. You can deploy all the databases and collections in your appwrite.json file using:

      +

      The Appwrite CLI also helps you deploy your project's databases and collections schema from one project to another.

      + +

      + You can deploy all the databases and collections in your appwrite.json file by running this command in the folder holding your appwrite.json file. +

      + +

      + The deploy command will overwrite existing collections causing existing data to be lost. + If you already have data in your project, you will need to write your own migration script using a Server SDK instead of using the CLI. +

      appwrite deploy collection
      @@ -57,15 +68,17 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,

      The Appwrite CLI can create teams to organize users. Teams can be used to grant access permissions to a group of users. Learn more about permissions.

      +

      Deploy teams by running this command in the folder holding your appwrite.json file.

      appwrite deploy team
      -

      Deploying Storage Buckets

      The Appwrite CLI allows you to configure and deploy buckets across projects. All the bucket's settings are available through the appwrite.json file.

      +

      Deploy storage buckets by running this command in the folder holding your appwrite.json file.

      +
      appwrite deploy bucket
      diff --git a/app/views/docs/configuration.phtml b/app/views/docs/configuration.phtml index 44f0132e1..9a0fc31f7 100644 --- a/app/views/docs/configuration.phtml +++ b/app/views/docs/configuration.phtml @@ -19,6 +19,51 @@

      Set up SMS delivery

      +

      Configure GitHub App

      +

      + Appwrite supports automatic deployments through Git integration. + In order for Appwrite to access your repos, you must configure a GitHub app to enable this integration. +

      + +

      You'll have to configure the following environment variables.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      VariableDescription
      _APP_VCS_GITHUB_APP_NAMEName of your GitHub app. This value should be set to your GitHub application's URL.
      _APP_VCS_GITHUB_PRIVATE_KEYGitHub app RSA private key. You can generate private keys from GitHub application settings.
      _APP_VCS_GITHUB_APP_IDGitHub application ID. You can find it in your GitHub application details.
      _APP_VCS_GITHUB_CLIENT_IDGitHub client ID. You can find it in your GitHub application details.
      _APP_VCS_GITHUB_CLIENT_SECRETGitHub client secret. You can generate secrets in your GitHub application settings.
      _APP_VCS_GITHUB_WEBHOOK_SECRETGitHub webhook secret. You can configure it in your GitHub application settings under webhook section.
      + +

      Learn more about environment variables

      +

      Configure Function Runtimes

      Not all function runtimes are enabled by default. Enable the runtimes that you need and disable unused runtimes to save disk space on your server. @@ -62,4 +107,4 @@

      More Configurable Options

      If you don't see something you'd like to configure on this page, try searching the complete list of environment variables.

      -

      Learn more about environment variables

      +

      Learn more about environment variables

      \ No newline at end of file diff --git a/app/views/docs/custom-domains.phtml b/app/views/docs/custom-domains.phtml index 74c087140..5c178c322 100644 --- a/app/views/docs/custom-domains.phtml +++ b/app/views/docs/custom-domains.phtml @@ -356,7 +356,7 @@ $dns = [

      Confirm and Verify Your Domain

      -

      Once you added your new CNAME record to your DNS settings, you will need to verify your new domain name from your Appwrite console. Enter your custom domains tab from your project settings, click the DNS Settings link and click on the 'Confirm and Verify" button. If everything went well, Appwrite will approve your domain and generate a new SSL certificate for it in the background.

      +

      Once you added your new CNAME record to your DNS settings, you will need to verify your new domain name from your Appwrite Console. Enter your custom domains tab from your project settings, click the DNS Settings link and click on the 'Confirm and Verify" button. If everything went well, Appwrite will approve your domain and generate a new SSL certificate for it in the background.

      Enjoy your Free SSL Certificate

      diff --git a/app/views/docs/databases-relationships.phtml b/app/views/docs/databases-relationships.phtml index 5b0feb4c0..8da2831e2 100644 --- a/app/views/docs/databases-relationships.phtml +++ b/app/views/docs/databases-relationships.phtml @@ -1,8 +1,8 @@

      Relationships describe how documents in different collections are associated, so that related documents can be read, updated, or deleted together. Entities in real-life often associate with each other in an organic and logical way, like a person and their dog, an album and its songs, or friends in a social network. These types of association between entities can be modeled in Appwrite using relationships.

      -

      Beta Feature

      -

      Appwrite Relationships is a beta feature. The API and behavior are subject to change in future versions.

      +

      Experimental Feature

      +

      Appwrite Relationships is an experimental feature. The API and behavior are subject to change in future versions.

      When to Use a Relationship

      @@ -558,7 +558,7 @@ databases.createDocument(

      Querying

      -

      Querying is currently not available in the beta version of Appwrite Relationships but will be added in a later version.

      +

      Querying is currently not available in the experimental version of Appwrite Relationships but will be added in a later version.

      Updating Relationships

      diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml new file mode 100644 index 000000000..e685405f0 --- /dev/null +++ b/app/views/docs/email-and-sms-templates.phtml @@ -0,0 +1,251 @@ +

      Appwrite uses emails to communicate with users to perform authentication and verification actions. Emails can be customized to fit your app's design and voice.

      + +

      + Each Appwrite project can have its own set of unique templates. + Templates also support localization, so every template can be written in multiple languages and served + depending on the configured locale. +

      + +

      Custom SMTP server

      +

      + Appwrite Cloud has a default SMTP server to get you started. + This SMTP server sends generic emails and doesn't allow customizing SMTP templates. + To use custom SMTP templates, you will need to configure your own SMTP server. +

      + +

      + There are many third-party SMTP providers like SendGrid and Mailgun. + Before proceeding, pick an SMTP provider, create an account, and obtain Sender name, Sender email, Server host, Server port, Username, and Password. +

      + +
        +
      1. Navigate to your project's Settings.
      2. +
      3. Navigate to the SMTP tab.
      4. +
      5. Under SMTP server, toggle Custom SMTP server.
      6. +
      7. Input Sender name, Sender email, Server host, Server port, Username, and Password from your provider.
      8. +
      9. Click Update.
      10. +
      + +

      Customize Templates

      +

      You can customize email templates for each of your projects in the Appwrite Console.

      +
      +

      Custom SMTP Server Required

      +

      The built-in email service does not support custom email templates to prevent malicious templates. Configure a custom SMTP server to enable custom email templates.

      +
      +
        +
      1. In your project, navigate to the Auth service.
      2. +
      3. Under the Auth service, navigate to the Templates tab.
      4. +
      5. Expand the email template you want to edit.
      6. +
      7. Select the Template language. You can have a different template for each language your app supports.
      8. +
      9. Update the email template fields and click Update to save your changes.
      10. +
      +

      Email Templates

      +

      You can customize the email templates for account verification, magic-url authentication, password resets, and user invites.

      +

      Email Template Components

      +

      Each email templates has the following components that you can customize.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ComponentDescription
      Sender nameReaders will see this as a display name of the sender.
      Sender emailReaders will see this as a display email of the sender. This email must be authenticated on the SMTP provider you've configured, otherwise it will be delivered to the spam folder. This usually means the email must end with the same domain as your SMTP username.
      Reply toReaders will reply to this email address instead of the sender address. You can leave this field empty, and the sender email will be used automatically.
      SubjectThe title of the email.
      MessageThe body of the email in HTML format. You can find the variables available in the Email Template Syntax section.
      +

      Email Template Syntax

      +

      Variables can be used in email templates to dynamically construct unique emails for each reader. These variables can only be used in the Message field of the email template.

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      VariableDescription
      {{project}}The project name.
      {{team}}The project team's name.
      {{user}}The name of the user receiving the email. This variable is not available in the Magic URL template, as there might not be a user yet.
      {{redirect}}The URL for the user to complete the email template's action.
      + +

      Email Template Examples

      +

      Here's an example of using these variables in a template.

      +
      +
      <!doctype html>
      +<html>
      +
      +<head>
      +    <style>
      +        ... your style here
      +    </style>
      +</head>
      +
      +<body style="direction: ltr">
      +
      +<div style="max-width:650px; word-wrap: break-word; overflow-wrap: break-word;
      +  word-break: break-all; margin:0 auto;">
      +    <table style="margin-top: 32px">
      +        <tr>
      +            <td>
      +                <h1>
      +                    {{subject}}
      +                </h1>
      +            </td>
      +        </tr>
      +    </table>
      +
      +    <table style="margin-top: 40px">
      +        <tr>
      +            <td>
      +                <p>Hello </p>
      +
      +                <p>Follow this link to reset your {{project}} password.</p>
      +
      +                <a href="{{redirect}}" target="_blank">{{redirect}}</a>
      +
      +                <p><br />If you didn't ask to reset your password, you can ignore this message.</p>
      +                <br />
      +
      +                <p>Thanks
      +                <br />
      +                {{project}} team
      +                </p>
      +            </td>
      +        </tr>
      +    </table>
      +</div>
      +
      +</body>
      +
      +</html>
      +
      + +

      Localization

      + +

      + Each template can have multiple supported locales, displayed in different format and language. + This can be configured under the Template language selector of each template. +

      + +

      + You can send messages in different languages by setting the locale with client.setLocale() in the SDKs or the X-Appwrite-Locale HTTP header. View here the list of available locales +

      + +

      For example, you can send an email verification in French.

      +
        +
      • +

        Web

        +
        +
        import { Client, Account } from "appwrite";
        +
        +const client = new Client();
        +
        +const account = new Account(client);
        +
        +client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2')                 // Your project ID
        +    .setLocale('fr')                             // Your locale
        +;
        +
        +const promise = account.createVerification('https://example.com');
        +
        +promise.then(function (response) {
        +    console.log(response); // Success
        +}, function (error) {
        +    console.log(error); // Failure
        +});
        +
        +
      • +
      • +

        Flutter

        +
        +
        import 'package:appwrite/appwrite.dart';
        +
        +void main() { // Init SDK
        +  Client client = Client();
        +  Account account = Account(client);
        +
        +  client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2')                 // Your project ID
        +    .setLocale('fr')                             // Your locale
        +  ;
        +  Future result = account.createVerification('https://example.com');
        +
        +  result
        +    .then((response) {
        +      print(response);
        +    }).catchError((error) {
        +      print(error.response);
        +  });
        +}
        +
        +
      • +
      • +

        Android

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Account
        +
        +val client = Client(context)
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("5df5acd0d48c2")                 // Your project ID
        +    .setLocale('fr')                             // Your locale
        +
        +val account = Account(client)
        +
        +val response = account.createVerification('https://example.com')
        +
        +
      • +
      • +

        Apple

        +
        +
        import Appwrite
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("5df5acd0d48c2")                 // Your project ID
        +    .setLocale('fr')                             // Your locale
        +
        +let account = Account(client)
        +
        +let token = try await account.createVerification('https://example.com')
        +
        +
      • +
      \ No newline at end of file diff --git a/app/views/docs/email-delivery.phtml b/app/views/docs/email-delivery.phtml index ad8000572..1ad88c091 100644 --- a/app/views/docs/email-delivery.phtml +++ b/app/views/docs/email-delivery.phtml @@ -66,4 +66,4 @@ The next possible source of error is the configuration in your .env file. Make s
      docker compose up -d --build --force-recreate
      -

      Now you can head over to your Appwrite console, logout from your account and try to recover your password or send invites to other team members from your Appwrite console using your newly configured SMTP provider.

      +

      Now you can head over to your Appwrite Console, logout from your account and try to recover your password or send invites to other team members from your Appwrite Console using your newly configured SMTP provider.

      diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml new file mode 100644 index 000000000..934166ed4 --- /dev/null +++ b/app/views/docs/functions-deploy.phtml @@ -0,0 +1,216 @@ +

      + Appwrite Functions are mini-applications in Appwrite with their own endpoints. + Each function can have many deployments, which can be thought of as versions of the mini-application. +

      + +

      + Functions can be created and deployed in different ways to meet your unique development habits. + You can automatically deploy Appwrite Functions from source control, build your own deployment pipelines using the Appwrite CLI, or upload code files manually. + Here's everything you need to know to deploy your first Appwrite Function. +

      + +

      Git

      +

      + The recommended way to manage your Appwrite Function deployments is to use a version control system, like Git. + This offers simple versioning and collaboration that will easily fit into the rest of your development workflow. +

      + +

      Create Function

      +

      Before deploying your function with Git, create a new function attached to your Git repo.

      +
        +
      1. + Navigate to Functions from the side bar of the Appwrite Console. +
      2. +
      3. + Click Create function. +
      4. +
      5. + When asked to Choose your source, under Connect Git repository, select your provider. +
      6. +
      7. + Search for the Git repository that hold your function and click connect. +
      8. +
      9. + Select a production branch. New commits pushed to the production branch will be automatically activated. Commits to any other branch will still be deployed, but not be activated. +
      10. +
      11. + Input the root directory of the function inside the repository. If you have only one function in your repository, you can leave this empty. If you have multiple, root directory should point to the folder of your function. This should be the directory in which your custom build commands can run successfully. It also improves efficiency because only what's necessary is cloned. +
      12. +
      13. + If you don't want deploy comments to be made on your pull requests or commits, select Silent mode. +
      14. +
      15. + Name your function, select a runtime that matches your function, and enter entrypoint, relative to the root directory from the previous step. Entrypoint is path to the main file of your function, which exports the function to be run on every execution. +
      16. +
      17. + If you have build steps, like installing dependencies, input the commands into the Build settings heading's Command field. + You can combine multiple commands using &&, such as npm install && npm build. + For compiled languages you don't need to worry about installing dependencies, as that's done automatically during compilation step. +
      18. +
      19. + Finally, configure the execute permissions of the function. For security, only provide execute permissions to the necessary roles. +
      20. +
      + +

      Deploy

      +
        +
      1. + Using Git, checkout the branch you configured as production branch when creating the Appwrite Function. +
      2. +
      3. + Create a new commit. +
      4. +
      5. + Push your new commit. +
      6. +
      7. + A new deployment will be automatically created, built and activated. +
      8. +
      + +

      CLI

      +
      +

      CLI Setup

      +

      Before you can deploy with the Appwrite CLI, make sure you've installed and initialized the CLI.

      +
      +

      + To deploy with the Appwrite CLI, your function must be added to appwrite.json that tells the CLI where each function is stored. + To ensure the folder structure is setup correctly and appwrite.json is configured correctly, use the appwrite init function method to create a starter function, then paste in your function code. +

      + +

      + Run the following command in the folder holding the appwrite.json file. +

      +
      +
      appwrite init function
      +
      + +

      + Give your function a name and choose your runtime. + This will create a new starter function in the current directory and also add it to your appwrite.json file. +

      + +

      + Edit the automatically generated code and add dependencies to the dependency files of your language or framework. + Then, deploy the function using the following command. +

      + +
      +
      appwrite deploy function
      +
      + +
      +

      Overwrite Warning

      +

      + If you made changes in the Appwrite Console that is different from your appwrite.json, + using the CLI deploy command will overwrite your console changes, such as execution schedule or permissions. + Update your appwrite.json manually before deploying to avoid overwriting changes. +

      +
      + +

      Manual Deployment

      +

      You can upload your functions to be deployed using the Appwrite Console. The example below shows a simple Node.js function, but the same idea applies to any other language.

      +
      +
      .
      +├── package.json
      +└── index.js
      +
      +
      + +

      First, navigate inside the folder that contains your dependency file. Package your code files into the .tar.gz format with this tar command:

      + +
        +
      • +

        Unix

        + +
        +
        tar --exclude code.tar.gz -czf code.tar.gz .
        +
        +
      • +
      • +

        CMD

        + +
        +
        tar --exclude code.tar.gz -czf code.tar.gz .
        +
        +
      • +
      • +

        PowerShell

        + +
        +
        tar --exclude code.tar.gz -czf code.tar.gz .
        +
        +
      • +
      + +

      Next, navigate to your Appwrite Console and upload the function.

      + +
        +
      1. Navigate to the function you want to deploy.
      2. +
      3. Click Create deployment.
      4. +
      5. Select the Manual tab.
      6. +
      7. Input the entry point of your function under Entrypoint. For the example above, it would be index.js.
      8. +
      9. Upload code.tar.gz.
      10. +
      11. Select Activate deployment after build to use your new deployment.
      12. +
      13. Click Create to deploy your function.
      14. +
      + +

      Domains

      +

      + Each deployed function can have its own domain. + By default, one is generated for each of your functions. + You can find the generated domain for your function like this. +

      + +
        +
      1. Navigate to the Appwrite Console's Functions page.
      2. +
      3. Navigate to the Domains tab.
      4. +
      5. In the table, you'll find a link formatted similar to https://64d4d22db370ae41a32e.appwrite.global. This is your generated domain.
      6. +
      + +

      + You can also add a custom domain, which allows you to build custom REST APIs using nothing but Appwrite Functions. + To do this, you need to first buy and register a domain. + After obtaining a domain, follow these steps to add the domain to Appwrite. +

      + +
        +
      1. Navigate to the Appwrite Console's Functions page.
      2. +
      3. Navigate to the Domains tab.
      4. +
      5. Click on Create domain.
      6. +
      7. Input your domain in the Domain input field and click Next.
      8. +
      9. Copy the CNAME record provided to you, and add it to your domain registrar.
      10. +
      11. Click Go to console and wait for the domain name to be verified and certificate to generate.
      12. +
      + +

      + DNS records can take up to 48 hours to propagate after they're added. + Please retry verification over the next 48 hours. + If the domain verification still fails and you have confirmed DNS records are added correctly, please contact support. +

      + +

      Debugging Build

      +

      After deploying a function, you can find the status of the deployment and build logs in the Appwrite Console.

      +
        +
      1. In Appwrite Console, navigate to Functions.
      2. +
      3. Click to open a function you wish to inspect.
      4. +
      5. Under the Deployments tab, you'll find the status of the current active deployment and previous inactive deployments.
      6. +
      7. You can access build logs for the active deployment by clicking the Build logs button. You can click on an inactive function's three dots button to find their build logs.
      8. +
      + +

      Redeploy Builds

      +

      + After updating the configuration of your Appwrite Function, you need to redeploy your function for the changes to take effect. + You can also redeploy builds to retry failed builds. +

      +
        +
      1. In Appwrite Console, navigate to Functions.
      2. +
      3. Click to open a function you wish to inspect.
      4. +
      5. Under the Deployments tab, you'll find the status of the current active deployment.
      6. +
      7. You can redeploy by clicking the triple-dots beside an execution, and hitting the Redeploy button.
      8. +
      +

      + The redeployment behavior varies depending on how the initial deployment is created. + For Git deployments, redeploy uses the same commit hash but updated function settings. + For manual and CLI deployments, redeploy uses previously updated code but updated function settings. +

      \ No newline at end of file diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml new file mode 100644 index 000000000..39617c173 --- /dev/null +++ b/app/views/docs/functions-develop.phtml @@ -0,0 +1,2670 @@ +

      + Appwrite Functions offer a familiar interface if you've developed REST endpoints. + Each function is handled following a request and response pattern. +

      + +

      Lifecycle

      +

      + There is a clear lifecycle for all Appwrite Functions, from beginning to end. + Here's everything that happens during a function execution. +

      + +
        +
      1. The function is invoked.
      2. +
      3. Appwrite passes in request information like headers, body or path through the context.req object.
      4. +
      5. The runtime executes the code you defined, you can log through the context.log() or context.error() methods.
      6. +
      7. Function terminates when you return results using return context.res.send(), return context.res.json() or similar.
      8. +
      + +

      You'll find all of these steps in a simple function like this.

      + +
        +
      • +

        Node.js

        +
        +
        import { Client } from 'node-appwrite';
        +
        +// This is your Appwrite function
        +// It's executed each time we get a request
        +export default async ({ req, res, log, error }) => {
        +  // Why not try the Appwrite SDK?
        +  //
        +  // const client = new Client()
        +  //    .setEndpoint('https://cloud.appwrite.io/v1')
        +  //    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +  //    .setKey(process.env.APPWRITE_API_KEY);
        +
        +  // You can log messages to the console
        +  log('Hello, Logs!');
        +
        +  // If something goes wrong, log an error
        +  error('Hello, Errors!');
        +
        +  // The `req` object contains the request data
        +  if (req.method === 'GET') {
        +    // Send a response with the res object helpers
        +    // `res.send()` dispatches a string back to the client
        +    return res.send('Hello, World!');
        +  }
        +
        +  // `res.json()` is a handy helper for sending JSON
        +  return res.json({
        +    motto: 'Build Fast. Scale Big. All in One Place.',
        +    learn: 'https://appwrite.io/docs',
        +    connect: 'https://appwrite.io/discord',
        +    getInspired: 'https://builtwith.appwrite.io',
        +  });
        +};
        +
        +
      • +
      • +

        PHP

        +
        +
        require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +
        +// This is your Appwrite function
        +// It's executed each time we get a request
        +return function ($context) {
        +    // Why not try the Appwrite SDK?
        +    //
        +    // $client = new Client();
        +    // $client
        +    //     ->setEndpoint('https://cloud.appwrite.io/v1')
        +    //     ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
        +    //      ->setKey(getenv('APPWRITE_API_KEY'));
        +
        +    // You can log messages to the console
        +    $context->log('Hello, Logs!');
        +
        +    // If something goes wrong, log an error
        +    $context->error('Hello, Errors!');
        +
        +    // The `req` object contains the request data
        +    if ($context->req->method === 'GET') {
        +        // Send a response with the res object helpers
        +        // `res.send()` dispatches a string back to the client
        +        return $context->res->send('Hello, World!');
        +    }
        +
        +    // `res.json()` is a handy helper for sending JSON
        +    return $context->res->json([
        +        'motto' => 'Build Fast. Scale Big. All in One Place.',
        +        'learn' => 'https://appwrite.io/docs',
        +        'connect' => 'https://appwrite.io/discord',
        +        'getInspired' => 'https://builtwith.appwrite.io',
        +    ]);
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        from appwrite.client import Client
        +import os
        +
        +
        +# This is your Appwrite function
        +# It's executed each time we get a request
        +def main(context):
        +    # Why not try the Appwrite SDK?
        +    #
        +    # client = (
        +    #     Client()
        +    #         .set_endpoint("https://cloud.appwrite.io/v1")
        +    #         .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
        +    #         .set_key(os.environ["APPWRITE_API_KEY"])
        +    # )
        +
        +    # You can log messages to the console
        +    context.log("Hello, Logs!")
        +
        +    # If something goes wrong, log an error
        +    context.error("Hello, Errors!")
        +
        +    # The `context.req` object contains the request data
        +    if context.req.method == "GET":
        +        # Send a response with the res object helpers
        +        # `context.res.send()` dispatches a string back to the client
        +        return context.res.send("Hello, World!")
        +
        +    # `context.res.json()` is a handy helper for sending JSON
        +    return context.res.json({
        +        "motto": "Build Fast. Scale Big. All in One Place.",
        +        "learn": "https://appwrite.io/docs",
        +        "connect": "https://appwrite.io/discord",
        +        "getInspired": "https://builtwith.appwrite.io",
        +    })
        +
        +
      • +
      • +

        Ruby

        +
        +
        require "appwrite"
        +
        +# This is your Appwrite function
        +# It's executed each time we get a request
        +def main(context)
        +  # Why not try the Appwrite SDK?
        +  #
        +  # client = Appwrite::Client.new
        +  # client
        +  #   .set_endpoint('https://cloud.appwrite.io/v1')
        +  #   .set_project(ENV['APPWRITE_FUNCTION_PROJECT_ID'])
        +  #   .set_key(ENV['APPWRITE_API_KEY'])
        +
        +  # You can log messages to the console
        +  context.log("Hello, Logs!")
        +
        +  # If something goes wrong, log an error
        +  context.error("Hello, Errors!")
        +
        +  # The `context.req` object contains the request data
        +  if (context.req.method == "GET")
        +    # Send a response with the res object helpers
        +    # `context.res.send()` dispatches a string back to the client
        +    return context.res.send("Hello, World!")
        +  end
        +
        +  # `context.res.json()` is a handy helper for sending JSON
        +  return context.res.json({
        +    "motto": "Build Fast. Scale Big. All in One Place.",
        +    "learn": "https://appwrite.io/docs",
        +    "connect": "https://appwrite.io/discord",
        +    "getInspired": "https://builtwith.appwrite.io",
        +  })
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        import { Client } from "https://deno.land/x/appwrite@7.0.0/mod.ts";
        +
        +// This is your Appwrite function
        +// It's executed each time we get a request
        +export default ({ req, res, log, error }: any) => {
        +  // Why not try the Appwrite SDK?
        +  //
        +  // const client = new Client()
        +  //    .setEndpoint('https://cloud.appwrite.io/v1')
        +  //    .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID"))
        +  //    .setKey(Deno.env.get("APPWRITE_API_KEY"));
        +
        +  // You can log messages to the console
        +  log("Hello, Logs!");
        +
        +  // If something goes wrong, log an error
        +  error("Hello, Errors!");
        +
        +  // The `req` object contains the request data
        +  if (req.method === "GET") {
        +    // Send a response with the res object helpers
        +    // `res.send()` dispatches a string back to the client
        +    return res.send("Hello, World!");
        +  }
        +
        +  // `res.json()` is a handy helper for sending JSON
        +  return res.json({
        +    motto: "Build Fast. Scale Big. All in One Place.",
        +    learn: "https://appwrite.io/docs",
        +    connect: "https://appwrite.io/discord",
        +    getInspired: "https://builtwith.appwrite.io",
        +  });
        +};
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +// This is your Appwrite function
        +// It's executed each time we get a request
        +Future main(final context) async {
        +// Why not try the Appwrite SDK?
        +  //
        +  // final client = Client()
        +  //    .setEndpoint('https://cloud.appwrite.io/v1')
        +  //    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +  //    .setKey(process.env.APPWRITE_API_KEY);
        +
        +  // You can log messages to the console
        +  context.log('Hello, Logs!');
        +
        +  // If something goes wrong, log an error
        +  context.error('Hello, Errors!');
        +
        +  // The `req` object contains the request data
        +  if (context.req.method == 'GET') {
        +    // Send a response with the res object helpers
        +    // `res.send()` dispatches a string back to the client
        +    return context.res.send('Hello, World!');
        +  }
        +
        +  // `res.json()` is a handy helper for sending JSON
        +  return context.res.json({
        +    'motto': 'Build Fast. Scale Big. All in One Place.',
        +    'learn': 'https://appwrite.io/docs',
        +    'connect': 'https://appwrite.io/discord',
        +    'getInspired': 'https://builtwith.appwrite.io',
        +  });
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +import io.appwrite.Client
        +import java.util.HashMap
        +
        +class Main {
        +    // This is your Appwrite function
        +    // It's executed each time we get a request
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        // Why not try the Appwrite SDK?
        +        // val client = Client()
        +        //    .setEndpoint("https://cloud.appwrite.io/v1")
        +        //    .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +        //    .setKey(System.getenv("APPWRITE_API_KEY"))
        +
        +        // You can log messages to the console
        +        context.log("Hello, Logs!")
        +
        +        // If something goes wrong, log an error
        +        context.error("Hello, Errors!")
        +
        +        // The `context.req` object contains the request data
        +        if (context.req.method == "GET") {
        +            // Send a response with the res object helpers
        +            // `context.res.send()` dispatches a string back to the client
        +            return context.res.send("Hello, World!")
        +        }
        +
        +        // `context.res.json()` is a handy helper for sending JSON
        +        return context.res.json(mutableMapOf(
        +            "motto" to "Build Fast. Scale Big. All in One Place.",
        +            "learn" to "https://appwrite.io/docs",
        +            "connect" to "https://appwrite.io/discord",
        +            "getInspired" to "https://builtwith.appwrite.io"
        +        ))
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +import java.util.HashMap;
        +import io.appwrite.Client;
        +
        +public class Main {
        +
        +    // This is your Appwrite function
        +    // It's executed each time we get a request
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        // Why not try the Appwrite SDK?
        +        //
        +        // Client client = new Client()
        +        //     .setEndpoint("https://cloud.appwrite.io/v1")
        +        //     .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +        //     .setKey(System.getenv("APPWRITE_API_KEY"));
        +
        +        // You can log messages to the console
        +        context.log("Hello, Logs!");
        +
        +        // If something goes wrong, log an error
        +        context.error("Hello, Errors!");
        +
        +        // The `context.getReq()` object contains the request data
        +        if (context.getReq().getMethod().equals("GET")) {
        +            // Send a response with the res object helpers
        +            // `context.getRes().send()` dispatches a string back to the client
        +            return context.getRes().send("Hello, World!");
        +        }
        +
        +        Map json = new HashMap<>();
        +        json.put("motto", "Build Fast. Scale Big. All in One Place.");
        +        json.put("learn", "https://appwrite.io/docs");
        +        json.put("connect", "https://appwrite.io/discord");
        +        json.put("getInspired", "https://builtwith.appwrite.io");
        +
        +        // `context.getRes().json()` is a handy helper for sending JSON
        +        return context.getRes().json(json);
        +    }
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Appwrite
        +import AppwriteModels
        +import Foundation
        +
        +// This is your Appwrite function
        +// It's executed each time we get a request
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    // Why not try the Appwrite SDK?
        +    //
        +    // let client = Client()
        +    //    .setEndpoint("https://cloud.appwrite.io/v1")
        +    //    .setProject(ProcessInfo.processInfo.environment["APPWRITE_FUNCTION_PROJECT_ID"])
        +    //    .setKey(ProcessInfo.processInfo.environment["APPWRITE_API_KEY"]);
        +
        +    // You can log messages to the console
        +    context.log("Hello, Logs!")
        +
        +    // If something goes wrong, log an error
        +    context.error("Hello, Errors!")
        +
        +    // The `context.req` object contains the request data
        +    if context.req.method == "GET" {
        +        // Send a response with the res object helpers
        +        // `res.send()` dispatches a string back to the client
        +        return context.res.send("Hello, World!")
        +    }
        +
        +    // `context.res.json()` is a handy helper for sending JSON
        +    return try context.res.json([
        +        "motto": "Build Fast. Scale Big. All in One Place.",
        +        "learn": "https://appwrite.io/docs",
        +        "connect": "https://appwrite.io/discord",
        +        "getInspired": "https://builtwith.appwrite.io",
        +    ])
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        namespace DotNetRuntime;
        +
        +using Appwrite;
        +using Appwrite.Services;
        +using Appwrite.Models;
        +
        +public class Handler {
        +
        +    // This is your Appwrite function
        +    // It"s executed each time we get a request
        +    public async Task Main(RuntimeContext Context) 
        +    {
        +        // Why not try the Appwrite SDK?
        +        //
        +        // var client = new Client()
        +        //     .SetEndpoint("https://cloud.appwrite.io/v1")  
        +        //     .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))        
        +        //     .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
        +
        +        // You can log messages to the console
        +        Context.Log("Hello, Logs!");
        +
        +        // If something goes wrong, log an error
        +        Context.Error("Hello, Errors!");
        +
        +        // The `Context.Req` object contains the request data
        +        if (Context.Req.Method == "GET") {
        +            // Send a response with the res object helpers
        +            // `Context.Res.Send()` dispatches a string back to the client
        +            return Context.Res.Send("Hello, World!");
        +        }
        +
        +        // `Context.Res.Json()` is a handy helper for sending JSON
        +        return Context.Res.Json(new Dictionary()
        +        {
        +            { "motto", "Build Fast. Scale Big. All in One Place." },
        +            { "learn", "https://appwrite.io/docs" },
        +            { "connect", "https://appwrite.io/discord" },
        +            { "getInspired", "https://builtwith.appwrite.io" },
        +        });
        +    }
        +}
        +
        +
      • +
      + +

      If you prefer to learn through more examples like this, explore the examples page.

      + +

      The Context Object

      +

      + Context is an object passed into every function to handle communication to both the end users, and logging to the Appwrite Console. + All input, output, and logging must be handled through the context object passed in. +

      + +

      You'll find these properties in the context object.

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      PropertyDescription
      reqContains request information like method, body, and headers. See full examples here.
      resContains methods to build a response and return information. See full examples here.
      log()Method to log information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
      error()Methoc to log errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
      + +

      Destructuring Assignment

      +

      + Some languages, namely JavaScript, support destructuring. You'll see us use destructuring in examples, which has the following syntax. + Learn more about destructuring assignment. +

      +
        +
      • +

        Node.js

        +
        +
        // before destructuring
        +export default async function (context) {
        +    context.log("This is a log!");
        +    return context.res.send("This is a response!");
        +}
        +
        +// after destructuring
        +export default async function ({ req, res, log, error }) {
        +    log("This is a log!");
        +    return res.send("This is a response!");
        +}
        +
        +
      • +
      • +

        Deno

        +
        +
        // before destructuring
        +export default async function (context: any) {
        +    context.log("This is a log!");
        +    return context.res.send("This is a response!");
        +}
        +   
        +// after destructuring
        +export default async function ({ req, res, log, error }: any) {
        +    log("This is a log!");
        +    return res.send("This is a response!");
        +}
        +
        +
      • +
      + +

      Request

      +

      + If you pass data into an Appwrite Function, it'll be found in the request object. + This includes all invocation inputs from Appwrite SDKs, HTTP calls, Appwrite events, or browsers visiting the configured domain. + Explore the request object with the following function, which logs all request params to the Appwrite Console. +

      + +
        +
      • +

        Node.js

        +
        +
        export default async ({ req, res, log }) => {
        +    log(req.bodyRaw);                     // Raw request body, contains request data
        +    log(JSON.stringify(req.body));        // Object from parsed JSON request body, otherwise string
        +    log(JSON.stringify(req.headers));     // String key-value pairs of all request headers, keys are lowercase
        +    log(req.scheme);                      // Value of the x-forwarded-proto header, usually http or https
        +    log(req.method);                      // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    log(req.url);                         // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    log(req.host);                        // Hostname from the host header, such as awesome.appwrite.io
        +    log(req.port);                        // Port from the host header, for example 8000
        +    log(req.path);                        // Path part of URL, for example /v1/hooks
        +    log(req.queryString);                 // Raw query params string. For example "limit=12&offset=50"
        +    log(JSON.stringify(req.query));       // Parsed query params. For example, req.query.limit
        +
        +    return res.send("All the request parameters are logged to the Appwrite Console.");
        +};
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +return function ($context) {
        +    $context->log($context->req->bodyRaw);              // Raw request body, contains request data
        +    $context->log(json_encode($context->req->body));    // Object from parsed JSON request body, otherwise string
        +    $context->log(json_encode($context->req->headers)); // String key-value pairs of all request headers, keys are lowercase
        +    $context->log($context->req->scheme);               // Value of the x-forwarded-proto header, usually http or https
        +    $context->log($context->req->method);               // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    $context->log($context->req->url);                  // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    $context->log($context->req->host);                 // Hostname from the host header, such as awesome.appwrite.io
        +    $context->log($context->req->port);                 // Port from the host header, for example 8000
        +    $context->log($context->req->path);                 // Path part of URL, for example /v1/hooks
        +    $context->log($context->req->queryString);          // Raw query params string. For example "limit=12&offset=50"
        +    $context->log(json_encode($context->req->query));   // Parsed query params. For example, req.query.limit
        +
        +    return $context->res->send("All the request parameters are logged to the Appwrite Console.");
        +}
        +
        +
      • +
      • +

        Python

        +
        +
        import json
        +
        +def main(context):
        +    context.log(context.req.bodyRaw)             # Raw request body, contains request data
        +    context.log(json.dumps(context.req.body))    # Object from parsed JSON request body, otherwise string
        +    context.log(json.dumps(context.req.headers)) # String key-value pairs of all request headers, keys are lowercase
        +    context.log(context.req.scheme)              # Value of the x-forwarded-proto header, usually http or https
        +    context.log(context.req.method)              # Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    context.log(context.req.url)                 # Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    context.log(context.req.host)                # Hostname from the host header, such as awesome.appwrite.io
        +    context.log(context.req.port)                # Port from the host header, for example 8000
        +    context.log(context.req.path)                # Path part of URL, for example /v1/hooks
        +    context.log(context.req.queryString)         # Raw query params string. For example "limit=12&offset=50"
        +    context.log(json.dumps(context.req.query))   # Parsed query params. For example, req.query.limit
        +
        +    return context.res.send("All the request parameters are logged to the Appwrite Console.")
        +
        +
      • +
      • +

        Ruby

        +
        +
        require 'json'
        +                
        +def main(context)
        +    context.log(context.req.bodyRaw)                #  Raw request body, contains request data
        +    context.log(JSON.generate(context.req.body))    # Object from parsed JSON request body, otherwise string
        +    context.log(JSON.generate(context.req.headers)) # String key-value pairs of all request headers, keys are lowercase
        +    context.log(context.req.scheme)                 # Value of the x-forwarded-proto header, usually http or https
        +    context.log(context.req.method)                 # Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    context.log(context.req.url)                    # Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    context.log(context.req.host)                   # Hostname from the host header, such as awesome.appwrite.io
        +    context.log(context.req.port)                   # Port from the host header, for example 8000
        +    context.log(context.req.path)                   # Path part of URL, for example /v1/hooks
        +    context.log(context.req.queryString)            # Raw query params string. For example "limit=12&offset=50"
        +    context.log(JSON.generate(context.req.query))   # Parsed query params. For example, req.query.limit
        +
        +    return context.res.send("All the request parameters are logged to the Appwrite Console.")
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        export default async ({ req, res, log }: any) => {
        +    log(req.bodyRaw);                 // Raw request body, contains request data
        +    log(JSON.stringify(req.body));    // Object from parsed JSON request body, otherwise string
        +    log(JSON.stringify(req.headers)); // String key-value pairs of all request headers, keys are lowercase
        +    log(req.scheme);                  // Value of the x-forwarded-proto header, usually http or https
        +    log(req.method);                  // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    log(req.url);                     // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    log(req.host);                    // Hostname from the host header, such as awesome.appwrite.io
        +    log(req.port);                    // Port from the host header, for example 8000
        +    log(req.path);                    // Path part of URL, for example /v1/hooks
        +    log(req.queryString);             // Raw query params string. For example "limit=12&offset=50"
        +    log(JSON.stringify(req.query));   // Parsed query params. For example, req.query.limit
        +
        +    return res.send("All the request parameters are logged to the Appwrite Console.");
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +import 'dart:convert';
        +
        +Future<dynamic> main(final context) async {
        +    context.log(context.req.bodyRaw);              // Raw request body, contains request data
        +    context.log(json.encode(context.req.body));    // Object from parsed JSON request body, otherwise string
        +    context.log(json.encode(context.req.headers)); // String key-value pairs of all request headers, keys are lowercase
        +    context.log(context.req.scheme);               // Value of the x-forwarded-proto header, usually http or https
        +    context.log(context.req.method);               // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    context.log(context.req.url);                  // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +    context.log(context.req.host);                 // Hostname from the host header, such as awesome.appwrite.io
        +    context.log(context.req.port);                 // Port from the host header, for example 8000
        +    context.log(context.req.path);                 // Path part of URL, for example /v1/hooks
        +    context.log(context.req.queryString);          // Raw query params string. For example "limit=12&offset=50"
        +    context.log(json.encode(context.req.query));   // Parsed query params. For example, req.query.limit
        +
        +    return context.res.send("All the request parameters are logged to the Appwrite Console.");
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Foundation
        +import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    context.log(context.req.bodyRaw)                                                     // Raw request body, contains request data
        +    context.log(NSJSONSerialization.jsonObject(with: context.req.body, options: [])!)    // Object from parsed JSON request body, otherwise string
        +    context.log(NSJSONSerialization.jsonObject(with: context.req.headers, options: [])!) // String key-value pairs of all request headers, keys are lowercase
        +    context.log(context.req.scheme)                                                      // Value of the x-forwarded-proto header, usually http or https
        +    context.log(context.req.method)                                                      // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +    context.log(context.req.url)                                                         // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50 
        +    context.log(context.req.host)                                                        // Hostname from the host header, such as awesome.appwrite.io
        +    context.log(context.req.port)                                                        // Port from the host header, for example 8000
        +    context.log(context.req.path)                                                        // Path part of URL, for example /v1/hooks
        +    context.log(context.req.queryString)                                                 // Raw query params string. For example "limit=12&offset=50"
        +    context.log(NSJSONSerialization.jsonObject(with: context.req.query, options: [])!)   // Parsed query params. For example, req.query.limit
        +
        +    return context.res.send("All the request parameters are logged to the Appwrite Console.")
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        namespace DotNetRuntime;
        +
        +using System.Text.Json;
        +
        +public class Handler {
        +    public async Task<RuntimeOutput> Main(RuntimeContext Context) 
        +    {
        +        Context.Log(Context.Req.BodyRaw);                                                     // Raw request body, contains request data
        +        Context.Log(JsonSerializer.Serialize<object>(Context.Req.Body));                 // Object from parsed JSON request body, otherwise string
        +        Context.Log(JsonSerializer.Serialize<object>(Context.Req.Headers));              // String key-value pairs of all request headers, keys are lowercase
        +        Context.Log(Context.Req.Scheme);                                                      // Value of the x-forwarded-proto header, usually http or https
        +        Context.Log(Context.Req.Method);                                                      // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +        Context.Log(Context.Req.Url);                                                         // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +        Context.Log(Context.Req.Host);                                                        // Hostname from the host header, such as awesome.appwrite.io
        +        Context.Log(Context.Req.Port);                                                        // Port from the host header, for example 8000
        +        Context.Log(Context.Req.Path);                                                        // Path part of URL, for example /v1/hooks
        +        Context.Log(Context.Req.QueryString);                                                 // Raw query params string. For example "limit=12&offset=50"
        +        Context.Log(JsonSerializer.Serialize<object>(Context.Req.Query));                // Parsed query params. For example, req.query.limit
        +
        +        return Context.Res.Send("All the request parameters are logged to the Appwrite Console.");
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +import com.google.gson.Gson
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        val gson = Gson()
        +
        +        context.log(context.req.bodyRaw)                // Raw request body, contains request data
        +        context.log(gson.toString(context.req.body))    // Object from parsed JSON request body, otherwise string
        +        context.log(gson.toString(context.req.headers)) // String key-value pairs of all request headers, keys are lowercase
        +        context.log(context.req.scheme)                 // Value of the x-forwarded-proto header, usually http or https
        +        context.log(context.req.method)                 // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +        context.log(context.req.url)                    // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +        context.log(context.req.host)                   // Hostname from the host header, such as awesome.appwrite.io
        +        context.log(context.req.port)                   // Port from the host header, for example 8000
        +        context.log(context.req.path)                   // Path part of URL, for example /v1/hooks
        +        context.log(context.req.queryString)            // Raw query params string. For example "limit=12&offset=50"
        +        context.log(gson.toString(context.req.query))   // Parsed query params. For example, req.query.limit
        +
        +        return context.res.send("All the request parameters are logged to the Appwrite Console.")
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java;
        +
        +import com.google.gson.Gson;
        +import io.openruntimes.java.models.RuntimeContext;
        +import io.openruntimes.java.models.RuntimeOutput;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) {
        +        Gson gson = new Gson();
        +
        +        context.log(context.getReq().getBodyRaw());                // Raw request body, contains request data
        +        context.log(gson.toString(context.getReq().getBody()));    // Object from parsed JSON request body, otherwise string
        +        context.log(gson.toString(context.getReq().getHeaders())); // String key-value pairs of all request headers, keys are lowercase
        +        context.log(context.getReq().getScheme());                 // Value of the x-forwarded-proto header, usually http or https
        +        context.log(context.getReq().getMethod());                 // Request method, such as GET, POST, PUT, DELETE, PATCH, etc.
        +        context.log(context.getReq().getUrl());                    // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50
        +        context.log(context.getReq().getHost());                   // Hostname from the host header, such as awesome.appwrite.io
        +        context.log(context.getReq().getPort());                   // Port from the host header, for example 8000
        +        context.log(context.getReq().getPath());                   // Path part of URL, for example /v1/hooks
        +        context.log(context.getReq().getQueryString());            // Raw query params string. For example "limit=12&offset=50"
        +        context.log(gson.toString(context.getReq().getQuery()));   // Parsed query params. For example, req.query.limit
        +
        +        return context.getRes().send("All the request parameters are logged to the Appwrite Console.");
        +    }
        +}
        +
        +
      • +
      + +

      Headers

      +

      + Appwrite Functions will always receive a set of headers that provide meta data about the function execution. + These are provided alongside any custom headers sent to the function. +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      VariableDescription
      x-appwrite-trigger + Describes how the function execution was invoked. + Possible values are http, schedule or event. +
      x-appwrite-event + If the function execution was triggered by an event, describes the triggering event. +
      x-appwrite-user-id + If the function execution was invoked by an authenticated user, display the user ID. + This doesn't apply to Appwrite Console users or API keys. +
      x-appwrite-user-jwt + JWT token generated from the invoking user's session. Used to authenticate Server SDKs to respect access permissions. + Learn more about JWT tokens. +
      x-appwrite-country-code + Displays the country code of the configured locale. +
      x-appwrite-continent-code + Displays the continent code of the configured locale. +
      x-appwrite-continent-eu + Describes if the configured local is within the EU. +
      + + +

      Response

      +

      + If you need to send a response to the invoker of the function, such as a user, client app, or an integration, use the response object. + The response information will not be logged to the Appwrite Console. + There are several possible ways to send a response, explore them in the following Appwrite Function. +

      + +
        +
      • +

        Node.js

        +
        +
        export default async ({ req, res, log }) => {
        +
        +    switch (req.query.type) {
        +        case 'empty': 
        +            return res.empty();
        +        case 'json':
        +            return res.json({"type": "This is a JSON response"});
        +        case 'redirect':
        +            return res.redirect("https://appwrite.io", 301);
        +        case 'html':
        +            return res.send(
        +                "<h1>This is an HTML response</h1>", 200, {
        +                    "content-type": "text/html"
        +                });
        +        default:
        +            return res.send("This is a text response");
        +    }
        +}
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +
        +return function ($context) {
        +    switch ($context->req->query['type']) {
        +        case 'empty':
        +            return $context->res->empty();
        +        case 'json':
        +            return $context->res->json(["type" => "This is a JSON response"]);
        +        case 'redirect':
        +            return $context->res->redirect("https://appwrite.io", 301);
        +        case 'html':
        +            return $context->res->send("<h1>This is an HTML response</h1>", 200, [
        +                "content-type" => "text/html"
        +                ]);
        +        default:
        +            return $context->res->send("This is a text response");
        +    }
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        def main(context):
        +    type = context.req.query['type']
        +
        +    if type == 'empty':
        +        return context.res.empty()
        +    elif type =='json':
        +        return context.res.json({"type": "This is a JSON response"})
        +    elif type == 'redirect':
        +        return context.res.redirect("https://appwrite.io", 301)
        +    elif type == 'html':
        +        return context.res.send("<h1>This is an HTML response</h1>", 200, {
        +            "content-type": "text/html"
        +        })
        +    else:
        +        return context.res.send("This is a text response")
        +
        +
      • +
      • +

        Ruby

        +
        +
        def main(context)
        +    case context.req.query['type'] 
        +        when 'empty'
        +            return context.res.empty()
        +        when 'json'
        +            return context.res.json({"type": "This is a JSON response"})
        +        when 'redirect'
        +            return context.res.redirect("https://appwrite.io", 301)
        +        when 'html'
        +            return context.res.send("<h1>This is an HTML response</h1>", 200, {
        +                "content-type": "text/html"
        +            })
        +        else
        +            return context.res.send("This is a text response")
        +    end
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        export default async ({ req, res, log }) => {
        +
        +    switch (req.query.type) {
        +        case 'empty':
        +            return res.empty();
        +        case 'json':
        +            return res.json({type": "This is a JSON response"});
        +        case 'redirect':
        +            return res.redirect("https://appwrite.io", 301);
        +        case 'html':
        +            return res.send(
        +                "<h1>This is an HTML response</h1>", 200, {
        +                    "content-type": "text/html"
        +                });
        +        default:
        +            return res.send("This is a text response");
        +    }
        +}
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +
        +Future<dynamic> main(final context) async {
        +    switch (context.req.query['type']) {
        +        case 'empty':
        +            return context.res.empty();
        +        case 'json':
        +            return context.res.json({'type': 'This is a JSON response'});
        +        case 'redirect':
        +            return context.res.redirect('https://appwrite.io', 301);
        +        case 'html':
        +            return context.res.send('<h1>This is an HTML response</h1>',
        +                200, {'content-type': 'text/html'});
        +        default:
        +            return context.res.send('This is a text response');
        +  }
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    switch context.req.query["type"] {
        +    case "empty":
        +        return context.res.empty()
        +    case "json":
        +        return context.res.send(["type": "This is a JSON response"])
        +    case "redirect":
        +        return context.res.redirect("https://appwrite.io", 301)
        +    case "html":
        +        return context.res.send("<h1>This is an HTML response</h1>", 200, [
        +            "content-type": "text/html"
        +            ])
        +    default:
        +        return context.res.send("This is a text response")
        +    }
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        public class Handler {
        +    public async Task<RuntimeOutput> Main(RuntimeContext Context) 
        +    {
        +        switch (Context.Request.Query["type"])
        +        {
        +            case "empty":
        +                return Context.Res.Empty();
        +            case "json":
        +                return Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } });
        +            case "redirect":
        +                return Context.Res.Redirect("https://appwrite.io", 301);
        +            case "html":
        +                return Context.Res.Send("<h1>This is an HTML response</h1>", 200, new Dictionary<string, string>() {
        +                    { "content-type", "text/html" } 
        +                });
        +            default:
        +                return Context.Res.Send("This is a text response");
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        when (context.req.query["type"]) {
        +            "empty" -> return context.res.empty()
        +            "json" -> return context.res.send(mapOf("type" to "This is a JSON response"))
        +            "redirect" -> return context.res.redirect("https://appwrite.io", 301)
        +            "html" -> return context.res.send("<h1>This is an HTML response</h1>", 200, mapOf("content-type" to "text/html"))
        +            else -> return context.res.send("This is a text response")
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +import java.util.Map;
        +import java.util.HashMap;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        switch (context.getReq().getQuery()["type"]) {
        +            case "text":
        +                return context.getRes().empty();
        +            case "json":
        +                HashMap<String, Object> data = new HashMap<>();
        +                data.put("type", "This is a JSON response");
        +                return context.getRes().send(data);
        +            case "redirect":
        +                return context.getRes().redirect("https://appwrite.io", 301);
        +            case "html":
        +                return context.getRes().send("<h1>This is an HTML response</h1>", 200, Map.of("content-type", "text/html"));
        +            default:
        +                return context.getRes().send("This is a text response");
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        C++

        +
        +
        #include "../RuntimeResponse.h"
        +#include "../RuntimeRequest.h"
        +#include "../RuntimeOutput.h"
        +#include "../RuntimeContext.h"
        +
        +namespace runtime {
        +  class Handler {
        +    public:
        +      static RuntimeOutput main(RuntimeContext &context) {
        +        std::string type = context.req.query["type"];
        +
        +        if (type == "empty") {
        +          return context.res.empty();
        +        } else if (type == "json") {
        +          Json::Value data;
        +          data["type"] = "This is a JSON response";
        +          return context.res.send(data);
        +        } else if (type == "redirect") {
        +          return context.res.redirect("https://appwrite.io", 301);
        +        } else if (type == "html") {
        +          Json::Value headers;
        +          headers["content-type"] = "text/html";
        +          return context.res.send("<h1>This is an HTML response</h1>", 200, headers);
        +        } else {
        +          return context.res.send("This is a text response");
        +        }
        +      }
        +  };
        +}
        +
        +
      • +
      + +

      + To get the different response types, set one of the following query parameters in the generated domain of your function. +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeQuery ParamExample
      text/?type=texthttps://64d4d22db370ae41a32e.appwrite.global/?type=text
      json/?type=jsonhttps://64d4d22db370ae41a32e.appwrite.global/?type=json
      redirect/?type=redirecthttps://64d4d22db370ae41a32e.appwrite.global/?type=redirect
      html/?type=htmlhttps://64d4d22db370ae41a32e.appwrite.global/?type=html
      empty/https://64d4d22db370ae41a32e.appwrite.global/
      + +

      Logging

      +

      + To protect user privacy, the request and response objects are not logged to the Appwrite Console by default. + This means, to see logs or debug function executions you need to use the log() and error() methods. + These logs are only visible to developers with access to the Appwrite Console. +

      + +

      Here's an example of using logs and errors.

      +
        +
      • +

        Node.js

        +
        +
        export default async ({ req, res, log, error }) => {
        +    log("This is a log, use for logging information to console");
        +    log(`This function was called with ${req.method} method`);
        +    error("This is an error, use for logging errors to console");
        +
        +    return res.send("Check the Appwrite Console to see logs and errors!");
        +};
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +
        +return function ($context) {
        +    $context->log("This is a log, use for logging information to console");
        +    $context->log("This function was called with " . $context->req->method . " method");
        +    $context->error("This is an error, use for logging errors to console");
        +
        +    return $context->send("Check the Appwrite Console to see logs and errors!");
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        def main(context):
        +    context.log("This is a log, use for logging information to console")
        +    context.log(f"This function was called with {context.req.method} method")
        +    context.error("This is an error, use for logging errors to console")
        +
        +    return context.res.send("Check the Appwrite Console to see logs and errors!")
        +
        +
      • +
      • +

        Ruby

        +
        +
        def main(context)
        +    context.log("This is a log, use for logging information to console")
        +    context.log("This function was called with #{context.req.method} method")
        +    context.error("This is an error, use for logging errors to console")
        +
        +    return context.res.send("Check the Appwrite Console to see logs and errors!")
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        export default async ({ res, log, error }: any) => {
        +    log("This is a log, use for logging information to console");
        +    log(`This function was called with ${context.req.method} method`);
        +    error("This is an error, use for logging errors to console");
        +
        +    return res.send("Check the Appwrite Console to see logs and errors!");
        +};
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +
        +Future<dynamic> main(final context) async {
        +    context.log("This is a log, use for logging information to console");
        +    context.log("This function was called with ${context.req.method} method");
        +    context.error("This is an error, use for logging errors to console");
        +
        +    return context.res.send("Check the Appwrite Console to see logs and errors!");
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    context.log("This is a log, use for logging information to console")
        +    context.log("This function was called with \(context.req.method) method")
        +    context.error("This is an error, use for logging errors to console")
        +
        +    return context.res.send("Check the Appwrite Console to see logs and errors!")
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        namespace DotNetRuntime;
        +
        +public class Handler {
        +    public async Task<RuntimeOutput> Main(RuntimeContext Context) 
        +    {
        +        Context.Log("This is a log, use for logging information to console");
        +        Context.Log($"This function was called with {Context.Req.Method} method");
        +        Context.Error("This is an error, use for logging errors to console");
        +
        +        return Context.Res.Send("Check the Appwrite Console to see logs and errors!");
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        context.log("This is a log, use for logging information to console")
        +        context.log("This function was called with ${context.req.method} method")
        +        context.error("This is an error, use for logging errors to console")
        +
        +        return context.res.send("Check the Appwrite Console to see logs and errors!")
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        context.log("This is a log, use for logging information to console");
        +        context.log("This function was called with " + context.req.method + " method");
        +        context.error("This is an error, use for logging errors to console");
        +
        +        return context.getRes().send("Check the Appwrite Console to see logs and errors!");
        +    }
        +}
        +
        +
      • +
      • +

        C++

        +
        +
        #include "../RuntimeResponse.h"
        +#include "../RuntimeRequest.h"
        +#include "../RuntimeOutput.h"
        +#include "../RuntimeContext.h"
        +
        +namespace runtime {
        +  class Handler {
        +    public:
        +      static RuntimeOutput main(RuntimeContext &context) {
        +        context.log("This is a log, use for logging information to console");
        +        context.log("This function was called with " + context.req.method + " method");
        +        context.error("This is an error, use for logging errors to console");
        +
        +        return context.res.send("Check the Appwrite Console to see logs and errors!");
        +      }
        +  };
        +}
        +
        +
      • +
      +

      You can access these logs through the following steps.

      +
        +
      1. In Appwrite Console, navigate to Functions.
      2. +
      3. Click to open a function you wish to inspect.
      4. +
      5. Under the Executions tab, click on an execution.
      6. +
      7. In the Response section, you'll be able to view logs under the Logs and Errors tabs.
      8. +
      + +

      Accessing Environment Variables

      +

      + If you need to pass constants or secrets to Appwrite Functions, you can use environment variables. + Environmental variables can be global, or function-specific. +

      + +

      Default Environment Variables

      +

      + Appwrite runtimes passes in some environment variables by default. + These are always accessible for every function at runtime. +

      + +
      +

      Appwrite API keys

      +

      + If your function is using an Appwrite SDK with an API key, this API key needs to be generated and passed in manually. + API keys are not passed by default for security reasons. +

      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      VariableDescription
      APPWRITE_FUNCTION_ID + The ID of the running function. +
      APPWRITE_FUNCTION_NAME + The Name of the running function. +
      APPWRITE_FUNCTION_DEPLOYMENT + The deployment ID of the running function. +
      APPWRITE_FUNCTION_PROJECT_ID + The project ID of the running function. +
      APPWRITE_FUNCTION_RUNTIME_NAME + The runtime of the running function. +
      APPWRITE_FUNCTION_RUNTIME_VERSION + The runtime version of the running function. +
      + +

      Function-level Environment Variables

      +

      + Function-level environment variables will only be accessible in the function they belong to. + Function-level environment variables will override project-level variables when they have conflicting names. +

      +
        +
      1. In Appwrite Console, navigate to Functions.
      2. +
      3. Click to open a function you wish to add variables to.
      4. +
      5. Under the Settings tab, navigate to Environment variables.
      6. +
      7. Create an environment variable by clicking Create variable, using the Editor, or import new variables through a .env file.
      8. +
      + +

      Project-level Variables

      +

      + Project-level variables are accessible to all Appwrite Functions in your project. + Function-level environment variables will override project-level variables when they have conflicting names. +

      +
        +
      1. In the Appwrite Console, navigate to your project's Settings page.
      2. +
      3. Navigate to Global variables section.
      4. +
      5. Create an environment variable by clicking Create variable, using the Editor, or import new variables through a .env file.
      6. +
      + +

      + You can access the environment variables through the systems library of each language. +

      + +
        +
      • +

        Node.js

        +
        +
        export default async ({ req, res, log }) => {
        +    return res.send(process.env.MY_VAR);
        +}
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +
        +return function ($context) {
        +    return $context->res->send(getenv('MY_VAR'));
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        def main(context):
        +    return context.res.send(os.environ['MY_VAR'])
        +
        +
      • +
      • +

        Ruby

        +
        +
        def main(context)
        +    return context.res.send(ENV['MY_VAR'])
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        export default async ({ req, res, log }) => {
        +    return res.send(Deno.env.get('MY_VAR'));
        +}
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +
        +Future<dynamic> main(final context) async {
        +    return context.res.send(Platform.environment['MY_VAR']);
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    return context.res.send(ProcessInfo.processInfo.environment["MY_VAR"])
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        namespace DotNetRuntime;
        +
        +public class Handler {
        +    public async Task<RuntimeOutput> Main(RuntimeContext Context) 
        +    {
        +        return Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR"));
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        return context.res.send(System.getenv("MY_VAR"))
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        return context.getRes().send(System.getenv("MY_VAR"));
        +    }
        +}
        +
        +
      • +
      • +

        C++

        +
        +
        #include "../RuntimeResponse.h"
        +#include "../RuntimeRequest.h"
        +#include "../RuntimeOutput.h"
        +#include "../RuntimeContext.h"
        +
        +namespace runtime {
        +  class Handler {
        +    public:
        +      static RuntimeOutput main(RuntimeContext &context) {
        +
        +      return context.res.send(std::getenv("MY_VAR"));
        +  };
        +}
        +
        +
      • +
      + +

      Dependencies

      + +

      + Your function's dependencies should be managed by the package manager of each language. By default, we include the following package managers in each runtime: +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      LanguagePackage ManagerCommands
      + Node icon + Node.jsnpmnpm install
      + PHP icon + PHPComposercomposer install
      + Python icon + Pythonpippip install -r requirements.txt
      + Ruby icon + RubyBundlerbundle install
      + Deno icon + Denodenodeno cache <ENTRYPOINT_FILE>
      + Dart icon + Dartpubpub get
      + Swift icon + SwiftSwift Package Managerswift package resolve
      + Swift icon + .NETNuGetdotnet restore
      + Swift icon + KotlinGradleN/A
      + Swift icon + JavaGradleN/A
      + C++ icon + C++NoneN/A
      + +

      + To install your dependencies before your function is built, you should add the relevant install command to the top your function's Build setting > Commands. +

      + +

      Using Appwrite in a Function

      + +

      + Appwrite can be used in your functions by adding the relevant SDK to your function's dependencies. + Authenticating with Appwrite is done via an API key or a JWT token. + API keys must be generated and exported as an environment variable. +

      +

      + You can read more about authentication in the Server Authentication section of the docs. +

      + + +

      Using with API Key

      +

      + API keys have defined scopes when you create them. + They ignore permissions and operate without a sessions. + Use API keys if the function should act as an admin type role, instead of acting on behalf of a user. + Pass in your API key as an environment variable. Never share API keys with users. +

      +
        +
      • +

        Node.js

        +
        +
        import { Client, Databases, ID } from 'node-appwrite';
        +
        +export default async ({ req, res, log, error }) => {
        +
        +    const client = new Client()
        +        .setEndpoint('https://cloud.appwrite.io/v1')
        +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +        .setKey(process.env.APPWRITE_API_KEY);
        +
        +    const databases = new Databases(client);
        +
        +    try {
        +        await databases.createDocument(
        +            '[DATABASE_ID]',
        +            '[COLLECTION_ID]',
        +            ID.unique(),
        +            {}
        +        )
        +    } catch (e) {
        +        error("Failed to create document: " + e.message)
        +        return res.send("Failed to create document")
        +    }
        +
        +    return res.send("Document created")
        +}
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +
        +require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +use Appwrite\Services\Databases;
        +use Appwrite\ID;
        +
        +return function ($context) {
        +    $client = (new Client())
        +        ->setEndpoint('https://cloud.appwrite.io/v1')
        +        ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
        +        ->setKey(getenv('APPWRITE_API_KEY'));
        +    
        +    $databases = new Databases($client);
        +
        +    try {
        +        $databases->createDocument(
        +            databaseId: '[DATABASE_ID]',
        +            collectionId: '[COLLECTION_ID]',
        +            documentId: ID::unique(),
        +            data: []
        +        );
        +    } catch (Exception $e) {
        +        $context->error("Failed to create document: " . $e->getMessage());
        +        return $context->res->send("Failed to create document");
        +    }
        +
        +    return $context->res->send("Document created");
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        from appwrite.client import Client
        +from appwrite.services.databases import Databases
        +from appwrite.id import ID
        +
        +import os
        +
        +def main(context):
        +    client = (
        +        Client()
        +            .set_endpoint("https://cloud.appwrite.io/v1")
        +            .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
        +            .set_key(os.environ["APPWRITE_API_KEY"])
        +    )
        +
        +    databases = Databases(client)
        +
        +    try:
        +        databases.create_document(
        +            database_id="[DATABASE_ID]",
        +            collection_id="[COLLECTION_ID]",
        +            document_id=ID.unique(),
        +            data={}
        +        )
        +    except Exception as e:
        +        context.error("Failed to create document: " + e.message)
        +        return context.response.send("Failed to create document")
        +
        +    return context.response.send("Document created")
        +
        +
      • +
      • +

        Ruby

        +
        +
        require "appwrite"
        +
        +include Appwrite
        +
        +def main(context)
        +    client = Client.new
        +        .set_endpoint('https://cloud.appwrite.io/v1')
        +        .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
        +        .set_key(req.variables['APPWRITE_API_KEY'])
        +
        +    databases = Appwrite::Databases.new(client)
        +
        +    begin
        +        databases.create_document(
        +            databaseId: '[DATABASE_ID]',
        +            collectionId: '[COLLECTION_ID]',
        +            documentId: ID.unique(),
        +            data: {}
        +        )
        +    rescue Exception => e
        +        context.error("Failed to create document: " + e.message)
        +        return context.response.send("Failed to create document")
        +    end
        +
        +    return context.response.send("Document created")
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
        +                
        +export default function ({req, res, error}: any){
        +    const client = new Client()
        +        .setEndpoint("https://cloud.appwrite.io/v1")
        +        .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
        +        .setKey(Deno.env.get("APPWRITE_API_KEY") || "");
        +    
        +    const databases = new Databases(client);
        +    
        +    try {
        +        databases.createDocument(
        +            "[DATABASE_ID]",
        +            "[COLLECTION_ID]",
        +            ID.unique(),
        +            {}
        +        );
        +    } catch (e) {
        +        error("Failed to create document: " + e.message);
        +        return res.send("Failed to create document");
        +    }
        +    
        +    return res.send("Document created");
        +}
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +Future<dynamic> main(final context) async {
        +    final client = Client()
        +        .setEndpoint('https://cloud.appwrite.io/v1')
        +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +        .setKey(process.env.APPWRITE_API_KEY);
        +    
        +    final databases = Databases(client);
        +    
        +    try {
        +        await databases.createDocument(
        +            databaseId: '[DATABASE_ID]',
        +            collectionId: '[COLLECTION_ID]',
        +            documentId: ID.unique(),
        +            data: {}
        +        );
        +    } catch (e) {
        +        context.error("Failed to create document: " + e.message);
        +        return context.res.send("Failed to create document");
        +    }
        +
        +    return context.res.send("Document created");
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Appwrite
        +import AppwriteModels
        +import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    let client = Client()
        +       .setEndpoint("https://cloud.appwrite.io/v1")
        +       .setProject(ProcessInfo.processInfo.environment["APPWRITE_FUNCTION_PROJECT_ID"])
        +       .setKey(ProcessInfo.processInfo.environment["APPWRITE_API_KEY"]);
        +
        +    let databases = Databases(client: client)
        +
        +    do {
        +        try await databases.createDocument(
        +            databaseId: "[DATABASE_ID]", 
        +            collectionId: "[COLLECTION_ID]",
        +            documentId: ID.unique(),
        +            data: [:]
        +        )
        +    } catch {
        +        context.error("Failed to create document: \(error.localizedDescription)")
        +        return context.res.send("Failed to create document")
        +    }
        +
        +    return context.res.send("Document created")
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        using Appwrite;
        +using Appwrite.Services;
        +using Appwrite.Models;                        
        +                        
        +namespace DotNetRuntime
        +{
        +    public class Handler 
        +    {
        +        public async Task Main(RuntimeContext Context) 
        +        {
        +            var client = new Client()
        +               .SetEndpoint("https://cloud.appwrite.io/v1")
        +               .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
        +               .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
        +    
        +            var databases = new Databases(client);
        +    
        +            try {
        +                await databases.CreateDocument(
        +                    databaseId: "[DATABASE_ID]",
        +                    collectionId: "[COLLECTION_ID]",
        +                    documentId: ID.Unique(),
        +                    data: new Dictionary<string, object>());
        +            } catch (Exception e) {
        +                Context.Error("Failed to create document: " + e.Message);
        +                return Context.Response.Send("Failed to create document");
        +            }
        +    
        +            return Context.Response.Send("Document created");
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +import io.appwrite.Client
        +import io.appwrite.services.Databases
        +import io.appwrite.ID
        +import java.util.HashMap
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        val client = Client()
        +           .setEndpoint("https://cloud.appwrite.io/v1")
        +           .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +           .setKey(System.getenv("APPWRITE_API_KEY"))
        +
        +        val databases = Databases(client)
        +
        +        try {
        +            databases.createDocument(
        +                databaseId = "[DATABASE_ID]",
        +                collectionId = "[COLLECTION_ID]",
        +                documentId = ID.unique()
        +                data = mapOf()
        +            )
        +        } catch (e: Exception) {
        +            context.error("Failed to create document: " + e.message)
        +            return context.res.send("Failed to create document")
        +        }
        +
        +        return context.res.send("Document created")
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +import java.util.HashMap;
        +import io.appwrite.Client;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        Client client = new Client()
        +            .setEndpoint("https://cloud.appwrite.io/v1")
        +            .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +            .setKey(System.getenv("APPWRITE_API_KEY"));
        +
        +        Databases databases = new Databases(client);
        +
        +        try {
        +            databases.createDocument(
        +                "[DATABASE_ID]",
        +                "[COLLECTION_ID]",
        +                ID.unique(),
        +                new HashMap<>()
        +            );
        +        } catch (Exception e) {
        +            context.error("Failed to create document: " + e.getMessage());
        +            return context.res.send("Failed to create document");
        +        }
        +
        +        return context.res.send("Document created");
        +    }
        +}
        +
        +
      • +
      + + +

      Using JWT

      +

      + JWTs allow you to act on behalf of an user in your Appwrite Function. + When using JWTs, you will be able to access and change only the resources with the same permissions as the user account that signed the JWT. + This preserves the permissions you configured on each resource. +

      + +

      + If the Appwrite Function is invoked by an authenticated user, the x-appwrite-user-jwt header is automatically passed in. +

      + +
        +
      • +

        Node.js

        +
        +
        import { Client, Databases, ID } from 'node-appwrite';
        +
        +export default async ({ req, res, log }) => {
        +    const client = new Client()
        +        .setEndpoint('https://cloud.appwrite.io/v1')
        +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +
        +    if (req.headers['x-appwrite-user-jwt']) {
        +        client.setJWT(req.headers['x-appwrite-user-jwt'])
        +    } else {
        +        return res.send("Please sign in, JWT not found")
        +    }
        +
        +    const databases = new Databases(client);
        +
        +    try {
        +        await databases.createDocument(
        +            '[DATABASE_ID]',
        +            '[COLLECTION_ID]',
        +            ID.unique(),
        +            {}
        +        )
        +    } catch (e) {
        +        log("Failed to create document: " + e.message)
        +        return res.send("Failed to create document")
        +    }
        +
        +    return res.send("Document created")
        +}
        +
        +
      • +
      • +

        PHP

        +
        +
        <?php
        +
        +require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +use Appwrite\Services\Databases;
        +use Appwrite\ID;
        +
        +return function ($context) {
        +    $client = new (Client())
        +        ->setEndpoint('https://cloud.appwrite.io/v1')
        +        ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
        +    
        +    if (isset($context->req->headers['x-appwrite-user-jwt'])) {
        +        $client->setJWT($context->req->headers['x-appwrite-user-jwt']);
        +    } else {
        +        return $context->res->send("Please sign in, JWT not found");
        +    }
        +    
        +    $databases = new Databases($client);
        +
        +    try {
        +        $databases->createDocument(
        +            databaseId: '[DATABASE_ID]',
        +            collectionId: '[COLLECTION_ID]',
        +            documentId: ID::unique(),
        +            data: []
        +        );
        +    } catch (Exception $e) {
        +        $context->error("Failed to create document: " . $e->getMessage());
        +        return $context->res->send("Failed to create document");
        +    }
        +
        +    return $context->res->send("Document created");
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        from appwrite.client import Client
        +from appwrite.services.databases import Databases
        +from appwrite.id import ID
        +
        +import os
        +
        +def main(context):
        +    client = (
        +        Client()
        +            .set_endpoint("https://cloud.appwrite.io/v1")
        +            .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
        +    )
        +
        +    if "x-appwrite-user-jwt" in context.req.headers:
        +        client.set_jwt(context.req.headers["x-appwrite-user-jwt"])
        +    else:
        +        return context.res.send("Please sign in, JWT not found")
        +
        +    databases = Databases(client)
        +
        +    try:
        +        databases.create_document(
        +            database_id="[DATABASE_ID]",
        +            collection_id="[COLLECTION_ID]",
        +            document_id=ID.unique(),
        +            data={}
        +        )
        +    except Exception as e:
        +        context.error("Failed to create document: " + e.message)
        +        return context.response.send("Failed to create document")
        +
        +    return context.response.send("Document created")
        +
        +
      • +
      • +

        Ruby

        +
        +
        require "appwrite"
        +
        +include Appwrite
        +
        +def main(context)
        +    client = Client.new
        +        .set_endpoint('https://cloud.appwrite.io/v1')
        +        .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
        +
        +    if context.request.headers['x-appwrite-user-jwt']
        +        client.set_jwt(context.request.headers['x-appwrite-user-jwt'])
        +    else
        +        return context.response.send("Please sign in, JWT not found")
        +    end
        +
        +    databases = Appwrite::Databases.new(client)
        +
        +    begin
        +        databases.create_document('[DATABASE_ID]', '[COLLECTION_ID]', Appwrite::ID.unique(), {})
        +    rescue Appwrite::Exception => e
        +        context.error("Failed to create document: " + e.message)
        +        return context.response.send("Failed to create document")
        +    end
        +
        +    return context.response.send("Document created")
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
        +                
        +export default function ({req, res, error}: any){
        +    const client = new Client()
        +        .setEndpoint("https://cloud.appwrite.io/v1")
        +        .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
        +    
        +    if (req.headers["x-appwrite-user-jwt"]) {
        +        client.setJWT(req.headers["x-appwrite-user-jwt"]);
        +    } else {
        +        return res.send("Please sign in, JWT not found");
        +    }
        +    
        +    const databases = new Databases(client);
        +    
        +    try {
        +        databases.createDocument(
        +            "[DATABASE_ID]",
        +            "[COLLECTION_ID]",
        +            ID.unique(),
        +            {}
        +        );
        +    } catch (e) {
        +        error("Failed to create document: " + e.message)
        +        return res.send("Failed to create document");
        +    }
        +    
        +    return res.send("Document created");
        +}
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'dart:async';
        +import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +Future<dynamic> main(final context) async {
        +    final client = Client()
        +        .setEndpoint('https://cloud.appwrite.io/v1')
        +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +    
        +    if (context.req.headers['x-appwrite-user-jwt'] != null) {
        +        client.setJWT(context.req.headers['x-appwrite-user-jwt']);
        +    } else {
        +        return context.res.send("Please sign in, JWT not found");
        +    }
        +    
        +    final databases = Databases(client);
        +    
        +    try {
        +        await databases.createDocument(
        +            databaseId: '[DATABASE_ID]',
        +            collectionId: '[COLLECTION_ID]',
        +            documentId: ID.unique(),
        +            data: {}
        +        );
        +    } catch (e) {
        +        context.error("Failed to create document: " + e.message);
        +        return context.res.send("Failed to create document");
        +    }
        +
        +    return context.res.send("Document created");
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Appwrite
        +import AppwriteModels
        +import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    let client = Client()
        +       .setEndpoint("https://cloud.appwrite.io/v1")
        +       .setProject(ProcessInfo.processInfo.environment["APPWRITE_FUNCTION_PROJECT_ID"])
        +    
        +    if let jwt = context.req.headers["x-appwrite-user-jwt"] {
        +        client.setJWT(jwt)
        +    } else {
        +        return context.res.send("Please sign in, JWT not found")
        +    }
        +
        +    let databases = Databases(client: client)
        +
        +    do {
        +        try await databases.createDocument(
        +            databaseId: "[DATABASE_ID]",
        +            collectionId: "[COLLECTION_ID]",
        +            documentId: ID.unique()
        +            data: [:]
        +        )
        +    } catch {
        +        context.error("Failed to create document: \(error.localizedDescription)")
        +        return context.res.send("Failed to create document")
        +    }
        +
        +    return context.res.send("Document created")
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        using Appwrite;
        +using Appwrite.Services;
        +using Appwrite.Models;
        +
        +namespace DotNetRuntime
        +{
        +    public class Handler
        +    {
        +        public async Task Main(RuntimeContext Context)
        +        {
        +            var client = new Client()
        +               .SetEndpoint("https://cloud.appwrite.io/v1")
        +               .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
        +
        +            if (Context.Req.Headers.ContainsKey("x-appwrite-user-jwt")) {
        +                client.SetJWT(Context.Req.Headers["x-appwrite-user-jwt"]);
        +            } else {
        +                return Context.Res.Send("Please sign in, JWT not found");
        +            }
        +
        +            var databases = new Databases(client);
        +
        +            try {
        +                await databases.CreateDocument(
        +                    databaseId: "[DATABASE_ID]",
        +                    collectionId: "[COLLECTION_ID]",
        +                    documentId: ID.Unique(),
        +                    data: new Dictionary<string, object>());
        +            } catch (Exception e) {
        +                Context.Error("Failed to create document: " + e.Message);
        +                return Context.Res.Send("Failed to create document");
        +            }
        +
        +            return Context.Res.Send("Document created");
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +import io.appwrite.Client
        +import io.appwrite.services.Databases
        +import io.appwrite.ID
        +import java.util.HashMap
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        val client = Client()
        +           .setEndpoint("https://cloud.appwrite.io/v1")
        +           .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +
        +        if (context.req.headers["x-appwrite-user-jwt"] != null) {
        +            client.setJWT(context.req.headers["x-appwrite-user-jwt"])
        +        } else {
        +            return context.res.send("Please sign in, JWT not found")
        +        }
        +
        +        val databases = Databases(client)
        +
        +        try {
        +            databases.createDocument(
        +                databaseId = "[DATABASE_ID]",
        +                collectionId = "[COLLECTION_ID]",
        +                documentId = ID.unique(),
        +                data = mapOf()
        +            )
        +        } catch (e: Exception) {
        +            context.error("Failed to create document: " + e.message)
        +            return context.res.send("Failed to create document")
        +        }
        +
        +        return context.res.send("Document created")
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +import java.util.HashMap;
        +import io.appwrite.Client;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        Client client = new Client()
        +            .setEndpoint("https://cloud.appwrite.io/v1")
        +            .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
        +                
        +        if (context.req.headers.containsKey("x-appwrite-user-jwt")) {
        +            client.setJWT(context.req.headers.get("x-appwrite-user-jwt"));
        +        } else {
        +            return context.res.send("Please sign in, JWT not found");
        +        }
        +
        +        Databases databases = new Databases(client);
        +
        +        try {
        +            databases.createDocument(
        +                "[DATABASE_ID]",
        +                "[COLLECTION_ID]",
        +                ID.unique(),
        +                new HashMap<>()
        +            );
        +        } catch (Exception e) {
        +            context.error("Failed to create document: " + e.getMessage());
        +            return context.res.send("Failed to create document");
        +        }
        +
        +        return context.res.send("Document created");
        +
        +    }
        +}
        +
        +
      • +
      + + +

      Code Splitting

      +

      + As your functions grow, you may find yourself needing to split your code into multiple files. + This helps you keep your codebase maintainable and easy to read. + Here's how you can accomplish code splitting. +

      +
        +
      • +

        Node.js

        +
        +
        // src/utils.js
        +
        +export function add(a, b) {
        +    return a + b;
        +}
        +            
        +
        +
        +
        // src/main.js
        +
        +import { add } from './utils.js';
        +
        +export default function ({ res }) {
        +    return res.send(add(1, 2));
        +}
        +
        +
      • +
      • +

        PHP

        +
        +
        // src/utils.php
        +
        +function add($a, $b) {
        +    return $a + $b;
        +}
        +
        +
        +
        // src/main.php
        +
        +include 'utils.php';
        +
        +return function ($context) {
        +    return $context->res->send(add(1, 2));
        +};
        +
        +
      • +
      • +

        Python

        +
        +
        // src/utils.py
        +
        +def add(a, b):
        +    return a + b;
        +        
        +
        +
        +
        // src/main.py
        +
        +from .utils import add
        +
        +def main(context):
        +    return context.res.send(add(1, 2))
        +
        +
      • +
      • +

        Ruby

        +
        +
        # lib/utils.rb
        +
        +def add(a, b)
        +    return a + b
        +end
        +
        +
        +
        # lib/main.rb
        +
        +require_relative 'utils'
        +
        +def main(context)
        +    return context.res.send(add(1, 2))
        +end
        +
        +
      • +
      • +

        Deno

        +
        +
        // src/utils.ts
        +
        +export function add(a: number, b: number): number {
        +    return a + b;
        +}
        +
        +
        +
        // src/main.ts
        +
        +import { add } from './utils.ts';
        +
        +export default function ({res}: {res: any}) {
        +    return res.send(add(1, 2));
        +}
        +
        +
      • +
      • +

        Dart

        +
        +
        // lib/utils.dart
        +
        +int add(int a, int b) {
        +    return a + b;
        +}
        +
        +
        +
        // lib/main.dart
        +import 'dart:async';
        +
        +Future<dynamic> main(final context) async {
        +    return context.res.send(add(1, 2));
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        // Sources/utils.swift
        +
        +func add(_ a: Int, _ b: Int) -> Int {
        +    return a + b
        +}
        +            
        +
        +
        +
        // Sources/index.swift
        +
        +import Foundation
        +
        +func main(context: RuntimeContext) async throws -> RuntimeOutput {
        +    return context.res.send(add(1, 2))
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        // src/Utils.cs
        +
        +namespace DotNetRuntime
        +{
        +    public static class Utils
        +    {
        +        public static int Add(int a, int b)
        +        {
        +            return a + b;
        +        }
        +    }
        +}
        +
        +
        +
        // src/Index.cs
        +
        +namespace DotNetRuntime
        +{
        +    public class Handler {
        +        public async Task Main(RuntimeContext Context)
        +        {
        +            return Context.Res.Send(Utils.Add(1, 2));
        +        }
        +    }
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        // src/Utils.kt
        +
        +package io.openruntimes.kotlin.src
        +
        +object Utils {
        +    fun add(a: Int, b: Int): Int {
        +        return a + b
        +    }
        +}
        +
        +
        +
        // src/Main.kt
        +
        +package io.openruntimes.kotlin.src
        +
        +import io.openruntimes.kotlin.RuntimeContext
        +import io.openruntimes.kotlin.RuntimeOutput
        +import io.openruntimes.kotlin.Utils
        +
        +class Main {
        +    fun main(context: RuntimeContext): RuntimeOutput {
        +        return context.res.send(Utils.add(1, 2))
        +    }
        +}
        +
        +
      • +
      • +

        Java

        +
        +
        // src/Utils.java
        +
        +package io.openruntimes.java.src;
        +
        +class Utils {
        +    public static int add(int a, int b) {
        +        return a + b;
        +    }
        +}
        +
        +
        +
        package io.openruntimes.java.src;
        +
        +import io.openruntimes.java.RuntimeContext;
        +import io.openruntimes.java.RuntimeOutput;
        +import io.openruntimes.java.Utils;
        +
        +public class Main {
        +    public RuntimeOutput main(RuntimeContext context) throws Exception {
        +        return context.res.send(Utils.add(1, 2));
        +    }
        +}
        +
        +
      • +
      + + +

      Upgrade

      +

      + Appwrite Functions received major updates in Appwrite version 1.4. + If you still have functions from previous versions, they will be read-only in Appwrite 1.4. + You will have to migrate your old functions to follow new runtime syntax. +

      + +

      + Here's a checklist of things you need to know. +

      + +
        +
      1. + The parameter passed into functions has changed. + req and res has been replaced by context, which contains new logger methods. + Learn about context. +
      2. +
      3. + To improve privacy and logging reliability, we provide new context.log() and context.error() functions. + You can no longer use native logging methods. + Learn about logging. +
      4. +
      5. + The old way of req.variables has been deprecated. + You can now access variables passed into each function as environment variables. + Learn about environment variables. +
      6. +
      7. + The req object has been updated to use terminology consistent with typical HTTP concepts. + You'll now find familiar concepts like headers, body, HTTP methods, and others. + Learn about request. +
      8. +
      9. + The response object has been updated. + You can now specify headers, as well as use new methods like return redirects or empty responses. + Learn about response. +
      10. +
      11. + Now, you must return a response such as return context.res.send(""). + This prevents confusing errors when functions are terminated prematurely before a response is sent. + Learn about response. +
      12. +
      13. + Some variables about how a function was triggered are now found in the context.req object as headers. +
      14. +
      \ No newline at end of file diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml new file mode 100644 index 000000000..0fdabae89 --- /dev/null +++ b/app/views/docs/functions-examples.phtml @@ -0,0 +1,930 @@ +

      + Appwrite Functions is all about flexibility. + Behind the simple workflow hides some useful examples that can help you accomplish your goals faster. + Take a look at the following. +

      + +

      Currency Conversion API

      + +

      + Here's a currency conversion API that converts from Euros and Indian Rupees to US Dollars. We'll use an external API to get the latest exchange rates, and query it using an dependency specific to each runtime. +

      + +

      Prerequisites

      + +
        +
      • +

        Node.js

        +
        +

        Run the following bash command to create a package.json file. This file is used to manage your Node.js project's dependencies.

        +
        +
        npm init -y
        +
        +

        Install the undici library. This library includes a fetch function that you can use to make HTTP requests.

        +
        +
        npm install undici
        +
        +

        Finally, add npm install to your function's build commands in the Appwrite Console.

        +
        +
      • +
      • +

        PHP

        +
        +

        Run the following bash command to create a composer.json file. This file is used to manage your PHP project's dependencies.

        +
        +
        composer init -y
        +
        +

        Install the guzzlehttp/guzzle library. This library includes a get function that you can use to make HTTP requests.

        +
        +
        composer require guzzlehttp/guzzle
        +
        +

        Finally, add composer install to your function's build commands in the Appwrite Console.

        +
        +
      • +
      • +

        Python

        +
        +

        Run the following bash command to create a requirements.txt file. This file is used to manage your Python project's dependencies.

        +
        +
        touch requirements.txt
        +
        +

        Install the requests library. This library includes a get function that you can use to make HTTP requests.

        +
        +
        echo "requests" >> requirements.txt
        +pip install -r requirements.txt
        +
        +

        Finally, add pip install -r requirements.txt to your function's build commands in the Appwrite Console.

        +
        +
      • +
      • +

        + Dart +

        +
        +

        + Create a pubspec.yaml file with the following contents. This file is used to manage your Dart project's dependencies. +

        +
        +
        name: appwrite_function
        +description: Appwrite Function
        +version: 1.0.0
        +environment:
        +  sdk: '>=2.12.0 <3.0.0'
        +
        +

        + Install the http library. This library includes a get function that you can use to make HTTP requests. +

        +
        +
        pub install http
        +
        +

        + Finally, add pub get to your function's build commands in the Appwrite Console. +

        +
        +
      • +
      • +

        + Ruby +

        +
        +

        + Create a Gemfile file with the following contents. This file is used to manage your Ruby project's dependencies. +

        +
        +
        source 'https://rubygems.org'
        +
        +

        + Install the httparty library. This library includes a get function that you can use to make HTTP requests. +

        +
        +
        echo "gem 'httparty'" >> Gemfile
        +bundle install
        +
        +

        + Finally, add bundle install to your function's build commands in the Appwrite Console. +

        +
        +
      • +
      + +

      Code

      + +
        +
      • +

        Node.js

        +
        +

        +

        +
        import { fetch } from 'undici';
        +
        +export default async function ({ req, res }) {
        +  if (req.path === '/eur') {
        +    const amountInEuros = Number(req.query.amount);
        +    const response = await fetch('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
        +    const data = await response.json();
        +    const amountInDollars = amountInEuros * data.rates.USD;
        +    return res.send(amountInDollars.toString());
        +  }
        +
        +  if (req.path === '/inr') {
        +    const amountInRupees = Number(req.query.amount);
        +    const response = await fetch('https://api.exchangerate.host/latest?base=INR&symbols=USD');
        +    const data = await response.json();
        +    const amountInDollars = amountInRupees * data.rates.USD;
        +    return res.send(amountInDollars.toString());
        +  }
        +
        +  return res.send('Invalid path');
        +};
        +
        +
        +
      • +
      • +

        PHP

        +
        +

        +

        +
        <?php
        +
        +require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +use Appwrite\Services\Database;
        +use GuzzleHttp\Client as GuzzleClient;
        +
        +return function ($context) {
        +    $client = new GuzzleClient();
        +
        +    if ($context->req->path === '/eur') {
        +        $amountInEuros = floatval($context->req->query['amount']);
        +        $response = $client->get('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
        +        $data = $response->json();
        +        $amountInDollars = $amountInEuros * $data['rates']['USD'];
        +        return $context->res->send(strval($amountInDollars));
        +    }
        +
        +    if ($context->req->path === '/inr') {
        +        $amountInRupees = floatval($context->req->query['amount']);
        +        $response = $client->get('https://api.exchangerate.host/latest?base=INR&symbols=USD');
        +        $data = $response->json();
        +        $amountInDollars = $amountInRupees * $data['rates']['USD'];
        +        return $context->res->send(strval($amountInDollars));
        +    }
        +
        +    return $context->res->send('Invalid path');
        +};
        +
        +
      • +
      • +

        Python

        +
        +

        +

        +
        import requests
        +
        +def main(context):
        +  if context.req.path == '/eur':
        +    amount_in_euros = float(context.req.query['amount'])
        +    response = requests.get('https://api.exchangerate.host/latest?base=EUR&symbols=USD')
        +    data = response.json()
        +    amount_in_dollars = amount_in_euros * data['rates']['USD']
        +    return context.res.send(str(amount_in_dollars))
        +
        +  if context.req.path == '/inr':
        +    amount_in_rupees = float(context.req.query['amount'])
        +    response = requests.get('https://api.exchangerate.host/latest?base=INR&symbols=USD')
        +    data = response.json()
        +    amount_in_dollars = amount_in_rupees * data['rates']['USD']
        +    return context.res.send(str(amount_in_dollars))
        +
        +  return 'Invalid path'
        +
        +
        +
      • +
      • +

        Dart

        +
        +

        +

        +
        import 'dart:async';
        +import 'package:http/http.dart' as http;
        +
        +Future<dynamic> main(final context) async {
        +  if (context.req.path == '/eur') {
        +    final amountInEuros = double.parse(context.req.query['amount'])
        +    final response = await http.get(Uri.parse('https://api.exchangerate.host/latest?base=EUR&symbols=USD'));
        +    final data = json.decode(response.body);
        +    final amountInDollars = amountInEuros * data['rates']['USD'];
        +    return context.res.send(amountInDollars.toString());
        +  }
        +
        +  if (context.req.path == '/inr') {
        +    final amountInRupees = double.parse(context.req.query['amount'])
        +    final response = await http.get(Uri.parse('https://api.exchangerate.host/latest?base=INR&symbols=USD'));
        +    final data = json.decode(response.body);
        +    final amountInDollars = amountInRupees * data['rates']['USD'];
        +    return context.res.send(amountInDollars.toString());
        +  }
        +
        +  return 'Invalid path';
        +}
        +
        +
        +
      • +
      • +

        Ruby

        +
        +

        +

        +
        require 'httparty'
        +
        +def main(context)
        +  if context.req.path == '/eur'
        +    amount_in_euros = context.req.query['amount'].to_f
        +    response = HTTParty.get('https://api.exchangerate.host/latest?base=EUR&symbols=USD')
        +    data = JSON.parse(response.body)
        +    amount_in_dollars = amount_in_euros * data['rates']['USD']
        +    return context.res.send(amount_in_dollars.to_s)
        +  end
        +
        +  if context.req.path == '/inr'
        +    amount_in_rupees = context.req.query['amount'].to_f
        +    response = HTTParty.get('https://api.exchangerate.host/latest?base=INR&symbols=USD')
        +    data = JSON.parse(response.body)
        +    amount_in_dollars = amount_in_rupees * data['rates']['USD']
        +    return context.res.send(amount_in_dollars.to_s)
        +  end
        +
        +  return 'Invalid path'
        +end
        +
        +
        +
      • + +
      + +

      + Use the function by navigating to function URL in the browser. The path should contain the currency and amount parameter. + For example, [YOUR_FUNCTION_URL]/eur?amount=5 should convert Euros to Dollars. +

      + + +

      Voting System Using Appwrite

      +

      + Here's a simple voting system that allows users to vote on various topics. Appwrite Functions and the server SDK are used to enforce voting rules and prevent multiple votes from the same user for a single topic. +

      + +

      Prerequisites

      + +

      Create a Topics collection with the following attributes:

      + + + + + + + + + + + + + + + + + + + + + +
      NameTypeDescription
      titlestringThe name of the topic
      descriptionstringLong form description of the topic
      + +

      Create a Votes collection with the following attributes:

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameTypeDescription
      userIdstringThe ID of the user who cast the vote
      topicIdstringThe ID of the topic that was voted on
      votestringThe vote cast by the user. Must be either "yes" or "no"
      + +

      Code

      + +
        +
      • +

        Node.js

        +
        +
        +
        import { Client, Databases, Query } from 'node-appwrite';
        +
        +export default async function ({ req, res }) {
        +  const vote = {
        +    userId: req.query.userId,
        +    topicId: req.query.topicId,
        +    vote: req.query.vote
        +  };
        +
        +  if (vote.vote !== 'yes' && vote.vote !== 'no') {
        +    return res.json({ ok: false, message: 'You must vote yes or no.' }, 400);
        +  }
        +
        +  const client = new Client();
        +  client
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +    .setKey(process.env.APPWRITE_API_KEY);
        +
        +  const database = new Database(client);
        +  
        +  const existingVotes = await database.listDocuments('[VOTES_COLLECTION_ID]', [
        +    Query.equals('userId', vote.userId),
        +    Query.equals('topicId', vote.topicId)
        +  ]);
        +
        +  if (existingVotes.total > 0) {
        +    return res.json({ ok: false, message: 'You have already voted on this topic.' }, 400);
        +  }
        +
        +  const voteDocument = await database.createDocument('[VOTES_COLLECTION_ID]', {
        +    userId,
        +    topicId,
        +    vote,
        +  });
        +
        +  return res.json({ ok: true, message: 'Vote cast.', vote: voteDocument });
        +}
        +
        +
        +
      • +
      • +

        Python

        +
        +

        +

        +
        from appwrite.client import Client
        +from appwrite.services.databases import Databases
        +from appwrite.query import Query
        +import os
        +
        +def main(context):
        +    vote = {
        +        'userId': context.req.query['userId'],
        +        'topicId': context.req.query['topicId'],
        +        'vote': context.req.query['vote']
        +    }
        +
        +    if vote['vote'] != 'yes' and vote['vote'] != 'no':
        +        return context.res.json({'ok': False, 'message': 'You must vote yes or no.'}, 400)
        +
        +    client = (
        +        Client()
        +        .set_endpoint("https://cloud.appwrite.io/v1")
        +        .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
        +        .set_key(os.environ["APPWRITE_API_KEY"])
        +    )
        +
        +    database = Databases(client)
        +    
        +    existing_votes = database.list_documents('[VOTES_COLLECTION_ID]', [
        +        Query.equals('userId', vote['userId']),
        +        Query.equals('topicId', vote['topicId'])
        +    ])
        +
        +    if existing_votes['total'] > 0:
        +        return context.res.json({
        +          'ok': False, 
        +          'message': 'You have already voted on this topic.'
        +        }, 400)
        +
        +    vote_document = database.create_document('[VOTES_COLLECTION_ID]', {
        +        'userId': vote['userId'],
        +        'topicId': vote['topicId'],
        +        'vote': vote['vote'],
        +    })
        +
        +    return context.res.json({'ok': True, 'message': 'Vote cast.', 'vote': vote_document})
        +
        +
        +
      • +
      • +

        PHP

        +
        +

        +

        +
        <?php
        +
        +require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +use Appwrite\Services\Database;
        +use Appwrite\Query;
        +
        +return function ($context) {
        +    $vote = [
        +        'userId' => $context->req->query['userId'],
        +        'topicId' => $context->req->query['topicId'],
        +        'vote' => $context->req->query['vote']
        +    ];
        +
        +    if ($vote['vote'] !== 'yes' && $vote['vote'] !== 'no') {
        +        return $context->res->json(['ok' => false, 'message' => 'You must vote yes or no.'], 400);
        +    }
        +
        +    $client = new Client();
        +    $client
        +        ->setEndpoint('https://cloud.appwrite.io/v1')
        +        ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
        +        ->setKey(getenv('APPWRITE_API_KEY'));
        +
        +    $database = new Database($client);
        +
        +    $existingVotes = $database->listDocuments('[VOTES_COLLECTION_ID]', [
        +        Query->equal('userId', $vote['userId']),
        +        Query->equal('topicId', $vote['topicId'])
        +    ]);
        +
        +    if ($existingVotes['total'] > 0) {
        +        return $context->res->json([
        +          'ok' => false, 
        +          'message' => 'You have already voted on this topic.'
        +        ], 400);
        +    }
        +
        +    $voteDocument = $database->createDocument('[VOTES_COLLECTION_ID]', [
        +        'userId' => $vote['userId'],
        +        'topicId' => $vote['topicId'],
        +        'vote' => $vote['vote'],
        +    ]);
        +
        +    return $context->res->json([
        +      'ok' => true, 
        +      'message' => 'Vote cast.', 
        +      'vote' => $voteDocument
        +    ]);
        +};
        +
        +
        +
      • +
      • +

        Ruby

        +
        +

        +

        +
        require "appwrite"
        +
        +def main(context)
        +    vote = {
        +        'userId' => context.req.query['userId'],
        +        'topicId' => context.req.query['topicId'],
        +        'vote' => context.req.query['vote']
        +    }
        +
        +    if vote['vote'] != 'yes' and vote['vote'] != 'no'
        +        return context.res.json({'ok': false, 'message': 'You must vote yes or no.'}, 400)
        +    end
        +
        +    client = Appwrite::Client.new()
        +    client
        +        .set_endpoint('https://cloud.appwrite.io/v1')
        +        .set_project(ENV['APPWRITE_FUNCTION_PROJECT_ID'])
        +        .set_key(ENV['APPWRITE_API_KEY'])
        +
        +    database = Appwrite::Database.new(client)
        +    
        +    existing_votes = database.list_documents('[VOTES_COLLECTION_ID]', [
        +        Appwrite::Query.new('userId', '=', vote['userId']),
        +        Appwrite::Query.new('topicId', '=', vote['topicId'])
        +    ])
        +
        +    if existing_votes['total'] > 0
        +        return context.res.json({
        +          'ok': false, 
        +          'message': 'You have already voted on this topic.'
        +        }, 400)
        +    end
        +
        +    vote_document = database.create_document('[VOTES_COLLECTION_ID]', {
        +        'userId': vote['userId'],
        +        'topicId': vote['topicId'],
        +        'vote': vote['vote'],
        +    })
        +
        +    return context.res.json({
        +      'ok': true, 
        +      'message': 'Vote cast.', 
        +      'vote': vote_document
        +    })
        +end
        +
        +
        +
      • +
      • +

        Dart

        +
        +

        +

        +
        import 'dart:async';
        +import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +Future main(final context) async {
        +    final vote = {
        +        'userId': context.req.query['userId'],
        +        'topicId': context.req.query['topicId'],
        +        'vote': context.req.query['vote']
        +    };
        +
        +    if (vote['vote'] != 'yes' && vote['vote'] != 'no') {
        +        return context.res.json({'ok': false, 'message': 'You must vote yes or no.'}, 400);
        +    }
        +
        +    final client = Client()
        +        .setEndpoint('https://cloud.appwrite.io/v1')
        +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +        .setKey(process.env.APPWRITE_API_KEY);
        +
        +    final database = Database(client);
        +
        +    final existingVotes = await database.listDocuments('[VOTES_COLLECTION_ID]', [
        +        Query.equals('userId', vote['userId']),
        +        Query.equals('topicId', vote['topicId'])
        +    ]);
        +
        +    if (existingVotes['total'] > 0) {
        +        return context.res.json({
        +          'ok': false, 
        +          'message': 'You have already voted on this topic.'
        +        }, 400);
        +    }
        +
        +    final voteDocument = await database.createDocument('[VOTES_COLLECTION_ID]', {
        +        'userId': vote['userId'],
        +        'topicId': vote['topicId'],
        +        'vote': vote['vote'],
        +    });
        +
        +    return context.res.json({
        +      'ok': true, 
        +      'message': 'Vote cast.', 
        +      'vote': voteDocument
        +    });
        +}
        +
        +
        +
      • +
      + +

      + Use the function by navigating to the function URL in the browser. The URL should contain the required parameters. + For example, [YOUR_FUNCTION_URL]/?userId=[USER_ID]&topicId=[TOPIC_ID]&vote=yes to cast a vote. +

      + +

      HTML Contact Form

      +

      + Here's a simple form page that handles form submissions, and can be used to store a user's message in a collection. + The form is submitted to the function using the POST method and the form data is sent as a URL-encoded string in the request body. +

      + +

      Prerequisites

      + +

      Create a Messages collection with the following attributes:

      + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameTypeDescription
      namestringThe name of the message author
      emailstringThe email of the message author
      contentstringThe content of the message
      + +

      Code

      + +
        +
      • +

        Node.js

        +
        +
        +
        import { Client, Databases, Query, ID } from 'node-appwrite';
        +import querystring from 'node:querystring';
        +
        +const html = `<!doctype html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <title>Contact Form</title>
        +  </head>
        +  <body>
        +    <form action="/" method="POST">
        +      <input type="text" id="name" name="name" placeholder="Name" required>
        +      <input type="email" id="email" name="email" placeholder="Email" required>
        +      <textarea id="content" name="content" placeholder="Message" required></textarea>
        +      <button type="submit">Submit</button>
        +    </form>
        +  </body>
        +</html>`
        +
        +export default async function ({ req, res }) {
        +  if (req.method === 'GET') {
        +    return res.send(html, 200, {'content-type': 'text/html'});
        +  }
        +
        +  if (req.method === 'POST' && req.headers['content-type'] === 'application/x-www-form-urlencoded') {
        +    const formData = querystring.parse(req.body);
        +
        +    const message = {
        +      name: formData.name,
        +      email: formData.email,
        +      content: formData.content
        +    };
        +
        +    const client = new Client();
        +    client
        +      .setEndpoint('https://cloud.appwrite.io/v1')
        +      .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +      .setKey(process.env.APPWRITE_API_KEY);
        +
        +    const databases = new Databases(client);
        +    const document = await databases.createDocument('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID.unique(), message);
        +
        +    return res.send("Message sent");
        +  }
        +
        +  return res.send('Not found', 404);
        +}
        +
        +
        +
      • +
      • +

        Python

        +
        +

        +

        +
        from appwrite.client import Client
        +from appwrite.services.databases import Databases
        +from appwrite.query import Query
        +from urllib.parse import parse_qs
        +import os
        +
        +html = '''<!doctype html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <title>Contact Form</title>
        +  </head>
        +  <body>
        +    <form action="/" method="POST">
        +      <input type="text" id="name" name="name" placeholder="Name" required>
        +      <input type="email" id="email" name="email" placeholder="Email" required>
        +      <textarea id="content" name="content" placeholder="Message" required></textarea>
        +      <button type="submit">Submit</button>
        +    </form>
        +  </body>
        +</html>
        +'''
        +
        +def main(context):
        +    if context.req.method == 'GET':
        +        return context.res.send(html, 200, {'content-type': 'text/html'})
        +
        +    if context.req.method == 'POST' and context.req.headers['content-type'] == 'application/x-www-form-urlencoded':
        +        formData = parse_qs(context.req.body)
        +
        +        message = {
        +            'name': formData['name'][0],
        +            'email': formData['email'][0],
        +            'content': formData['content'][0]
        +        }
        +
        +        client = (
        +            Client()
        +            .set_endpoint("https://cloud.appwrite.io/v1")
        +            .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
        +            .set_key(os.environ["APPWRITE_API_KEY"])
        +        )
        +
        +        databases = Databases(client)
        +        document = databases.create_document('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID.unique(), message)
        +
        +        return context.res.send("Message sent")
        +
        +    return context.res.send('Not found', 404)
        +
        +
        +
      • +
      • +

        PHP

        +
        +

        +

        +
        <?php
        +
        +require(__DIR__ . '/../vendor/autoload.php');
        +
        +use Appwrite\Client;
        +use Appwrite\Exception;
        +use Appwrite\Services\Databases;
        +
        +$html = '<!doctype html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <title>Contact Form</title>
        +  </head>
        +  <body>
        +    <form action="/" method="POST">
        +      <input type="text" id="name" name="name" placeholder="Name" required>
        +      <input type="email" id="email" name="email" placeholder="Email" required>
        +      <textarea id="content" name="content" placeholder="Message" required></textarea>
        +      <button type="submit">Submit</button>
        +    </form>
        +  </body>
        +</html>';
        +
        +return function ($context) {
        +  global $html;
        +
        +  if ($context->req->method === 'GET') {
        +    return $context->res->send($html, 200, ['content-type' => 'text/html']);
        +  }
        +
        +  if ($context->req->method === 'POST' && $context->req->headers['content-type'] === 'application/x-www-form-urlencoded') {
        +    \parse_str($context->req->body, $formData);
        +    
        +    $message = [
        +      'name' => $formData['name'],
        +      'email' => $formData['email'],
        +      'content' => $formData['content']
        +    ];
        +
        +    $client = new Client();
        +    $client
        +      ->setEndpoint('https://cloud.appwrite.io/v1')
        +      ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
        +      ->setKey(getenv('APPWRITE_API_KEY'));
        +
        +    $databases = new Databases($client);
        +    $document = $databases->createDocument('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID::unique(), $message);
        +
        +    return $context->res->send("Message sent");
        +  }
        +
        +  return $context->res->send('Not found', 404);
        +};
        +
        +
        +
      • +
      • +

        Ruby

        +
        +

        +

        +
        require "appwrite"
        +
        +html = '''<!doctype html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <title>Contact Form</title>
        +  </head>
        +  <body>
        +    <form action="/" method="POST">
        +      <input type="text" id="name" name="name" placeholder="Name" required>
        +      <input type="email" id="email" name="email" placeholder="Email" required>
        +      <textarea id="content" name="content" placeholder="Message" required></textarea>
        +      <button type="submit">Submit</button>
        +    </form>
        +  </body>
        +</html>
        +'''
        +
        +def main(context)
        +    if context.req.method == 'GET'
        +        return context.res.send(html, 200, {'content-type': 'text/html'})
        +    end
        +
        +    if context.req.method == 'POST' and context.req.headers['content-type'] == 'application/x-www-form-urlencoded'
        +        formData = URI.decode_www_form(context.req.body).to_h
        +
        +        message = {
        +            'name' => formData['name'],
        +            'email' => formData['email'],
        +            'content' => formData['content']
        +        }
        +
        +        client = Appwrite::Client.new()
        +        client
        +            .set_endpoint('https://cloud.appwrite.io/v1')
        +            .set_project(ENV['APPWRITE_FUNCTION_PROJECT_ID'])
        +            .set_key(ENV['APPWRITE_API_KEY'])
        +
        +        databases = Appwrite::Database.new(client)
        +        document = databases.create_document('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID.unique(), message)
        +
        +        return context.res.send("Message sent")
        +    end
        +
        +    return context.res.send('Not found', 404)
        +end
        +
        +
        +
      • +
      • +

        Dart

        +
        +

        +

        +
        import 'dart:async';
        +import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +Future main(final context) async {
        +    final html = '''<!doctype html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <title>Contact Form</title>
        +  </head>
        +  <body>
        +    <form action="/" method="POST">
        +      <input type="text" id="name" name="name" placeholder="Name" required>
        +      <input type="email" id="email" name="email" placeholder="Email" required>
        +      <textarea id="content" name="content" placeholder="Message" required></textarea>
        +      <button type="submit">Submit</button>
        +    </form>
        +  </body>
        +</html>
        +''';
        +
        +    if (context.req.method == 'GET') {
        +        return context.res.send(html, 200, {'content-type': 'text/html'});
        +    }
        +
        +    if (context.req.method == 'POST' && context.req.headers['content-type'] == 'application/x-www-form-urlencoded') {
        +        final formData = Uri.splitQueryString(context.req.body);
        +
        +        final message = {
        +            'name': formData['name'],
        +            'email': formData['email'],
        +            'content': formData['content']
        +        };
        +
        +        final client = Client()
        +            .setEndpoint('https://cloud.appwrite.io/v1')
        +            .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
        +            .setKey(process.env.APPWRITE_API_KEY);
        +
        +        final databases = Database(client);
        +        final document = await databases.createDocument('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID.unique(), message);
        +
        +        return context.res.send("Message sent");
        +    }
        +
        +    return context.res.send('Not found', 404);
        +}
        +
        +
        +
      • +
      + +

      + Use the function by navigating to the function URL in the browser. Submit the form to store the message in the collection. +

      diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml new file mode 100644 index 000000000..150aa2842 --- /dev/null +++ b/app/views/docs/functions-execute.phtml @@ -0,0 +1,612 @@ + +

      + Appwrite Functions can be executed in several ways. + Executions can be invoked through the Appwrite SDK and visiting its REST endpoint. Functions can also be triggered by events and scheduled executions. + Here are all the different ways to consume your Appwrite Functions. +

      + +

      Domains

      +

      + Each Appwrite function has its own domain. + You can find this in the Appwrite Console, under the Function overview. +

      + +

      + The generated domains will look like this. +

      +
      +
      https://64d4d22db370ae41a32e.appwrite.global
      +
      + +

      + Alternatively you can add a custom domain to your Appwrite Function. +

      + +

      REST API

      +

      + When requests are made to this domain, whether through a browser or through an HTTP requests, + the request information like request URL, request headers, and request body will be passed to the function. + This unlocks ability for Appwrite Function to become a full-blown API server on its own. It also allows accepting incoming webhooks for handling online payments, hosting social platform bots, and much more. +

      + +
      +
      curl -X POST https://64d4d22db370ae41a32e.appwrite.global \
      +    -H "X-Custom-Header: 123" \
      +    -H "Content-Type: application/json" \
      +    -d '{"data":"this is json data"}'
      +
      + + +

      SDK

      +

      + You can invoke your Appwrite Functions directly from the Appwrite SDKs. +

      + +

      +Learn more about using the Appwrite SDKs +

      + +

      Client SDKs

      + +
        +
      • +

        Web

        +
        +
        +
        import { Client, Functions } from 'appwrite';  
        +
        +const client = new Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject('[PROJECT_ID]');
        +
        +const functions = new Functions(client)
        +
        +try {
        +    const execution = await functions.createExecution(
        +        '[FUNCTION_ID]',
        +        JSON.stringify({ 'foo': 'bar' }),
        +        false,
        +        '/',
        +        'GET',
        +        { 'X-Custom-Header': '123' }
        +    )
        +    console.log(execution)
        +} catch (err) {
        +    console.error(err.message)
        +}
        +
        +
        +
      • +
      • +

        Flutter

        +
        +
        +
        import 'package:appwrite/appwrite.dart';
        +import 'dart:convert';
        +
        +final client = Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject('[PROJECT_ID]');
        +
        +final functions = Functions(client);
        +
        +try {
        +    final execution = await functions.createExecution(
        +        functionId: '[FUNCTION_ID]',
        +        body: json.encode({ 'foo': 'bar' }),
        +        async: false,
        +        path: '/',
        +        method: 'GET',
        +        headers: {
        +            'X-Custom-Header': '123'
        +        }
        +    );
        +    print(execution.toMap());
        +} catch (e) {
        +    print(e.message);
        +}
        +
        +
        +
      • +
      • +

        Android

        +
        +
        +
        import io.appwrite.Client;
        +import io.appwrite.services.Functions;
        +import com.google.gson.Gson;
        +
        +val client = Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject('[PROJECT_ID]')
        +
        +val functions = Functions(client)
        +
        +try {
        +    val execution = functions.createExecution(
        +        functionId = "[FUNCTION_ID]",
        +        body = gson.toJson(mapOf("foo" to "bar")),
        +        async = false,
        +        path = "/",
        +        method = "GET",
        +        headers = mapOf(
        +            "X-Custom-Header" to "123"
        +        )
        +    )
        +    print(execution.toMap())
        +} catch (AppwriteException e) {
        +    e.printStackTrace()
        +}
        +
        +
        +
      • +
      • +

        Apple

        +
        +
        +
        import Appwrite
        +import Foundation
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1")
        +    .setProject("[PROJECT_ID]")
        +
        +let functions = Functions(client)
        +
        +do {
        +    let execution = try await functions.createExecution(
        +        functionId: "[FUNCTION_ID]",
        +        data: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!,
        +        path: "/",
        +        method: "GET",
        +        headers: [
        +            "X-Custom-Header": "123"
        +        ]
        +    )
        +    print(execution.toMap())
        +} catch {
        +    print(error.localizedDescription)
        +}
        +
        +
        +
      • +
      + + +

      Server SDKs

      +
        +
      • +

        Node.js

        +
        +
        +
        import { Client, Functions } from 'node-appwrite';  
        +
        +const client = new Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject('[PROJECT_ID]')
        +    .setKey('[API_KEY]');
        +
        +const functions = new Functions(client);
        +
        +try {
        +    const execution = await functions.createExecution(
        +        '[FUNCTION_ID]',
        +        JSON.stringify({ 'foo': 'bar' }),
        +        false,
        +        '/',
        +        'GET',
        +        { 'X-Custom-Header': '123' }
        +    )
        +    console.log(execution)
        +} catch (error) {
        +    console.error(error.message)
        +}
        +
        +
        +
      • +
      • +

        PHP

        +
        +
        +
        <?php
        +
        +use Appwrite\Client;
        +use Appwrite\Services\Functions;
        +
        +$client = new Client();
        +
        +$client
        +    ->setEndpoint('https://cloud.appwrite.io/v1')
        +    ->setProject('[PROJECT_ID]')
        +    ->setKey('[API_KEY]');
        +
        +$functions = new Functions($client);
        +
        +try {
        +    $execution = $functions->createExecution(
        +        functionId: '[FUNCTION_ID]',
        +        body: json_encode([ 'foo' => 'bar' ]),
        +        async: false,
        +        path: '/',
        +        method: 'GET',
        +        headers: [
        +            'X-Custom-Header' => '123'
        +        ]
        +    );
        +    echo $execution;
        +} catch ($e) {
        +    echo $e->getMessage();
        +}
        +
        +
        +
      • +
      • +

        Python

        +
        +
        +
        from appwrite.client import Client
        +from appwrite.services.functions import Functions
        +
        +import json
        +
        +client = Client()
        +
        +(client
        +  .set_endpoint('https://cloud.appwrite.io/v1')
        +  .set_project('[PROJECT_ID]')
        +  .set_key('[API_KEY]')
        +)
        +
        +functions = Functions(client)
        +
        +try:
        +    execution = functions.create_execution(
        +        functionId="[FUNCTION_ID]",
        +        data=json.dumps({'foo': 'bar'}),
        +        path='/',
        +        method='GET',
        +        headers=[
        +            'X-Custom-Header': '123'
        +        ]
        +    )
        +    print(execution)
        +except Exception as e:
        +    print(e.message)
        +
        +
        +
      • +
      • +

        Ruby

        +
        +
        +
        require 'Appwrite'
        +require 'json'
        +
        +include Appwrite
        +
        +client = Client.new
        +    .set_endpoint('https://cloud.appwrite.io/v1') 
        +    .set_project('[PROJECT_ID]') 
        +    .set_key('[API_KEY]') 
        +
        +functions = Functions.new(client)
        +
        +begin
        +    execution = functions.create_execution(
        +        function_id: '[FUNCTION_ID]',
        +        body: JSON.generate({ 'foo': 'bar'}),
        +        async: false,
        +        path: '/',
        +        method: 'GET',
        +        headers: {
        +        'X-Custom-Header': '123'
        +    })
        +    puts execution
        +rescue => e
        +    puts e.message
        +end
        +
        +
        +
      • +
      • +

        Deno

        +
        +
        +
        import { Client, Functions } from "https://deno.land/x/appwrite/mod.ts";
        +
        +const client = new Client()
        +    .setEndpoint('https://cloud.appwrite.io/v1') 
        +    .setProject('[PROJECT_ID]')
        +    .setKey('[API_KEY]');
        +
        +const functions = new Functions(client);
        +
        +try {
        +    const execution = await functions.createExecution(
        +        '[FUNCTION_ID]',
        +        JSON.stringify({ 'foo': 'bar' }),
        +        false,
        +        '/',
        +        'GET',
        +        { 'X-Custom-Header': '123' }
        +    )
        +    console.log(execution)
        +} catch (error) {
        +    console.error(error.message)
        +}
        +
        +
        +
      • +
      • +

        Dart

        +
        +
        +
        import 'package:dart_appwrite/dart_appwrite.dart';
        +import 'dart:convert';
        +
        +final client = Client();
        +    .setEndpoint('https://cloud.appwrite.io/v1')
        +    .setProject('[PROJECT_ID]')
        +    .setKey('[API_KEY]');
        +
        +final functions = Functions(client);
        +
        +try {
        +    final execution = await functions.createExecution(
        +        functionId: '[FUNCTION_ID]',
        +        body: json.encode({
        +          'foo': 'bar'
        +        }),
        +        async: false,
        +        path: '/',
        +        method: 'GET',
        +        headers: {
        +            'X-Custom-Header': '123'
        +        }
        +    );
        +} catch (e) {
        +    print(e.message);
        +}
        +
        +
        +
      • +
      • +

        Swift

        +
        +
        +
        import Appwrite
        +import Foundation
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1")
        +    .setProject("[PROJECT_ID]")
        +    .setKey("[API_KEY]")
        +
        +let functions = Functions(client)
        +
        +do {
        +    let execution = try await functions.createExecution(
        +        functionId: "[FUNCTION_ID]",
        +        body: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!),
        +        async: false,
        +        path: "/",
        +        method: "GET",
        +        headers: [
        +            "X-Custom-Header": "123"
        +        ]
        +    )
        +    print(execution)
        +catch {
        +    print(error.localizedDescription)
        +}
        +
        +
        +
      • +
      • +

        .NET

        +
        +
        +
        using Appwrite;
        +using Appwrite.Services;
        +using Appwrite.Models;
        +using System.Text.Json;
        +
        +var client = new Client()
        +    .SetEndPoint("https://cloud.appwrite.io/v1")
        +    .SetProject("[PROJECT_ID]")
        +    .SetKey("[API_KEY]");
        +
        +var functions = new Functions(client);
        +
        +try
        +{
        +    var execution = await functions.CreateExecution(
        +        functionId: "[FUNCTION_ID]",
        +        body: JsonSerializer.Serialize<object>(new Dictionary<string, object> {
        +            { "foo", "bar" }
        +        }),
        +        async: false,
        +        path: "/",
        +        method: "GET",
        +        headers: new Dictionary<string, object> {
        +            { "X-Custom-Header", "123" }
        +        });
        +
        +    Debug.Write(execution)
        +}
        +catch (Exception e)
        +{
        +    Debug.Write(e);
        +}
        +
        +
        +
      • +
      • +

        Kotlin

        +
        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Functions
        +import com.google.gson.Gson
        +
        +val client = Client(context)
        +    .setEndpoint("https://cloud.appwrite.io/v1")
        +    .setProject("[PROJECT_ID]")
        +    .setKey("[API_KEY]")
        +
        +val functions = Functions(client)
        +
        +try {
        +    val execution = functions.createExecution(
        +        functionId = "[FUNCTION_ID]",
        +        body = gson.toJson(mapOf(
        +            "foo" to "bar"
        +        )),
        +        path = "/",
        +        method = "GET",
        +        headers = mapOf(
        +            "X-Custom-Header" to "123"
        +        )
        +    )
        +    print(execution)
        +} catch (e: Exception) {
        +    e.printStackTrace()
        +}
        +
        + +
        +
      • +
      • +

        Java

        +
        +
        +
        import io.appwrite.Client;
        +import io.appwrite.services.Functions;
        +import java.util.HashMap;
        +import com.google.gson.Gson;
        +
        +Client client = new Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1")
        +    .setProject("[PROJECT_ID]")
        +    .setKey("[API_KEY]");
        +
        +Functions functions = new Functions(client);
        +
        +functions.createExecution(
        +    "[FUNCTION_ID]",
        +    gson.toJson(new HashMap() {{
        +        put("foo", "bar");
        +    }}),
        +    false,
        +    "/",
        +    "GET",
        +    new HashMap() {{
        +        put("X-Custom-Header", "123");
        +    }},
        +    new CoroutineCallback<>((execution, error) -> {
        +        if (error != null) {
        +            error.printStackTrace();
        +            return;
        +        }
        +
        +        System.out.println(result);
        +    }),
        +);
        +
        +
        +
      • +
      + + +

      Console

      +

      + Another easy way to test a function is directly in the Appwrite Console. + You test a function by hitting the Execute now button, which will display with modal below. + You'll be able to mock executions by configuring the path, method, headers, and body. +

      + +setParam('srcLight', '/images-ee/docs/functions-execute-light.png') + ->setParam('srcDark', '/images-ee/docs/functions-execute-dark.png') + ->setParam('alt', '"Execute Function" modal.') + ->setParam('description', '"Execute Function" modal.') + ->render(); +?> + +

      Events

      +

      + Changes in Appwrite emit events. + You can configure Functions to be executed in response to these events. +

      +
        +
      1. In Appwrite Console, navigate to Functions.
      2. +
      3. Click to open a function you wish to configure.
      4. +
      5. Under the Settings tab, navigate to Events.
      6. +
      7. Add one or multiple events as triggers for the function.
      8. +
      9. + Be careful to avoid selecting events that can be caused by the function itself. + This can cause the function to trigger its own execution, resulting in infinite recursions. +
      10. +
      + + +

      Schedule

      +

      Appwrite supports scheduled function executions. You can schedule executions using cron expressions in the settings of your function. Cron supports recurring executions as frequently as every minute.

      + +

      Here are some cron expressions for common intervals.

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Cron ExpressionSchedule
      */15 * * * *Every 15 minutes
      0 * * * *Every Hour
      0 0 * * *Every day at 00:00
      0 0 * * 1Every monday at 00:00
      + +

      Permissions

      + +

      + Appwrite Functions can be executed using Client or Server SDKs. + Client SDKs must be authenticated with an account that has been granted execution permissions on the function's settings page. + Server SDKs require an API key with the correct scopes. +

      +

      + If your function has a generated or custom domain, executions are not authenticated. + Anyone visiting the configured domains will be considered a guest, so make sure to give `Any` execute permission in order for domain executions to work. + If you need to enforce permissions for functions with a domain, use authentication methods like JWT. +

      + +

      Logs and results

      +

      + You can view the logs your function executions in the Appwrite Console. + Navigate to Functions and click on a function to view its executions. +

      +

      + For security reasons, Appwrite does not store the response of function executions. + If you need to debug, we recommend logging the response in your function code. +

      diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml new file mode 100644 index 000000000..663d4eaf0 --- /dev/null +++ b/app/views/docs/functions-runtimes.phtml @@ -0,0 +1,80 @@ +getParam('events', []); +$runtimes = $this->getParam('runtimes', []); +$runtimes['node-16.0']["cloud"] = true; +$runtimes['node-18.0']["cloud"] = true; +$runtimes['php-8.0']["cloud"] = true; +$runtimes['ruby-3.0']["cloud"] = true; +$runtimes['python-3.9']["cloud"] = true; +$runtimes['dart-2.17']["cloud"] = true; + +$sorted_runtimes = []; + +foreach ($runtimes as $key => $item) { + $name = $item['name']; + + if (!isset($sorted_runtimes[$name])) { + $sorted_runtimes[$name] = []; + } + + $item['version'] = $key; + + $sorted_runtimes[$name]['versions'][] = $item; +} +?> + + +

      + Appwrite Functions supports an extensive list of runtimes to meet your unique tech preferences. + Not all runtimes are available on Appwrite Cloud yet. Check for the Cloud label in each listed runtime to know which ones are available. +

      + +

      Supported Runtimes

      + +

      Below is a list of supported Functions runtimes. The Appwrite team continually adds support for new runtimes.

      + + + + + + + + + + + + + + $runtime): ?> + + + + + + + + + + +
      NameVersionImageArchitectures
      + Function Env. + + escape($key); ?> + + $version): ?> + escape($version['version']); ?>
      + +
      + $version): ?> + + Cloud + + + + $version): ?> + escape($version['image'] ?? ''); ?> + + escape(implode(' / ', $runtime['versions'][0]['supports'] ?? [])); ?>
      \ No newline at end of file diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml index 43fdedb12..0d1f9e026 100644 --- a/app/views/docs/functions.phtml +++ b/app/views/docs/functions.phtml @@ -2,925 +2,67 @@ use Appwrite\Utopia\View; -$events = $this->getParam('events', []); -$runtimes = $this->getParam('runtimes', []); - ?> -

      Appwrite Functions allow you to extend and customize your Appwrite server functionality by executing your custom code. Appwrite can execute your custom code in response to any Appwrite system event like account creation, user login, or document update. You can also schedule your functions or start them manually by triggering your function from an HTTP endpoint using the Appwrite client or server APIs.

      - -

      Appwrite Functions run in a secure, isolated Docker container. By default, Appwrite supports multiple runtimes for different languages that you can use to run your code.

      - -

      Getting Started

      - -

      The quickest way to get started with Appwrite Functions is using the Appwrite CLI. The CLI comes with starter code and some simple commands to quickly create and deploy your functions. Once you have the CLI installed and setup with an Appwrite project, create your first function using:

      - -
      -
      appwrite init function
      -
      - -

      Give your function a name and choose your runtime. This will create a new starter function in the current directory and also add it to your appwrite.json file. Go ahead and deploy your function using :

      - -
      -
      appwrite deploy function
      -
      - -

      You can now head over to your Appwrite Dashboard, navigate to the Function settings and execute your function. You can find the status of your execution under the Logs tab.

      - -

      Feel free to modify and play around with the starter code and use the appwrite deploy command to instantly deploy your changes to the Appwrite server.

      - -

      The following sections will dive deeper into some more terminology and advanced concepts which can be useful when writing your function from scratch.

      - -

      Writing your own Function

      - -

      When writing your own Appwrite Function, you must export the code in certain ways depending on the language. This varies between languages so refer to the examples below.

      - -
        -
      • -

        Node.js

        -
        -
        -
        module.exports = async (req, res) => {
        -  const payload =
        -    req.payload ||
        -    'No payload provided. Add custom data when executing function.';
        -
        -  const secretKey =
        -    req.variables.SECRET_KEY ||
        -    'SECRET_KEY variable not found. You can set it in Function settings.';
        -
        -  const randomNumber = Math.random();
        -
        -  const trigger = req.variables.APPWRITE_FUNCTION_TRIGGER;
        -
        -  res.json({
        -    message: 'Hello from Appwrite!',
        -    payload,
        -    secretKey,
        -    randomNumber,
        -    trigger,
        -  });
        -};
        -
        -

        Installing Dependencies

        -

        Include a package.json file along with your function, and Appwrite handles the rest! The best practice is to make sure that the node_modules folder is not a part of your tarball.

        -
        -
      • -
      • -

        PHP

        -
        -
        -
        <?php
        -
        -return function ($req, $res) {
        -  $payload =
        -    $req['payload'] ?:
        -    'No payload provided. Add custom data when executing function.';
        -
        -  $secretKey =
        -    $req['variables']['SECRET_KEY'] ?:
        -    'SECRET_KEY variable not found. You can set it in Function settings.';
        -
        -  $randomNumber = \mt_rand() / \mt_getrandmax();
        -
        -  $trigger = $req['variables']['APPWRITE_FUNCTION_TRIGGER'];
        -
        -  $res->json([
        -    'message' => 'Hello from Appwrite!',
        -    'payload' => $payload,
        -    'secretKey' => $secretKey,
        -    'randomNumber' => $randomNumber,
        -    'trigger' => $trigger,
        -  ]);
        -};
        -
        -

        Installing Dependencies

        -

        Include a composer.json file along with your function, make sure to require autoload.php from vendor folder, and Appwrite handles the rest!. The best practice is to make sure that the vendor directory is not a part of your tarball.

        -
        -
      • -
      • -

        Python

        -
        -
        -
        import random
        -
        -def main(req, res):
        -  payload = req.payload or 'No payload provided. Add custom data when executing function.'
        -
        -  secretKey = req.variables.get(
        -    'SECRET_KEY',
        -    'SECRET_KEY variable not found. You can set it in Function settings.'
        -  )
        -
        -  randomNumber = random.random()
        -
        -  trigger = req.variables['APPWRITE_FUNCTION_TRIGGER']
        -
        -  return res.json({
        -    'message': 'Hello from Appwrite!',
        -    'payload': payload,
        -    'secretKey': secretKey,
        -    'randomNumber': randomNumber,
        -    'trigger': trigger,
        -  })
        -
        -

        Installing Dependencies

        -

        Include a requirements.txt file with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        Ruby

        -
        -
        -
        def main(req, res)
        -  payload =
        -    !req.payload.empty? ? req.payload :
        -    'No payload provided. Add custom data when executing function.'
        -
        -  secretKey =
        -    req.variables['SECRET_KEY'] ||
        -    'SECRET_KEY variable not found. You can set it in Function settings.'
        -
        -  randomNumber = rand()
        -
        -  trigger = req.variables['APPWRITE_FUNCTION_TRIGGER']
        -
        -  return res.json({
        -    :message => 'Hello from Appwrite!',
        -    :payload => payload,
        -    :secretKey => secretKey,
        -    :randomNumber => randomNumber,
        -    :trigger => trigger,
        -  })
        -end
        -
        -

        Installing Dependencies

        -

        Include a Gemfile with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        Deno

        -
        -
        -
        export default async function (req: any, res: any) {
        -  const payload =
        -    req.payload ||
        -    'No payload provided. Add custom data when executing function.';
        -
        -  const secretKey =
        -    req.variables.SECRET_KEY ||
        -    'SECRET_KEY variable not found. You can set it in Function settings.';
        -
        -  const randomNumber = Math.random();
        -
        -  const trigger = req.variables.APPWRITE_FUNCTION_TRIGGER;
        -
        -  res.json({
        -    message: 'Hello from Appwrite!',
        -    payload,
        -    secretKey,
        -    randomNumber,
        -    trigger,
        -  });
        -};
        -
        -

        Installing Dependencies

        -

        No special steps are required for Deno, Appwrite handles everything!

        -
        -
      • -
      • -

        Dart

        -
        -
        -
        import 'dart:math';
        -import 'dart:async';
        -
        -Future <void> start(final req, final res) async {
        -  final payload =
        -    !req.payload?.isEmpty ? req.payload :
        -    'No payload provided. Add custom data when executing function.';
        -
        -  final secretKey =
        -    req.variables['SECRET_KEY'] ??
        -    'SECRET_KEY variable not found. You can set it in Function settings.';
        -
        -  final randomNumber = new Random().nextDouble();
        -
        -  final trigger = req.variables['APPWRITE_FUNCTION_TRIGGER'];
        -
        -  res.json({
        -    'message': 'Hello from Appwrite!',
        -    'payload': payload,
        -    'secretKey': secretKey,
        -    'randomNumber': randomNumber,
        -    'trigger': trigger,
        -  });
        -}
        -
        -

        Installing Dependencies

        -

        Include a pubspec.yaml file with your function- Appwrite handles the rest!

        -
        -
      • -
      • -

        Swift

        -
        -
        -
        func main(req: RequestValue, res: RequestResponse) throws -> RequestResponse {
        -    let payload = req.payload.isEmpty 
        -        ? "No payload provided. Add custom data when executing function" 
        -        : req.payload
        -    
        -    let secretKey = req.variables["SECRET_KEY"] 
        -        ?? "SECRET_KEY variable not found. You can set it in Function settings."
        -
        -    let randomNumber = Double.random(in: 0...1)
        -
        -    let trigger = req.variables["APPWRITE_FUNCTION_TRIGGER"]
        -
        -    return res.json(data: [
        -        "message": "Hello from Appwrite!",
        -        "payload": payload,
        -        "secretKey": secretKey,
        -        "randomNumber": randomNumber,
        -        "trigger": trigger,
        -    ])
        -}
        -
        -

        With Swift, your entrypoint can be empty since Appwrite automatically infers it from the location of your main() function. Just ensure that your cloud function has a single declaration of main() across your source files.

        -

        Installing Dependencies

        -

        Include a Package.swift file with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        .NET

        -
        -
        -
        public async Task Main(RuntimeRequest req, RuntimeResponse res)
        -{
        -  var payload = (string.IsNullOrEmpty(req.Payload))
        -                ? "No payload provided. Add custom data when executing function."
        -                : req.Payload; 
        -
        -  var secretKey = req.Variables.ContainsKey("SECRET_KEY")
        -                  ? req.Variables["SECRET_KEY"]
        -                  : "SECRET_KEY variable not found. You can set it in Function settings.";
        -
        -  var randomNumber = new Random().NextDouble();
        -
        -  var trigger = req.Variables["APPWRITE_FUNCTION_TRIGGER"];
        -
        -  return res.Json(new() 
        -  {
        -    { "message", "Hello from Appwrite!" },
        -    { "payload", payload },
        -    { "secretKey", secretKey },
        -    { "randomNumber", randomNumber },
        -    { "trigger", trigger },
        -  });
        -}
        -
        -

        Installing Dependencies

        -

        Include a Function.csproj file with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        Kotlin

        -
        -
        -
        import kotlin.random.Random
        -
        -@Throws(Exception::class)
        -fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse {
        -
        -    val payload = if (req.payload.isEmpty()) "No payload provided. Add custom data when executing function." else req.payload
        -
        -    val secretKey = req.variables["SECRET_KEY"] ?: "SECRET_KEY variable not found. You can set it in Function settings."
        -    
        -    val randomNumber = Random.nextDouble(0.0, 1.0)
        -
        -    val trigger = req.variables["APPWRITE_FUNCTION_TRIGGER"]    
        -
        -    return res.json(mapOf(
        -        "message" to "Hello from Appwrite!",
        -        "payload" to payload,
        -        "secretKey" to secretKey,
        -        "randomNumber" to randomNumber,
        -        "trigger" to trigger
        -    ))
        -}
        -
        -

        Installing Dependencies

        -

        Include a deps.gradle file with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        Java

        -
        -
        -
        import java.util.Map;
        -import java.util.HashMap;
        -
        -public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) throws Exception {
        -
        -    String payload = (req.getPayload().isEmpty())
        -                     ? "No payload provided. Add custom data when executing function."
        -                     : req.getPayload();
        -
        -    Map variables = req.getVariables();
        -
        -    String secretKey = variables.containsKey("SECRET_KEY")
        -                       ? variables.get("SECRET_KEY")
        -                       : "SECRET_KEY variable not found. You can set it in Function settings.";
        -
        -    double randomNumber = Math.random();
        -
        -    String trigger = variables.get("APPWRITE_FUNCTION_TRIGGER");
        -
        -    Map response = new HashMap();
        -        response.put("message", "Hello from Appwrite!");
        -        response.put("payload", payload);
        -        response.put("secretKey", secretKey);
        -        response.put("randomNumber", randomNumber);
        -        response.put("trigger", trigger);
        -
        -    return res.json(response);
        -}
        -
        -

        Installing Dependencies

        -

        Include a deps.gradle file with your function, Appwrite handles the rest!

        -
        -
      • -
      • -

        C++

        -
        -
        -
        #include <iostream>
        -#include <string>
        -
        -static RuntimeResponse &main(const RuntimeRequest &req, RuntimeResponse &res) {
        -
        -    std::string payload = req.payload.empty() ? 
        -                          "No payload provided. Add custom data when executing function." : 
        -                          req.payload;
        -
        -    std::string secretKey = req.variables.get("SECRET_KEY", "SECRET_KEY variable not found. You can set it in Function settings.").asString();
        -
        -    double randomNumber = ((double) rand() / (RAND_MAX));
        -
        -    std::string trigger = req.variables["APPWRITE_FUNCTION_TRIGGER"].asString();
        -
        -    Json::Value response;
        -    response["message"] = "Hello from Appwrite!";
        -    response["payload"] = payload;
        -    response["secretKey"] = secretKey;
        -    response["randomNumber"] = randomNumber;
        -    response["trigger"] = trigger;
        -    
        -    return res.json(response);
        -}
        -
        -

        Installing Dependencies

        -

        Include a CMakeLists.txt file with your function, Appwrite handles the rest!

        -
        -
      • -
      - - -

      When your function is called, you receive two parameters, a request and a response object. The request object contains all data that was sent to the function including function variables. A schema of the request object can be found below and is the same for all runtimes.

      - - - - - - - - - - - - - - - - - - - - - - -
      PropertyDescription
      headersAn object containing all the request headers.
      payloadA JSON string containing the data when you created the execution.
      variablesAn object containing all the function variables. This includes variables automatically added by Appwrite.
      - -

      The response object has two functions, send() and json() that can be used to send data back to the client. The types and implementation of these functions vary depending on runtime due to all languages being slightly different. You can check out implementation in the specific languages to learn more about them. The schema of the response object can be found below:

      - - - - - - - - - - - - - - - - - - -
      FunctionDescription
      send(text, status)Function to return a text response. Status code defaults to 200
      json(obj, status)Function to return a JSON response. Status code defaults to 200
      - -

      Create your Function

      - -

      Before you can deploy your function, you will need to create a new function from your Appwrite project's dashboard. Access the Function settings from your project's left navigation panel. Click the 'Add Function' button and choose a function name and runtime. In your Functions settings page, you can also set your function event triggers, CRON schedule, and set secure function variables for your function.

      - -

      Deploy Your Function

      - -

      Once you've written your function, you can now deploy it using the Appwrite CLI, the Appwrite Server API or manually from the Appwrite console.

      - -
        -
      • -

        Unix

        - -
        -
        appwrite functions createDeployment \
        -    --functionId=6012cc93d5a7b \
        -    --activate=true \
        -    --entrypoint="index.js" \
        -    --code="."
        -
        -
      • -
      • -

        CMD

        - -
        -
        appwrite functions createDeployment ^
        -    --functionId=6012cc93d5a7b ^
        -    --activate=true ^
        -    --entrypoint="index.js" ^
        -    --code="."
        -
        -
      • -
      • -

        PowerShell

        +

        + Appwrite Functions unlock limitless potential for developers to extend Appwrite with code snippets. + Appwrite Functions are user-defined functions that can start small and scale big, deploying automatically from source control. + These Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, and scheduled executions. + Each function will have its own URL, execute in its own isolated container, and have its own configurable environment variables and permissions. +

        -
        -
        appwrite functions createDeployment `
        -    --functionId=6012cc93d5a7b `
        -    --activate=true `
        -    --entrypoint="index.js" `
        -    --code="."
        -
        -
      • -
      - -

      The command above accepts three parameters:

      - - - - - - - - - - - - - - - - - - - - - - -
      NameDescription
      functionIdThe ID of the Function you created in the previous step. You can find your function ID on your function page in your project dashboard.
      entrypointThe file name of your custom code that is executed when the function is triggered.
      codePath to your function tarball. When used with the Appwrite CLI, simply pass the path to your code directory, and the CLI will automatically package your code.
      - -

      You can also create new code deployments using the Appwrite server API

      - -

      Manual Deployment

      -

      You can also upload your functions to be deployed using the Appwrite console. The example below shows a simple Node.JS function, but the same idea applies to any other language.

      - -
      -
      .
      -├── package.json
      -└── index.js
      -
      -
      - -

      First, navigate inside the folder that contains your dependency file. Package your code files into the .tar.gz format with this tar command:

      - -
        -
      • -

        Unix

        - -
        -
        tar -czf code.tar.gz --exclude code.tar.gz .
        -
        -
      • -
      • -

        CMD

        - -
        -
        tar -czf code.tar.gz --exclude code.tar.gz .
        -
        -
      • -
      • -

        PowerShell

        - -
        -
        tar -czf code.tar.gz --exclude code.tar.gz .
        -
        -
      • -
      - -

      Next, navigate to your Appwrite console and upload the function.

      - -
        -
      1. Navigate to the function you want to deploy.
      2. -
      3. Click Create deployment.
      4. -
      5. Select the Manual tab.
      6. -
      7. Input the entry point of your function under Entrypoint. For the example above, it would be index.js.
      8. -
      9. Upload code.tar.gz.
      10. -
      11. Select Activate deployment after build to use your new function.
      12. -
      13. Click Create to deploy your function.
      14. -
      - - -

      Builds

      -

      Deployments needs to be built before they can be activated. This is automatically done after creating a deployment and the time taken can vary depending on the runtime.

      - -

      If a build fails for any reason, the deployment's status is set to failed and you won't be able to activate it. You can however retry a build if you think it was caused by an external factor using the Retry Button on the Appwrite Dashboard or Retry Build endpoint with the buildId from the deployment.

      - -

      To find more details about a deployment and reasons for its failure, you can use the Get Deployment endpoint using the deploymentId.

      - -

      Deployments that have been built successfully are marked as ready and can be activated and executed.

      - -
      -

      Build Times

      -

      Compiled runtimes such as Rust and Swift take much longer to build however yield better performance over their interpreted counterparts such as Node.

      -
      - -

      Execute

      - -

      Besides setting a schedule or allowing your function to listen to Appwrite's system events, you can also manually execute your cloud functions from your Appwrite console or API.

      +

      Getting Started

      +

      + Appwrite Functions let you build anything you can imagine, but this flexibility makes it difficult to know where to start. + Start exploring by cloning one of the quick start templates or using a template with pre-built integration to quickly implement features. +

      setParam('srcLight', '/images-ee/docs/functions-light.png') - ->setParam('srcDark', '/images-ee/docs/functions-dark.png') - ->setParam('alt', 'Function settings page.') - ->setParam('description', 'Function settings page.') + ->setParam('srcLight', '/images-ee/docs/functions-starter-light.png') + ->setParam('srcDark', '/images-ee/docs/functions-starter-dark.png') + ->setParam('alt', '"Create Function" page.') + ->setParam('description', '"Create Function" page.') ->render(); ?> -

      To execute a function from the Appwrite console, click the Execute Now button on your function's overview page. To execute a function from the API, send a POST request to the function execution endpoint.

      - -

      The function execution endpoint is available from both Appwrite client and server APIs. To execute your function from the server API, you need an API key with 'execution.write' scope.

      - -

      Executing the function from the client API requires the current user to have execution permission for the function. You can change the execution permission from the function's settings page in the Appwrite console, by default no user, team, or role has this permission.

      - -
        -
      • -

        Web

        -
        -
        import { Client, Functions } from "appwrite";
        -
        -const client = new Client()
        -    .setEndpoint('https://cloud.appwrite.io/v1')
        -    .setProject('[PROJECT_ID]');
        -
        -const functions = new Functions(client);
        -
        -let promise = functions.createExecution('[FUNCTION_ID]');
        -
        -promise.then(function (response) {
        -    console.log(response); // Success
        -}, function (error) {
        -    console.log(error); // Failure
        -});
        -
        -
      • -
      • -

        Flutter

        - -
        -
        import 'package:appwrite/appwrite.dart';
        -
        -void main() async {
        -    final client = Client()
        -        .setEndpoint('https://cloud.appwrite.io/v1')
        -        .setProject('[PROJECT_ID]');
        -
        -    final functions = Functions(client);
        -
        -    final execution = await functions.createExecution(
        -        functionId: '[FUNCTION_ID]'
        -    );
        -}
        -
        -
      • -
      • -

        Android

        - -
        -
        import io.appwrite.Client
        -import io.appwrite.services.Functions
        -
        -suspend fun main() {
        -    val client = Client(applicationContext)
        -        .setEndpoint("https://cloud.appwrite.io/v1")
        -        .setProject("[PROJECT_ID]")
        -
        -    val functions = Functions(client)
        -
        -    val execution = functions.createExecution(
        -        functionId = "[FUNCTION_ID]"
        -    )
        -}
        -
        -
      • -
      • -

        Apple

        - -
        -
        import Appwrite
        -
        -func main() async throws {
        -    let client = Client()
        -      .setEndpoint("https://cloud.appwrite.io/v1")
        -      .setProject("[PROJECT_ID]")
        -
        -    let functions = Functions(client)
        -
        -    let execution = try await functions.createExecution(
        -        functionId: "[FUNCTION_ID]"
        -    )
        -}
        -
        -
      • -
      • -

        GraphQL

        - -
        -
        mutation {
        -    functionsCreateExecution(functionId: "[FUNCTION_ID]") {
        -        _id
        -        statusCode
        -        response
        -        stdout
        -        stderr
        -        duration
        -    }
        -}
        -
        -
      • -
      - -

      Scheduled Execution

      -

      Appwrite supports scheduled function executions. You can schedule executions using cron expressions in the settings of your function. Cron supports recurring executions as frequently as every minute.

      - -

      Here are some cron expressions for common intervals.

      - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Cron ExpressionSchedule
      */15 * * * *Every 15 minutes
      0 * * * *Every Hour
      0 0 * * *Every day at 00:00
      0 0 * * 1Every monday at 00:00
      - -

      Abuse and Limits

      - -

      Appwrite Functions can be executed using Client or Server SDKs. Client SDKs must be authenticated with an account that has been granted execution permissions on the function's settings page. Server SDKs require an API key with the correct scopes.

      - -

      The Functions Service APIs are rate limited to 60 calls per minute per account when using a Client SDK. Learn more about rate limiting. The response size of a Cloud Function is limited to 1MB. Responses larger than 1MB should be handled using Appwrite's Databases or Storage service.

      - -

      Each execution has a default timeout of 15 seconds to prevent hanging functions from blocking resources. This timeout can be configured per function on a function's settings page or in appwrite.json for up to 900 seconds.

      - -

      Ignore Files

      - -

      Library folders such as node_modules or vendor should not be included in your tarball since these dependencies will be installed during your function's build process. Similarly, you should not include files containing secrets in your deployment. You can use the Appwite CLI's file ignoring feature to exclude specific files from a deployment.

      - -

      You can use the ignore property in your appwrite.json file to specify which files and folders should be ignored. This value must be an array of paths, as seen in the example below:

      - -
      -
      {
      -    ...
      -    "functions": [
      -        {
      -            "$id": "6213b58cb21dda6c3263",
      -            "name": "My Awesome Function",
      -            "runtime": "node-17.0",
      -            "path": "My Awesome Function",
      -            "entrypoint": "src/index.js",
      -            "ignore": [ "node_modules", ".env" ]
      -        },
      -        ...
      -    ],
      -}
      -
      - -

      The example configuration above would not deploy the folder node_modules and the file .env.

      - -

      Alternatively, you can add a .gitignore file into your function folder and Appwrite CLI will ignore files specified in there. Keep in mind that if present, the ignore configuration in appwrite.json will nullify your ignore file.

      - -

      If you need to use a .gitignore file for your version control but don't want the Appwrite CLI to use it, you can specify the ignore key in appwrite.json to be an empty array.

      - -

      Supported Runtimes

      - -

      Appwrite provides multiple code runtimes to execute your custom functions. Each runtime uses a Docker image tied to a specific language version to provide a safe, isolated playground to run your team's code.

      - -

      Below is a list of supported Cloud Functions runtimes. The Appwrite team continually adds support for new runtimes.

      - - - - - - - - - - - - $runtime): ?> - - - - - - - - -
      NameImageArchitectures
      Function Env.escape($key); ?> escape($runtime['image'] ?? ''); ?> escape(implode(' / ', $runtime['supports'] ?? [])); ?>
      - -

      By default, the following runtimes are enabled: node-16.0, php-8.0, python-3.9, ruby-3.0, and dart-2.17.

      - -

      Function Variables

      - -

      Function variables supplied by Appwrite in addition to your own defined function variables that you can access from your function code. These variables give you information about your execution runtime environment.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      NameDescription
      - APPWRITE_FUNCTION_ID - Your function's unique ID.
      - APPWRITE_FUNCTION_NAME - Your function's name.
      - APPWRITE_FUNCTION_DEPLOYMENT - Your function's code deployment unique ID.
      - APPWRITE_FUNCTION_TRIGGER - Either 'event' when triggered by one of the selected scopes, 'http' when triggered by an HTTP request or the Appwrite Console, or 'schedule' when triggered by the cron schedule.
      - APPWRITE_FUNCTION_RUNTIME_NAME - Your function runtime name. Can be any of Appwrite supported execution runtimes.
      - APPWRITE_FUNCTION_RUNTIME_VERSION - Your function runtime version.
      - APPWRITE_FUNCTION_EVENT - Your function event name. This value is available only when your function trigger is 'event.' This variable value can be any of Appwrite system events.
      - APPWRITE_FUNCTION_EVENT_DATA - Your function event payload. This value is available only when your function trigger is 'event'. This variable value contains a string in JSON format with your specific event data.
      - APPWRITE_FUNCTION_DATA -

      version >= 0.8.0

      -
      Your function's custom execution data. This variable's value contains a string in any format. If the custom data is in JSON FORMAT, it must be parsed inside the function code. Note that this variable can be set only when triggering a function using the SDK or HTTP API and the Appwrite Dashboard.
      - APPWRITE_FUNCTION_PROJECT_ID -

      version >= 0.8.0

      -
      Your function's project ID.
      - APPWRITE_FUNCTION_USER_ID -

      version >= 0.8.0

      -
      The userId of the user that triggered your function's execution. Executions triggered in the Appwrite console will be prepended with "admin-".
      - APPWRITE_FUNCTION_JWT -

      version >= 0.8.0

      -
      A JSON Web Token generated for the user that executes your function.
      - APPWRITE_FUNCTION_EVENT_PAYLOAD -

      version < 0.8.0 (deprecated)

      -
      Your function event payload. Deprecated in favor of APPWRITE_FUNCTION_EVENT_DATA in version 0.8.0.
      - APPWRITE_FUNCTION_ENV_NAME -

      version < 0.8.0 (deprecated)

      -
      Your function environment name. Can be any of Appwrite supported execution environments.
      - APPWRITE_FUNCTION_ENV_VERSION -

      version < 0.8.0 (deprecated)

      -
      Your function environment version.
      - -
      -

      Using an Appwrite SDK in Your Function

      -

      Appwrite Server SDKs require an API key, an endpoint, and a project ID for authentication. Appwrite passes in your project ID with the function variable APPWRITE_FUNCTION_PROJECT_ID, but not the endpoint and API key. If you need to use a Server SDK, you will need to add function variables for your endpoint and API key in the Settings tab of your function.

      -

      If you are running a local Appwrite instance, you will need to pass in the machine's public IP instead of 'https://localhost/v1'. Localhost inside the function's runtime container is not the same as localhost of your machine.

      -
      - -

      Appwrite SDKs in Functions

      - -

      You can integrate Appwrite Functions with other Appwrite services by using the appropriate Server SDK for your runtime. You can find starter code for your function's runtime in the Appwrite Function Starter repository.

      - -

      To initialize a Server SDK in a function, you need to provide your Appwrite endpoint and an API key in the Variables tab of your Function. The ID of your Appwrite project is passed in automatically as APPWRITE_FUNCTION_PROJECT_ID.

      - -

      Monitor & Debug

      - -

      You can monitor your function execution usage stats and logs from your Appwrite console. To access your functions usage stats and logs, click the Usage tab in your function dashboard.

      - -

      The usage screen in your console will allow you to track the number of execution and your function CPU usage time. You can also review a detailed log of your function execution history, including the function exit code, output log, and error log.

      - -setParam('srcLight', '/images-ee/docs/functions-monitor-light.png') - ->setParam('srcDark', '/images-ee/docs/functions-monitor-dark.png') - ->setParam('alt', 'Function usage and logs tracking.') - ->setParam('description', 'Function usage and logs tracking.') - ->render(); -?> - -

      Demos & Examples

      - -

      There are many Cloud Function demos and examples created by the Appwrite team and community in multiple coding languages. These examples are available at our examples repository on GitHub. You can also submit your examples by submitting a pull-request.

      +

      Explore Features

      +

      + Appwrite Functions use familiar HTTP concepts, so you can learn quickly and gain transferable skills. +

      +

      +Learn more about developing functions +

      + +

      + Appwrite Functions can be deployed automatically from Git, through the Appwrite CLI, or be uploaded manually. + Develop and deploy with the workflow you're already comfortable with. +

      +

      +Learn more about deploying functions +

      + +

      + Appwrite Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, and scheduled executions. + Explore how Appwrite Functions can be invoked. +

      +

      +Learn more about executing functions +

      + +

      + Appwrite supports a growing list of 10+ runtimes. + Avoid adding additional complexity to your codebase by coding in languages you already use and love. +

      +

      +Learn more about using function runtimes +

      + +

      + Like to learn from examples? + Here's a curated list of examples that showcase Appwrite Functions' capabilities. +

      +

      +Learn more about using function examples +

      \ No newline at end of file diff --git a/app/views/docs/getting-started-for-android.phtml b/app/views/docs/getting-started-for-android.phtml index 74d35cbf0..d737cb6e3 100644 --- a/app/views/docs/getting-started-for-android.phtml +++ b/app/views/docs/getting-started-for-android.phtml @@ -19,7 +19,7 @@ $androidVersion = (isset($versions['android'])) ? $versions['android'] : '';

      Add your Android Platform

      -

      To init your SDK and start interacting with Appwrite services, you need to add a new Android platform to your project. To add a new platform, go to your Appwrite console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      +

      To init your SDK and start interacting with Appwrite services, you need to add a new Android platform to your project. To add a new platform, go to your Appwrite Console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      From the options, choose to add a new Android platform and add add your app name and package name, your package name is generally the applicationId in your app-level build.gradle file. By registering your new app platform, you are allowing your app to communicate with the Appwrite API.

      @@ -40,7 +40,7 @@ $androidVersion = (isset($versions['android'])) ? $versions['android'] : '';

      OAuth Callback

      -

      In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

      +

      In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the <application> tag, along side the existing <activity> tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite Console.

      escape('
      diff --git a/app/views/docs/getting-started-for-apple.phtml b/app/views/docs/getting-started-for-apple.phtml
      index 88e7d102a..1be6fa026 100644
      --- a/app/views/docs/getting-started-for-apple.phtml
      +++ b/app/views/docs/getting-started-for-apple.phtml
      @@ -19,7 +19,7 @@ $appleVersion = $versions['apple'] ?? '';
       
       

      Add your Apple Platform

      -

      To init your SDK and start interacting with Appwrite services, you need to add a new Apple platform to your project. To add a new platform, go to your Appwrite console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      +

      To init your SDK and start interacting with Appwrite services, you need to add a new Apple platform to your project. To add a new platform, go to your Appwrite Console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      From the options, choose to add a new Apple platform, select the iOS, macOS, watchOS or tvOS tab and add your app name and bundle identifier, Your bundle identifier can be found at the top of the General tab in your project settings, or in your Info.plist file. By registering your new app platform, you are allowing your app to communicate with the Appwrite API.

      @@ -64,7 +64,7 @@ $appleVersion = $versions['apple'] ?? '';

      OAuth Callback

      -

      In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your `Info.plist`

      +

      In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your Info.plist.

      escape('CFBundleURLTypes
      @@ -83,7 +83,7 @@ $appleVersion = $versions['apple'] ?? '';
       ');?>
      -

      If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

      +

      If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

      escape('
      diff --git a/app/views/docs/getting-started-for-flutter.phtml b/app/views/docs/getting-started-for-flutter.phtml
      index 6bd614873..47355fa81 100644
      --- a/app/views/docs/getting-started-for-flutter.phtml
      +++ b/app/views/docs/getting-started-for-flutter.phtml
      @@ -19,7 +19,7 @@ $version = (isset($versions['flutter'])) ? $versions['flutter'] : '';
       
       

      Add your Flutter Platform

      -

      To init your SDK and start interacting with Appwrite services, you need to add a new Flutter platform to your project. To add a new platform, go to your Appwrite console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      +

      To init your SDK and start interacting with Appwrite services, you need to add a new Flutter platform to your project. To add a new platform, go to your Appwrite Console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.

      From the options, choose to add a new Flutter platform and add your app credentials. Appwrite Flutter SDK currently supports building apps for Android, iOS, Linux, Mac OS, Web and Windows.

      @@ -29,7 +29,7 @@ $version = (isset($versions['flutter'])) ? $versions['flutter'] : '';

      For Android first add your app name and package name, Your package name is generally the applicationId in your app-level build.gradle file. By registering your new app platform, you are allowing your app to communicate with the Appwrite API.

      -

      In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in you project settings screen in your Appwrite console.

      +

      In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in you project settings screen in your Appwrite Console.

      escape('
      diff --git a/app/views/docs/getting-started-for-server.phtml b/app/views/docs/getting-started-for-server.phtml
      index e5ede12fe..b6dd13ab4 100644
      --- a/app/views/docs/getting-started-for-server.phtml
      +++ b/app/views/docs/getting-started-for-server.phtml
      @@ -109,7 +109,7 @@ $swiftVersion = $versions['swift'] ?? '';
       
       

      Create Your First Appwrite Project

      -

      Go to your new Appwrite console and click the icon in the top navigation header or on the 'Create Project' button on your console homepage. Choose a name for your project and click create to get started.

      +

      Go to your new Appwrite Console and click the icon in the top navigation header or on the 'Create Project' button on your console homepage. Choose a name for your project and click create to get started.

      Authentication

      @@ -228,7 +228,7 @@ let client = Client()
      using Appwrite;
       
       var client = new Client()
      -  .SetEndpoint("http://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
      +  .SetEndpoint("https://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
         .SetProject("[PROJECT_ID]")               // Your project ID
         .SetKey("919c2db5d4...a2a3346ad2");                        // Your secret API Key
      @@ -399,7 +399,7 @@ let client = Client()
      using Appwrite;
       
       var client = new Client()
      -  .SetEndpoint("http://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
      +  .SetEndpoint("https://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
         .SetProject("[PROJECT_ID]")               // Your project ID
         .SetJWT("919c2db5d4...a2a3346ad2");                        // Your secret JWT
       
      @@ -763,7 +763,7 @@ using Appwrite.Services; using Appwrite.Models; var client = new Client() - .SetEndpoint("http://cloud.appwrite.io/v1") // Your Appwrite Endpoint + .SetEndpoint("https://cloud.appwrite.io/v1") // Your Appwrite Endpoint .SetProject("[PROJECT_ID]") // Your project ID .SetKey("cd868db89"); // Your secret API key diff --git a/app/views/docs/getting-started-for-web.phtml b/app/views/docs/getting-started-for-web.phtml index d7ec5bc2a..6dd6c4fd4 100644 --- a/app/views/docs/getting-started-for-web.phtml +++ b/app/views/docs/getting-started-for-web.phtml @@ -21,13 +21,13 @@ $demos = $platform['demos'] ?? [];

      Add Your Web Platform

      -

      To init your SDK and interact with Appwrite services, you need to add a web platform to your project. To add a new platform, go to your Appwrite console, choose the project you created in the step before and click the 'Add Platform' button.

      +

      To init your SDK and interact with Appwrite services, you need to add a web platform to your project. To add a new platform, go to your Appwrite Console, choose the project you created in the step before and click the 'Add Platform' button.

      From the options, choose to add a web platform and add your client app hostname. By adding your hostname to your project platform, you are allowing cross-domain communication between your project and the Appwrite API. Only web apps hosted on domains specified in a web platform will be able to make requests to your Appwrite instance, preventing unwanted access from malicious actors.

      Web platforms allow wildcard hostnames through a * character. The wildcard character can be applied anywhere in a hostname, both *.example.com and prod.*.example.com are valid examples. Avoid using wildcards unless necessary to keep your Appwrite project secure.

      - +

      Get Appwrite Web SDK

      diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 3554cba88..0490265d6 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -68,7 +68,6 @@ $cols = [
    • Functions
    • Localization
    • Avatars
    • -
    • Health
    @@ -81,18 +80,43 @@ $cols = [
  • Storage
  • Authentication
  • -
  • Functions
  • +
  • + Functions + +
  • +
  • + Migrations + +
  • @@ -107,6 +131,7 @@ $cols = [
  • Pagination
  • Webhooks
  • Custom Domains
  • +
  • Email Templates
  • Response Codes
  • Rate Limits
  • diff --git a/app/views/docs/keys.phtml b/app/views/docs/keys.phtml index cfff198a4..a63fff508 100644 --- a/app/views/docs/keys.phtml +++ b/app/views/docs/keys.phtml @@ -2,7 +2,7 @@ $scopes = $this->getParam('scopes', ); ?> -

    Using your API Keys, you can access Appwrite services using the SDK of your choice. To create a new API key, go to your API keys tab in your project setting using your Appwrite console and click the 'Add API Key' button.

    +

    Using your API Keys, you can access Appwrite services using the SDK of your choice. To create a new API key, go to your API keys tab in your project setting using your Appwrite Console and click the 'Add API Key' button.

    When adding a new API Key, you can choose which scope to grant your application. If you need to replace your API Key, create a new key, update your app credentials and, once ready, delete your old key.

    diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml new file mode 100644 index 000000000..6c012e1ef --- /dev/null +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -0,0 +1,34 @@ +

    + If you're moving your projects from Appwrite Cloud to self-hosted, we've got you covered. + Migrations makes it as easy as a couple clicks to move all of your Appwrite Cloud project data to a self-hosted instance. +

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    3. Your self-hosted Appwrite project must be accessible from the internet for the migration to work.
    4. +
    5. Migrations are non-destructive. No data will be deleted or lost in the source project.
    6. +
    + +

    Migrating to Self-hosted from Cloud

    + +

    + To begin migrating to Appwrite Self-hosted, make sure to read the migrations overview + and things to keep in mind sections above. +

    + +

    Steps in Cloud Console

    +
      +
    1. Navigate to your Appwrite Cloud Console and click on the Migrations tab in Project Settings.
    2. +
    3. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
    4. +
    5. Optionally, tell us about why you're moving to self-hosted.
    6. +
    7. After clicking Continue, you'll be redirected to your self-hosted project to complete the process.
    8. +
    + +

    Steps in Self-hosted Console

    +
      +
    1. Once redirected to your self-hosted server, you'll be prompted to select a project. If you have multiple organizations, you will also be asked to pick one. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to begin the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-cloud-to-self-hosted.phtml b/app/views/docs/migrations-cloud-to-self-hosted.phtml new file mode 100644 index 000000000..801d93c0e --- /dev/null +++ b/app/views/docs/migrations-cloud-to-self-hosted.phtml @@ -0,0 +1,34 @@ +

    + Moving to a self-hosted instance? We've got you covered. + Migrations makes it as easy as a couple clicks to move all of your Appwrite Cloud project data to a self-hosted instance. +

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    3. Your self-hosted Appwrite project must be accessible from the internet for the migration to work.
    4. +
    5. Migrations are non-destructive. No data will be deleted or lost in the source project.
    6. +
    + +

    Migrating to Self-hosted from Cloud

    + +

    + To begin migrating to Appwrite Self-hosted, make sure to read the migrations overview + and things to keep in mind sections above. +

    + +

    Steps on Your Cloud Project

    +
      +
    1. Navigate to your Appwrite Cloud Console and click on the Migrations tab.
    2. +
    3. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
    4. +
    5. Optionally, tell us about why you're moving to self-hosted.
    6. +
    7. After clicking Continue, you'll be directed back to your self-hosted project to complete the process.
    8. +
    + +

    Steps on Your Self-hosted Project

    +
      +
    1. Once redirected to your self-hosted project, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml new file mode 100644 index 000000000..2c351d599 --- /dev/null +++ b/app/views/docs/migrations-firebase.phtml @@ -0,0 +1,154 @@ +

    + Moving your project from Firebase to Appwrite? + Appwrite Migrations can help you streamline the process. + + Here's what you need to know to get started. +

    + +

    Things to keep in mind

    + +
      +
    1. Appwrite will not incur usage charges during migrations, but Firebase may still incur service charges.
    2. +
    3. Appwrite Migrations only supports Firestore as a database source. Realtime Database is currently not supported.
    4. +
    5. At the moment only top level document migration is supported. Nested documents will not be migrated automatically.
    6. +
    7. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    8. +
    9. Functions are not automatically migrated because of syntax and runtime differences.
    10. +
    + +

    Migrating to Appwrite from Firebase

    +

    + To begin migrating to Appwrite make sure to read the migration overview + and things to keep in mind sections above. +

    + +
      +
    1. + Create a new project and click on the Migrations tab in Project Settings. +
    2. +
    3. + Click on the Create Migration button and select Firebase as your source. +
    4. +
    5. + Navigate to your Firebase console. +
    6. +
    7. + Click the gear icon to access your Project Settings. +
    8. +
    9. + Click on Service Accounts, then click on the Manage service account permissions link redirecting you to the Google Cloud Console. +
    10. +
    11. + Click on Create Service Account, give it a name, id and description you want, then click Continue. +
    12. +
    13. + Next you'll be prompted to grant the service account roles. You need to grant the following roles. +
    14. + + + + + + + + + + + + + + + + + +
      RoleReason
      Firebase ViewerRead access to your entire Firebase project including Database and Storage.
      Identity Toolkit ViewerRead access to your users including their hash config.
      +
    15. If you prefer to create a custom role, you can use the following permissions.
    16. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      PermissionReason
      datastore.databases.getRead access to your Firestore database.
      datastore.databases.listRead access to your Firestore database.
      datastore.entities.getRead access to your Firestore database's documents.
      datastore.entities.listRead access to your Firestore database's documents.
      datastore.indexes.getRead access to your Firestore database's indexes.
      datastore.indexes.listRead access to your Firestore database's indexes.
      firebaseauth.configs.getRead access to your Firebase project's authentication configs.
      firebaseauth.configs.getHashConfigRead access to your Firebase project's authentication configs including hash salt.
      firebaseauth.configs.getSecretRead access to your Firebase project's authentication configs including secret.
      firebaseauth.users.getRead access to your Firebase project's users.
      identitytoolkit.tenants.getRead access to your Firebase project's users.
      identitytoolkit.tenants.listRead access to your Firebase project's users.
      storage.buckets.getRead access to your Firebase project's storage buckets.
      storage.buckets.listRead access to your Firebase project's storage buckets.
      storage.objects.getRead access to your Firebase project's storage objects.
      storage.objects.listRead access to your Firebase project's storage objects.
      +
    17. + Click Done to create the service account. After that you'll be redirected back to the service accounts page. Select the service account you just created and click Keys. +
    18. +
    19. + Click Add Key and select Create new key. Select JSON as the key type and click Create. This will download a JSON file to your computer. +
    20. +
    21. + Upload the JSON file to Appwrite and follow the migration wizard. +
    22. +
    23. + After completing the migration wizard, migration will begin. Return to step 4 of the migration steps. +
    24. +
    25. + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
    26. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml new file mode 100644 index 000000000..9040dafa1 --- /dev/null +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -0,0 +1,38 @@ +

    + If you're moving your self-hosted projects to Appwrite Cloud, we've got your back. + Migrations makes it as easy as a couple clicks to move all of your self-hosted project data to a Cloud instance. +

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset $createdAt and $updatedAt timestamps to the date of the migration.
    2. +
    3. Your self-hosted Appwrite project must be accessible from the internet for the migration to work.
    4. +
    5. Migrations are non-destructive. No data will be deleted or lost in the source project.
    6. +
    + +

    Migrating to Cloud from Self-hosted

    +

    + To begin migrating to self-hosted, make sure to read the migration overview + and things to keep in mind sections above. +

    + +

    Steps in Self-hosted Console

    + +
      +
    1. Navigate to your self-hosted project's console and click on the Migrations tab in Project Settings.
    2. +
    3. Click Deploy to cloud, and you will be redirected to Appwrite Cloud.
    4. +
    5. You will complete the migration on Appwrite Cloud.
    6. +
    + +

    Steps in Cloud Console

    +
      +
    1. Once redirected to Appwrite Cloud, you'll be prompted to select a project. If you have multiple organizations, you will also be asked to pick one. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    + +
    +

    Keep in mind

    +

    Your Self-hosted instance will generate a API Key in the background to pass to Cloud. You can revoke this key after the migration process is complete.

    +
    \ No newline at end of file diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml new file mode 100644 index 000000000..7558fe9b5 --- /dev/null +++ b/app/views/docs/migrations-nhost.phtml @@ -0,0 +1,64 @@ +

    + Moving your project from NHost to Appwrite? + Appwrite Migrations can help you streamline the process. + + Here's what you need to know to get started. +

    + +

    Things to keep in mind

    + +
      +
    1. Appwrite will not incur usage charges during migrations, but NHost may still incur service charges.
    2. +
    3. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
    4. +
    5. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    6. +
    7. Functions are not automatically migrated because of syntax and runtime differences.
    8. +
    + +

    Migrating to Appwrite from NHost

    +

    + To begin migrating to Appwrite make sure to read the migration overview + and things to keep in mind sections above. +

    + +
      +
    1. + Create a new project and click on the Migrations tab in Project Settings. +
    2. +
    3. + Click on the Create Migration button and select NHost as your source. +
    4. +
    5. + Enter the credentials following the instructions below and click Next. +
    6. +
    7. + Select the resources you want to migrate and finally click Start migration to begin the migration process. +
    8. +
    9. + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
    10. +
    + +

    NHost Credentials

    +

    +Enter all the following credentials from your NHost project. +

    +
      +
    1. + Region - The region your NHost project is hosted in. This can be found in your NHost project environment variables as NHOST_REGION. +
    2. +
    3. + Subdomain - The subdomain of your NHost project. This can be found in your NHost project environment variables as NHOST_SUBDOMAIN. +
    4. +
    5. + Database - The name of your NHost database. This can be found in your NHost project Database settings. +
    6. +
    7. + Username - The username of your NHost database. This can be found in your NHost project Database settings. +
    8. +
    9. + Password - The password of your NHost database. You set this when you created your NHost project, if you don't remember it you can reset it from your NHost project Database settings. +
    10. +
    11. + Admin Secret - The admin secret of your NHost project. This can be found in your NHost project environment variables as NHOST_ADMIN_SECRET. We use this to transfer your NHost files to Appwrite. +
    12. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-self-hosted-to-cloud.phtml b/app/views/docs/migrations-self-hosted-to-cloud.phtml new file mode 100644 index 000000000..5cfee4cb8 --- /dev/null +++ b/app/views/docs/migrations-self-hosted-to-cloud.phtml @@ -0,0 +1,38 @@ +

    + Making the move to Appwrite Cloud? We've got your back. + Migrations makes it as easy as a couple clicks to move all of your self-hosted project data to a Cloud instance. +

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset $createdAt and $updatedAt timestamps to the date of the migration.
    2. +
    3. Your self-hosted Appwrite project must be accessible from the internet for the migration to work.
    4. +
    5. Migrations are non-destructive. No data will be deleted or lost in the source project.
    6. +
    + +

    Migrating to Self-hosted from Cloud

    +

    + To begin migrating to self-hosted, make sure to read the migration overview + and things to keep in mind sections above. +

    + +

    Steps on Your Self-hosted Project

    + +
      +
    1. Navigate to your self-hosted project's console and click on the Migrations tab.
    2. +
    3. Click Deploy to cloud, you will be redirected to Appwrite Cloud.
    4. +
    5. You will complete the migration on Appwrite Cloud.
    6. +
    + +

    Steps on Your Cloud Project

    +
      +
    1. Once redirected to Appwrite Cloud, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    + +
    +

    Keep in mind

    +

    Your Self-hosted instance will generate a API Key in the background to pass to Cloud. You can revoke this key after the migration process is complete.

    +
    \ No newline at end of file diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml new file mode 100644 index 000000000..8ff4a7bca --- /dev/null +++ b/app/views/docs/migrations-supabase.phtml @@ -0,0 +1,65 @@ +

    + Moving your project from Supabase to Appwrite? + Appwrite Migrations can help you streamline the process. + + Here's what you need to know to get started. +

    + +

    Things to keep in mind

    + +
      +
    1. Appwrite will not incur usage charges during migrations, but Supabase may still incur service charges.
    2. +
    3. Appwrite's Databases services supports a different set of features as PostgreSQL. Some features like advanced indexes, Postgres functions and scheduling will not be migrated.
    4. +
    5. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    6. +
    7. Functions are not automatically migrated because of syntax and runtime differences.
    8. +
    + +

    Migrating to Appwrite from Supabase

    +

    + To begin migrating to Appwrite make sure to read the migration overview + and things to keep in mind sections above. +

    + +
      +
    1. + Create a new project and click on the Migrations tab in Project Settings. +
    2. +
    3. + Click on the Create Migration button and select Supabase as your source. +
    4. +
    5. + Enter the credentials following the instructions below and click Next. +
    6. +
    7. + Select the resources you want to migrate and finally click Start migration to begin the migration process. +
    8. +
    9. + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
    10. +
    + +

    Credentials

    + +

    Enter all the following credentials from your Supabase project.

    + +
      + +
    1. + Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. +
    2. +
    3. + Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. +
    4. +
    5. + Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. +
    6. +
    7. + Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot your password, you can reset it within Database Settings. +
    8. +
    9. + Endpoint - This is the endpoint of your Supabase instance under Project Settings > API. This is used to migrate your files. +
    10. +
    11. + API Key - This is the key of your Supabase instance under Project Settings > API. This is used to migrate your files. Make sure to use the hidden service_role key. +
    12. +
    diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml new file mode 100644 index 000000000..7d4308bac --- /dev/null +++ b/app/views/docs/migrations.phtml @@ -0,0 +1,90 @@ +

    + If you're looking to migrate existing projects to Appwrite, Migrations can help you make the move more quickly. + You can move your app from Firebase, Supabase, NHost, and even move between self-hosted and Cloud projects using Migrations. + You can also use Migrations to move between two self-hosted instances or even to duplicate project on the same instance. + Migrations will automatically move accounts, database documents, and storage files from one source to another. +

    + +

    Supported sources

    +

    + You can transfer from these sources to an Appwrite project. + Resources marked enabled are migrated automatically. + Resources marked partial can be migrated, but with limitations or caveats, check the guide for each source to learn more. + Resources marked manual require manual migration. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SourceUsersDatabasesDocumentsFilesFunctions
    +

    Firebase

    +
    enabledenabledpartialenabledmanual
    +

    Supabase

    +
    enabledenabledpartialenabledmanual
    +

    NHost

    +
    enabledenabledpartialenabledmanual
    +

    Cloud to Self-hosted

    +
    enabledenabledenabledenabledenabled
    +

    Self-hosted to Cloud

    +
    enabledenabledenabledenabledenabled
    + +

    Limitations

    +

    + Migrations cannot transfer all data perfectly, so certain fields, such as $createdAt and $updatedAt, may not be transferred. + More information can be found on the migration page for each source. +

    + +

    + Migrations help you jump start your move, but because each product is unique, complex databases and product unique features like functions might need to be migrated manually. + We also recommend you carefully validate permissions and data integrity when moving between platforms. +

    \ No newline at end of file diff --git a/app/views/docs/permissions-old.phtml b/app/views/docs/permissions-old.phtml index ac8cb8ecb..a1d7ff4c5 100644 --- a/app/views/docs/permissions-old.phtml +++ b/app/views/docs/permissions-old.phtml @@ -10,7 +10,7 @@

    For example, only users with a guest role can access authentication endpoints while access to member users is denied.

    -

    You can change your project members' roles from your project settings in the Appwrite console.

    +

    You can change your project members' roles from your project settings in the Appwrite Console.

    diff --git a/app/views/docs/permissions.phtml b/app/views/docs/permissions.phtml index adb1bbd3d..1c10fc523 100644 --- a/app/views/docs/permissions.phtml +++ b/app/views/docs/permissions.phtml @@ -18,7 +18,7 @@

    Default Values

    -

    If you create a resource using a Server SDK or the Appwrite console without explicit permissions, no one can access it by default because the permissions will be empty. If you create a resource using a Client SDK without explicit permissions, the creator will be granted read, update, and delete permissions on that resource by default.

    +

    If you create a resource using a Server SDK or the Appwrite Console without explicit permissions, no one can access it by default because the permissions will be empty. If you create a resource using a Client SDK without explicit permissions, the creator will be granted read, update, and delete permissions on that resource by default.

    Server Integration

    diff --git a/app/views/docs/production.phtml b/app/views/docs/production.phtml index 3133817d1..460e73f91 100644 --- a/app/views/docs/production.phtml +++ b/app/views/docs/production.phtml @@ -15,7 +15,7 @@

    Limit Console Access

    -

    Appwrite provides three different methods to limit access to your Appwrite console.

    +

    Appwrite provides three different methods to limit access to your Appwrite Console.

    1. Whitelist a group of developers by IP using the _APP_CONSOLE_WHITELIST_IPS environment variable.
    2. diff --git a/app/views/docs/sdks.phtml b/app/views/docs/sdks.phtml index b266a1ae4..aebf84904 100644 --- a/app/views/docs/sdks.phtml +++ b/app/views/docs/sdks.phtml @@ -14,14 +14,14 @@ $markdown->setSafeMode(true);
    3. - escape($platform['name']); ?> SDKs (beta) + escape($platform['name']); ?> SDKs (experimental)
    4. -

      SDKs (beta)

      +

      SDKs (experimental)

      text($platform['description']); ?>

      @@ -63,7 +63,7 @@ $markdown->setSafeMode(true); official - beta + experimental @@ -79,7 +79,7 @@ $markdown->setSafeMode(true);

      Integrate without an SDK

      -

      We are always looking to add new SDKs to our platform, but if the SDK you are looking for is still missing or in a beta channel, you can always integrate with Appwrite directly using any standard HTTP client and the Appwrite REST API. You can learn more about how you can integrate directly with Appwrite HTTP API from our dedicated blog post on the topic.

      +

      We are always looking to add new SDKs to our platform, but if the SDK you are looking for is still missing or is labeled experimental, you can always integrate with Appwrite directly using any standard HTTP client and the Appwrite REST API. You can learn more about how you can integrate directly with Appwrite HTTP API from our dedicated blog post on the topic.

      Community

      diff --git a/app/views/docs/self-hosting.phtml b/app/views/docs/self-hosting.phtml index 2aafd2f6f..2f6c39fd9 100644 --- a/app/views/docs/self-hosting.phtml +++ b/app/views/docs/self-hosting.phtml @@ -136,7 +136,7 @@
      docker compose up -d --remove-orphans
      -

      Once the Docker installation completes, go to your machine's hostname or IP address on your browser to access the Appwrite console. Please note that on hosts that are not Linux-native, the server might take a few minutes to start after installation completes.

      +

      Once the Docker installation completes, go to your machine's hostname or IP address on your browser to access the Appwrite Console. Please note that on hosts that are not Linux-native, the server might take a few minutes to start after installation completes.

      Stop

      diff --git a/composer.lock b/composer.lock index 9c76a9193..f84377e3e 100644 --- a/composer.lock +++ b/composer.lock @@ -58,24 +58,24 @@ }, { "name": "utopia-php/framework", - "version": "0.19.21", + "version": "0.19.1", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "3b7bd8e4acf84fd7d560ced8e0142221d302575d" + "reference": "cc7629b5f7a8f45912ec2e069b7f14e361e41c34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/3b7bd8e4acf84fd7d560ced8e0142221d302575d", - "reference": "3b7bd8e4acf84fd7d560ced8e0142221d302575d", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/cc7629b5f7a8f45912ec2e069b7f14e361e41c34", + "reference": "cc7629b5f7a8f45912ec2e069b7f14e361e41c34", "shasum": "" }, "require": { - "php": ">=8.0.0" + "php": ">=7.3.0" }, "require-dev": { - "phpunit/phpunit": "^9.5.10", - "vimeo/psalm": "4.13.1" + "phpunit/phpunit": "^9.4", + "vimeo/psalm": "4.0.1" }, "type": "library", "autoload": { @@ -101,24 +101,24 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.19.21" + "source": "https://github.com/utopia-php/framework/tree/0.19.1" }, - "time": "2022-05-12T18:42:28+00:00" + "time": "2021-11-25T16:11:40+00:00" } ], "packages-dev": [ { "name": "amphp/amp", - "version": "dev-master", + "version": "2.x-dev", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + "reference": "c5ea79065f98f93f7b16a4d5a504fe5d69451447" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "url": "https://api.github.com/repos/amphp/amp/zipball/c5ea79065f98f93f7b16a4d5a504fe5d69451447", + "reference": "c5ea79065f98f93f7b16a4d5a504fe5d69451447", "shasum": "" }, "require": { @@ -133,7 +133,6 @@ "psalm/phar": "^3.11@dev", "react/promise": "^2" }, - "default-branch": true, "type": "library", "extra": { "branch-alias": { @@ -187,7 +186,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.2" + "source": "https://github.com/amphp/amp/tree/master" }, "funding": [ { @@ -195,11 +194,11 @@ "type": "github" } ], - "time": "2022-02-20T17:52:18+00:00" + "time": "2022-08-21T11:55:21+00:00" }, { "name": "amphp/byte-stream", - "version": "dev-master", + "version": "1.x-dev", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", @@ -223,7 +222,6 @@ "phpunit/phpunit": "^6 || ^7 || ^8", "psalm/phar": "^3.11.4" }, - "default-branch": true, "type": "library", "extra": { "branch-alias": { @@ -355,12 +353,12 @@ "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", "shasum": "" }, "require": { @@ -411,9 +409,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/main" }, "funding": [ { @@ -429,7 +427,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2023-01-13T15:47:53+00:00" }, { "name": "composer/xdebug-handler", @@ -532,6 +530,54 @@ }, "time": "2019-12-04T15:06:13+00:00" }, + { + "name": "doctrine/deprecations", + "version": "1.1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "bdaa697ed9c7f5ee2f7d3b5f9c2a6f2519523cd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/bdaa697ed9c7f5ee2f7d3b5f9c2a6f2519523cd9", + "reference": "bdaa697ed9c7f5ee2f7d3b5f9c2a6f2519523cd9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.x" + }, + "time": "2023-07-29T16:12:19+00:00" + }, { "name": "felixfbecker/advanced-json-rpc", "version": "v3.2.1", @@ -691,12 +737,12 @@ "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "2d589921f23d869846a52c541247e0bafca61ab3" + "reference": "cfc54e30a4f5e5af5f9d9ce86697cfcc5f7e7c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2d589921f23d869846a52c541247e0bafca61ab3", - "reference": "2d589921f23d869846a52c541247e0bafca61ab3", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/cfc54e30a4f5e5af5f9d9ce86697cfcc5f7e7c24", + "reference": "cfc54e30a4f5e5af5f9d9ce86697cfcc5f7e7c24", "shasum": "" }, "require": { @@ -707,6 +753,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, + "default-branch": true, "bin": [ "bin/php-parse" ], @@ -739,7 +786,7 @@ "issues": "https://github.com/nikic/PHP-Parser/issues", "source": "https://github.com/nikic/PHP-Parser/tree/4.x" }, - "time": "2022-06-04T10:44:36+00:00" + "time": "2023-07-30T21:38:32+00:00" }, { "name": "openlss/lib-array2xml", @@ -853,24 +900,30 @@ "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9455bde915e322a823d464a2c41e5c0de03512a6" + "reference": "7b217217725dc991a0ae7b995041cee1d5019561" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9455bde915e322a823d464a2c41e5c0de03512a6", - "reference": "9455bde915e322a823d464a2c41e5c0de03512a6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/7b217217725dc991a0ae7b995041cee1d5019561", + "reference": "7b217217725dc991a0ae7b995041cee1d5019561", "shasum": "" }, "require": { "ext-filter": "*", "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "1.x-dev@dev", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { "mockery/mockery": "~1.3.5", - "psalm/phar": "^4.8" + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.26" }, "default-branch": true, "type": "library", @@ -903,7 +956,7 @@ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" }, - "time": "2022-04-02T20:16:01+00:00" + "time": "2023-03-12T10:50:44+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -911,21 +964,29 @@ "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "77a32518733312af16a44300404e945338981de3" + "reference": "07100e65d09fd50608d649fc656cae1c921a2495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", - "reference": "77a32518733312af16a44300404e945338981de3", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/07100e65d09fd50608d649fc656cae1c921a2495", + "reference": "07100e65d09fd50608d649fc656cae1c921a2495", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", - "psalm/phar": "^4.8" + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" }, "default-branch": true, "type": "library", @@ -952,34 +1013,76 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x" }, - "time": "2022-03-15T21:29:03+00:00" + "time": "2023-07-20T19:57:33+00:00" }, { - "name": "psr/container", - "version": "dev-master", + "name": "phpstan/phpdoc-parser", + "version": "1.23.x-dev", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "4a1ab8e11e9957f9cc9f89f87a7c912489f08119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/4a1ab8e11e9957f9cc9f89f87a7c912489f08119", + "reference": "4a1ab8e11e9957f9cc9f89f87a7c912489f08119", "shasum": "" }, "require": { - "php": ">=7.4.0" + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" }, "default-branch": true, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.x" + }, + "time": "2023-07-24T11:53:35+00:00" + }, + { + "name": "psr/container", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -1006,9 +1109,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-11-05T16:47:00+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/log", @@ -1062,16 +1165,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1116,7 +1219,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0" }, "funding": [ { @@ -1124,7 +1227,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "symfony/console", @@ -1132,12 +1235,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "09a5561288c73b1ac9aaa00d64ebe6a6782a6a3b" + "reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/09a5561288c73b1ac9aaa00d64ebe6a6782a6a3b", - "reference": "09a5561288c73b1ac9aaa00d64ebe6a6782a6a3b", + "url": "https://api.github.com/repos/symfony/console/zipball/b504a3d266ad2bb632f196c0936ef2af5ff6e273", + "reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273", "shasum": "" }, "require": { @@ -1202,7 +1305,7 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], @@ -1223,30 +1326,29 @@ "type": "tidelift" } ], - "time": "2022-06-27T16:58:25+00:00" + "time": "2023-07-19T20:11:33+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "dev-main", + "version": "2.5.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "4912000e79dc2d6df029d35d8755be1ed79b6691" + "reference": "80d075412b557d41002320b96a096ca65aa2c98d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/4912000e79dc2d6df029d35d8755be1ed79b6691", - "reference": "4912000e79dc2d6df029d35d8755be1ed79b6691", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=7.1" }, - "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1275,7 +1377,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/main" + "source": "https://github.com/symfony/deprecation-contracts/tree/2.5" }, "funding": [ { @@ -1291,7 +1393,7 @@ "type": "tidelift" } ], - "time": "2022-05-20T13:56:22+00:00" + "time": "2023-01-24T14:02:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1299,12 +1401,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -1320,7 +1422,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1358,7 +1460,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/main" }, "funding": [ { @@ -1374,7 +1476,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -1382,12 +1484,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "433d05519ce6990bf3530fba6957499d327395c2" + "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", - "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { @@ -1400,7 +1502,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1440,7 +1542,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/main" }, "funding": [ { @@ -1456,7 +1558,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -1464,12 +1566,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { @@ -1482,7 +1584,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1525,7 +1627,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/main" }, "funding": [ { @@ -1541,7 +1643,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1549,12 +1651,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -1570,7 +1672,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1609,7 +1711,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/main" }, "funding": [ { @@ -1625,7 +1727,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php73", @@ -1633,12 +1735,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { @@ -1648,7 +1750,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1689,7 +1791,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php73/tree/main" }, "funding": [ { @@ -1705,7 +1807,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php80", @@ -1713,12 +1815,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -1728,7 +1830,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1773,7 +1875,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php80/tree/main" }, "funding": [ { @@ -1789,25 +1891,26 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/service-contracts", - "version": "dev-main", + "version": "2.5.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "8336f2b06febd99d6309550ccdf4ca4cd054e73a" + "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/8336f2b06febd99d6309550ccdf4ca4cd054e73a", - "reference": "8336f2b06febd99d6309550ccdf4ca4cd054e73a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3", + "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/container": "^2.0" + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -1815,11 +1918,10 @@ "suggest": { "symfony/service-implementation": "" }, - "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1829,10 +1931,7 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1859,7 +1958,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/main" + "source": "https://github.com/symfony/service-contracts/tree/2.5" }, "funding": [ { @@ -1875,37 +1974,38 @@ "type": "tidelift" } ], - "time": "2022-05-20T13:56:22+00:00" + "time": "2023-04-21T15:04:16+00:00" }, { "name": "symfony/string", - "version": "6.2.x-dev", + "version": "5.4.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "9c4a9a2eacc3edb31ec95c4fb6b189d28406537e" + "reference": "1181fe9270e373537475e826873b5867b863883c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/9c4a9a2eacc3edb31ec95c4fb6b189d28406537e", - "reference": "9c4a9a2eacc3edb31ec95c4fb6b189d28406537e", + "url": "https://api.github.com/repos/symfony/string/zipball/1181fe9270e373537475e826873b5867b863883c", + "reference": "1181fe9270e373537475e826873b5867b863883c", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": ">=3.0" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/translation-contracts": "^2.0|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { @@ -1944,7 +2044,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/6.2" + "source": "https://github.com/symfony/string/tree/5.4" }, "funding": [ { @@ -1960,7 +2060,7 @@ "type": "tidelift" } ], - "time": "2022-06-26T16:35:21+00:00" + "time": "2023-06-28T12:46:07+00:00" }, { "name": "vimeo/psalm",