diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index ed68f522..d9d840c1 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -90,16 +90,16 @@

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 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.

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.

+

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/command-line-deployment.phtml b/app/views/docs/command-line-deployment.phtml index 79487ed3..79e12b86 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/custom-domains.phtml b/app/views/docs/custom-domains.phtml index 74c08714..5c178c32 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/email-delivery.phtml b/app/views/docs/email-delivery.phtml index ad800057..1ad88c09 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 00000000..934166ed --- /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 00000000..b2b7bad3 --- /dev/null +++ b/app/views/docs/functions-develop.phtml @@ -0,0 +1,2606 @@ +

+ 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 `ctx.req` object contains the request data
    +    if context.req.method == "GET":
    +        # Send a response with the res object helpers
    +        # `ctx.res.send()` dispatches a string back to the client
    +        return context.res.send("Hello, World!")
    +
    +    # `ctx.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 `ctx.req` object contains the request data
    +  if (context.req.method == "GET")
    +    # Send a response with the res object helpers
    +    # `ctx.res.send()` dispatches a string back to the client
    +    return context.res.send("Hello, World!")
    +  end
    +
    +  # `ctx.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',
    +  });
    +}
    +
    +
  • +
  • +

    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 try 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("http://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" },
    +        });
    +    }
    +}
    +
    +
  • +
  • +

    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().apply {
    +        //    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();
    +        // 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);
    +    }
    +}
    +
    +
  • +
+ +

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 destructing 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!");
    +    // ... more code
    +}
    +
    +// after destructuring
    +export default async function ({ req, res, log, error }) {
    +    log("This is a log!");
    +    // ... more code
    +}
    +
    +
  • +
  • +

    Deno

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

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 try 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 along side 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 'text': 
    +            return res.send("This is a text response", 200);
    +        case 'json':
    +            return res.json({"type": "This is a JSON response"}, 200);
    +        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.empty();
    +    }
    +}
    +
    +
  • +
  • +

    PHP

    +
    +
    <?php
    +
    +return function ($context) {
    +    switch ($context->req->query['type']) {
    +        case 'text':
    +            return $context->res->send("This is a text response", 200);
    +        case 'json':
    +            return $context->res->json(["type" => "This is a JSON response"], 200);
    +        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->empty();
    +    }
    +};
    +
    +
  • +
  • +

    Python

    +
    +
    def main(context):
    +    switch context.req.query['type']:
    +        case 'text':
    +            return context.res.send("This is a text response", 200)
    +        case 'json':
    +            return context.res.json({"type": "This is a JSON response"}, 200)
    +        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.empty()
    +
    +
  • +
  • +

    Ruby

    +
    +
    def main(context)
    +    case context.req.query['type'] 
    +        when 'text'
    +            return context.res.send("This is a text response", 200)
    +        when 'json'
    +            return context.res.json({"type": "This is a JSON response"}, 200)
    +        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.empty()
    +    end
    +end
    +
    +
  • +
  • +

    Deno

    +
    +
    export default async ({ req, res, log }) => {
    +
    +    switch (req.query.type) {
    +        case 'text':
    +            return res.send("This is a text response", 200);
    +        case 'json':
    +            return res.json({type": "This is a JSON response"}, 200);
    +        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.empty();
    +    }
    +}
    +
    +
  • +
  • +

    Dart

    +
    +
    import 'dart:async';
    +
    +Future<dynamic> main(final context) async {
    +    switch (context.req.query['type']) {
    +        case 'text':
    +            return context.res
    +                .send('This is a text response', 200);
    +        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
    +                .empty();
    +    }
    +}
    +
    +
  • +
  • +

    Swift

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

    .NET

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

    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"]) {
    +            "text" -> return context.send("This is a text response", 200)
    +            "json" -> return context.send(mapOf("type" to "This is a JSON response"), 200)
    +            "redirect" -> return context.redirect("https://appwrite.io", 301)
    +            "html" -> return context.send("<h1>This is an HTML response</h1>", 200, mapOf("content-type" to "text/html"))
    +            else -> return context.empty()
    +        }
    +    }
    +}
    +
    +
  • +
  • +

    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.send("This is a text response", 200);
    +            case "json":
    +                HashMap<String, Object> data = new HashMap<>();
    +                data.put("type", "This is a JSON response");
    +                return context.send(data, 200);
    +            case "redirect":
    +                return context.redirect("https://appwrite.io", 301);
    +            case "html":
    +                return context.send("<h1>This is an HTML response</h1>", 200, Map.of("content-type", "text/html"));
    +            default:
    +                return context.empty();
    +        }
    +    }
    +}
    +
    +
  • +
  • +

    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 == "text") {
    +          return context.send("This is a text response", 200);
    +        } else if (type == "json") {
    +          Json::Value data;
    +          data["type"] = "This is a JSON response";
    +          return context.send(data, 200);
    +        } else if (type == "redirect") {
    +          return context.redirect("https://appwrite.io", 301);
    +        } else if (type == "html") {
    +          Json::Value headers;
    +          headers["content-type"] = "text/html";
    +          return context.send("<h1>This is an HTML response</h1>", 200, headers);
    +        } else {
    +          return context.empty();
    +        }
    +      }
    +  };
    +}
    +
    +
  • +
+ +

+ 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 ({ res, log, error }) => {
    +    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!");
    +};
    +
    +
  • +
  • +

    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.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.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.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 try context.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 await Context.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.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.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.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, 200);
    +}
    +
    +
  • +
  • +

    PHP

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

    Python

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

    Ruby

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

    Deno

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

    Dart

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

    Swift

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

    .NET

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

    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.send(System.getenv("MY_VAR"), 200)
    +    }
    +}
    +
    +
  • +
  • +

    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.send(System.getenv("MY_VAR"), 200);
    +    }
    +}
    +
    +
  • +
  • +

    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.send(std::getenv("MY_VAR"), 200);
    +  };
    +}
    +
    +
  • +
+ +

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 ManagerN/A
+ Swift icon + .NETNuGetN/A
+ 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. +

+
    +
  • +

    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)
    +    // Pass in your API key as an environment variable. Never share API keys with users.
    +    .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();
    +    $client
    +        ->setEndpoint('https://cloud.appwrite.io/v1')
    +        ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
    +        // Pass in your API key as an environment variable. Never share API keys with users.
    +        ->setKey(getenv('APPWRITE_API_KEY'));
    +    
    +    $databases = new Databases($client);
    +
    +    try {
    +        $databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []);
    +    } 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"])
    +        # Pass in your API key as an environment variable. Never share API keys with users.
    +        .set_key(os.environ["APPWRITE_API_KEY"])
    +    )
    +
    +    databases = Databases(client)
    +
    +    try:
    +        databases.create_document("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {})
    +    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"
    +
    +def main(context)
    +  client = Appwrite::Client.new
    +  client
    +    .set_endpoint('https://cloud.appwrite.io/v1')
    +    .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
    +    # Pass in your API key as an environment variable. Never share API keys with users.
    +    .set_key(req.variables['APPWRITE_API_KEY'])
    +
    +    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();
    +    client
    +        .setEndpoint("https://cloud.appwrite.io/v1")
    +        .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
    +        // Pass in your API key as an environment variable. Never share API keys with users.
    +        .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)
    +        // Pass in your API key as an environment variable. Never share API keys with users.
    +        .setKey(process.env.APPWRITE_API_KEY);
    +    
    +    final databases = Databases(client);
    +    
    +    try {
    +        await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
    +    } 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"])
    +       // Pass in your API key as an environment variable. Never share API keys with users.
    +       .setKey(ProcessInfo.processInfo.environment["APPWRITE_API_KEY"]);
    +
    +    let databases = Databases(client: client)
    +
    +    do {
    +        try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:])
    +    } catch {
    +        context.error("Failed to create document: \(error.localizedDescription)")
    +        return try await context.res.send("Failed to create document")
    +    }
    +
    +    return context.res.send("Document created")
    +}
    +
    +
  • +
  • +

    .NET

    +
    +
    namespace DotNetRuntime;
    +
    +using Appwrite;
    +using Appwrite.Services;
    +using Appwrite.Models;
    +
    +public class Handler {
    +
    +    public async Task Main(RuntimeContext Context) 
    +    {
    +        var client = new Client()
    +           .SetEndpoint("http://cloud.appwrite.io/v1")  
    +           .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))       
    +            // Pass in your API key as an environment variable. Never share API keys with users.
    +           .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
    +
    +        var databases = new Databases(client);
    +
    +        try {
    +            await databases.CreateDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), 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().apply {
    +           setEndpoint("https://cloud.appwrite.io/v1")
    +           setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
    +           // Pass in your API key as an environment variable. Never share API keys with users.
    +           setKey(System.getenv("APPWRITE_API_KEY"))
    +        }
    +
    +        val databases = Databases(client)
    +
    +        try {
    +            databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap())
    +        } 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();
    +        client
    +                .setEndpoint("https://cloud.appwrite.io/v1")
    +                .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
    +                // Pass in your API key as an environment variable. Never share API keys with users.
    +                .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();
    +    $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('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []);
    +    } 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]", "[COLLECTION_ID]", ID.unique(), {})
    +    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"
    +
    +def main(context)
    +  client = Appwrite::Client.new
    +  client
    +    .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();
    +    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('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
    +    } 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]", 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

    +
    +
    namespace DotNetRuntime;
    +
    +using Appwrite;
    +using Appwrite.Services;
    +using Appwrite.Models;
    +
    +public class Handler {
    +
    +    public async Task Main(RuntimeContext Context) 
    +    {
    +        var client = new Client()
    +           .SetEndpoint("http://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("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), 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().apply {
    +           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("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap())
    +        } 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();
    +        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
    +
    +import utils
    +
    +def main(context):
    +    return context.res.send(utils.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
    +
    +class 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 00000000..485c4fe3 --- /dev/null +++ b/app/views/docs/functions-examples.phtml @@ -0,0 +1,940 @@ +

+ 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');
    +};
    +
    +
    +
  • +
  • +

    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()
    +    client.set_endpoint('https://cloud.appwrite.io/v1')
    +    client.set_project(os.environ['APPWRITE_FUNCTION_PROJECT_ID'])
    +    client.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
    +    });
    +}
    +
    +
    +
  • +
  • +

    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()
    +    client.set_endpoint('https://cloud.appwrite.io/v1')
    +    client.set_project(os.environ['APPWRITE_FUNCTION_PROJECT_ID'])
    +    client.set_key(os.environ['APPWRITE_API_KEY'])
    +
    +    database = Databases(client)
    +
    +    existing_votes = database.list_documents('[VOTES_COLLECTION_ID]', [
    +        Query.equal('userId', vote['userId']),
    +        Query.equal('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]', vote)
    +
    +    return context.res.json({
    +      'ok': True, 
    +      'message': 'Vote cast.', 
    +      'vote': vote_document
    +    })
    +
    +
    +
  • +
+ +

+ 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", 200);
    +  }
    +
    +  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", 200)
    +
    +    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", 200);
    +  }
    +
    +  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", 200)
    +    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", 200);
    +    }
    +
    +    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 00000000..a6e52cfc --- /dev/null +++ b/app/views/docs/functions-execute.phtml @@ -0,0 +1,570 @@ + +

+ 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()
    +
    +client
    +    .setEndpoint('https://cloud.appwrite.io/v1')
    +    .setProject('[PROJECT_ID]')
    +
    +const functions = new Functions(client)
    +
    +try {
    +    const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
    +        'foo': 'bar'
    +    }), '/', 'GET', {
    +      'X-Custom-Header': '123'
    +    })
    +    console.log(data)
    +} catch (err) {
    +    console.error(err.message)
    +}
    +
    +
    +
  • +
  • +

    Flutter

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

    Android

    +
    +
    +
    import io.appwrite.Client;
    +import io.appwrite.services.Functions;
    +import com.google.gson.Gson;
    +
    +val client = new Client();
    +client
    +    .setEndpoint('https://cloud.appwrite.io/v1')
    +    .setProject('[PROJECT_ID]')
    +
    +val functions = new Functions(client);
    +
    +try {
    +    val response = await functions.createExecution('[FUNCTION_ID]', gson.toString({
    +        'foo': 'bar'
    +    }), '/', 'GET', {
    +        'X-Custom-Header': '123'
    +    });
    +    print(response.data);
    +} catch (e) {
    +    print(e.message);
    +}
    +
    +
    +
  • +
  • +

    Apple

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

Server SDKs

+
    +
  • +

    Node.js

    +
    +
    +
    import { Client, Functions } from 'node-appwrite';  
    +
    +const client = new Client()
    +
    +client
    +    .setEndpoint('https://cloud.appwrite.io/v1')
    +    .setProject('[PROJECT_ID]')
    +    .setKey('[API_KEY]')
    +
    +const functions = new Functions(client)
    +
    +try {
    +    const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
    +        'foo': 'bar'
    +    }), '/', 'GET', {
    +        'X-Custom-Header': '123'
    +    })
    +    console.log(data)
    +} catch (err) {
    +    console.error(err.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);
    +
    +$result = $functions->createExecution('[FUNCTION_ID]', json_encode([
    +    'foo' => 'bar' 
    +], '/', 'GET', [
    +    'X-Custom-Header': '123'
    +]);
    +
    +
    +
  • +
  • +

    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)
    +
    +result = functions.create_execution('[FUNCTION_ID]', json.dumps({
    +    'foo': 'bar'
    +}, '/', 'GET', {
    +    'X-Custom-Header': '123'
    +})
    +
    +
    +
  • +
  • +

    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)
    +
    +response = functions.create_execution(function_id: '[FUNCTION_ID]', data: JSON.generate({
    +    'foo': 'bar'
    +}), '/', 'GET', {
    +    'X-Custom-Header': '123'
    +})
    +
    +puts response.inspect
    +
    +
    +
  • +
  • +

    Deno

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

    Dart

    +
    +
    +
    import 'package:dart_appwrite/dart_appwrite.dart';
    +import 'dart:convert';
    +
    +void main() {
    +  Client client = Client();
    +  Functions functions = Functions(client);
    +
    +  client
    +    .setEndpoint('https://cloud.appwrite.io/v1')
    +    .setProject('[PROJECT_ID]')
    +    .setKey('[API_KEY]')
    +  ;
    +
    +  Future result = functions.createExecution(
    +    functionId: '[FUNCTION_ID]',
    +    data: json.encode({
    +      'foo': 'bar'
    +    }),
    +    xpath: '/',
    +    method: 'GET',
    +    headers: {
    +        'X-Custom-Header': '123'
    +    }
    +  );
    +
    +  result
    +    .then((response) {
    +      print(response);
    +    }).catchError((error) {
    +      print(error.response);
    +  });
    +}
    +
    +
    +
  • +
  • +

    Swift

    +
    +
    +
    import Appwrite
    +import Foundation
    +
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1")
    +    .setProject("[PROJECT_ID]")
    +    .setKey("[API_KEY]")
    +
    +let functions = Functions(client)
    +
    +let execution = try await functions.createExecution(
    +    functionId: "[FUNCTION_ID]",
    +    data: NSJSONSerialization.jsonObject(with: [
    +        "foo": "bar"
    +    ], options: [])!),
    +    xpath: '/',
    +    method: 'GET',
    +    headers: [
    +        "X-Custom-Header": "123"
    +])
    +
    +
    +
  • +
  • +

    .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);
    +
    +Execution result = await functions.CreateExecution(
    +    functionId: "[FUNCTION_ID]",
    +    data: JsonSerializer.Serialize<object>(new Dictionary<string, object> {
    +        { "foo", "bar" }
    +    }),
    +    xpath: "/",
    +    method: "GET",
    +    headers: new Dictionary<string, object> {
    +        { "X-Custom-Header", "123" }
    +});
    +
    +
    +
  • +
  • +

    Kotlin

    +
    +
    +
    import io.appwrite.Client
    +import io.appwrite.services.Functions
    +import com.google.gson.Gson
    +
    +fun main(args: Array<String>) {
    +    val client = Client(context)
    +        .setEndpoint("https://cloud.appwrite.io/v1")
    +        .setProject("[PROJECT_ID]")
    +        .setKey("[API_KEY]")
    +
    +    val functions = Functions(client)
    +
    +    val response = functions.createExecution(
    +        functionId = "[FUNCTION_ID]",
    +        data = gson.toString(mapOf(
    +            "foo" to "bar"
    +        )),
    +        xpath = "/",
    +        method = "GET",
    +        headers = mapOf(
    +            "X-Custom-Header" to "123"
    +        )
    +    )
    +}
    +
    +
    +
    + +
    +
  • +
  • +

    Java

    +
    +
    +
    import io.appwrite.Client;
    +import io.appwrite.services.Functions;
    +import java.util.HashMap;
    +import com.google.gson.Gson;
    +
    +public static void main(String[] args) throws Exception {
    +    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]",
    +        new CoroutineCallback<>((result, error) -> {
    +            if (error != null) {
    +                error.printStackTrace();
    +                return;
    +            }
    +
    +            System.out.println(result);
    +        }),
    +        gson.toString(new HashMap() {{
    +            put("foo", "bar");
    +        }}),
    +        "/",
    +        "GET",
    +        new HashMap() {{
    +            put("X-Custom-Header", "123");
    +        }},
    +    );
    +}
    +
    +
    +
  • +
+ + +

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 00000000..663d4eaf --- /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 43fdedb1..0d1f9e02 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 c410e4ca..d737cb6e 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 2e71911d..9d2246ca 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.

diff --git a/app/views/docs/getting-started-for-flutter.phtml b/app/views/docs/getting-started-for-flutter.phtml index 6bd61487..47355fa8 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 e5ede12f..b05dd86e 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

diff --git a/app/views/docs/getting-started-for-web.phtml b/app/views/docs/getting-started-for-web.phtml index 51d3428d..6dd6c4fd 100644 --- a/app/views/docs/getting-started-for-web.phtml +++ b/app/views/docs/getting-started-for-web.phtml @@ -21,7 +21,7 @@ $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.

diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index f0b0e45c..8c3e91ed 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -97,7 +97,16 @@ $cols = [
  •   Security
  • -
  • Functions
  • +
  • + Functions + +
  • Migrations
      diff --git a/app/views/docs/keys.phtml b/app/views/docs/keys.phtml index cfff198a..a63fff50 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.phtml b/app/views/docs/migrations.phtml index e130ae47..7d4308ba 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -8,7 +8,7 @@

      Supported sources

      You can transfer from these sources to an Appwrite project. - Resources marked supported are migrated automatically. + 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.

      @@ -29,51 +29,51 @@

      Firebase

      - supported - supported + enabled + enabled partial - supported + enabled manual

      Supabase

      - supported - supported + enabled + enabled partial - supported + enabled manual

      NHost

      - supported - supported + enabled + enabled partial - supported + enabled manual

      Cloud to Self-hosted

      - supported - supported - supported - supported - supported + enabled + enabled + enabled + enabled + enabled

      Self-hosted to Cloud

      - supported - supported - supported - supported - supported + enabled + enabled + enabled + enabled + enabled diff --git a/app/views/docs/permissions-old.phtml b/app/views/docs/permissions-old.phtml index ac8cb8ec..a1d7ff4c 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 adb1bbd3..1c10fc52 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 3133817d..460e73f9 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/self-hosting.phtml b/app/views/docs/self-hosting.phtml index 2aafd2f6..2f6c39fd 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 9c76a919..f84377e3 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",