From a0ebf266a8ef920bb9e3555c99fe3c2e549803c1 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" 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. 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: 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 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 The following sections will dive deeper into some more terminology and advanced concepts which can be useful when writing your function from scratch. 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. Installing Dependencies Include a Installing Dependencies Include a Installing Dependencies Include a Installing Dependencies Include a Installing Dependencies No special steps are required for Deno, Appwrite handles everything! Installing Dependencies Include a 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 Installing Dependencies Include a Installing Dependencies Include a Installing Dependencies Include a Installing Dependencies Include a When your function is called, you receive two parameters, a The response object has two functions, 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. 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. The command above accepts three parameters: You can also create new code deployments using the Appwrite server API 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. First, navigate inside the folder that contains your dependency file. Package your code files into the Next, navigate to your Appwrite console and upload the function. 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 To find more details about a deployment and reasons for its failure, you can use the Get Deployment endpoint using the Deployments that have been built successfully are marked as ready and can be activated and executed. Compiled runtimes such as Rust and Swift take much longer to build however yield better performance over their interpreted counterparts such as Node. 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. 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. 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. 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 Library folders such as You can use the ignore property in your The example configuration above would not deploy the folder Alternatively, you can add a If you need to use a 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. By default, the following runtimes are enabled: 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. version >= 0.8.0 version >= 0.8.0 version >= 0.8.0 version >= 0.8.0 version < 0.8.0 (deprecated) version < 0.8.0 (deprecated) version < 0.8.0 (deprecated) 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 If you are running a local Appwrite instance, you will need to pass in the machine's public IP instead of 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 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. 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.
+ Appwrite Functions let you extend Appwrite by adding your own code and logic.
+ You can think of them as code snippets that are triggered by server events, webhooks, scheduled executions, or user invokation.
+ Each function will have their own URL, execute in their own isolated container, and have their own configurable environment variables and permissions.
+ With these features, Appwrite Functions unlock limitless potential to expand Appwrite's capabilities with custom logic and integrations.
+
+ The quickest way to experience Appwrite functions is to [TODO: @matej What's a good example to show to give devs an idea of what Appwrite Functions workflow is like?]
+
+ To fully harness the power of Appwrite Functions, explore the following features.
+
+ If you need to integrate Appwrite with a third-party API or add a function for common utilities,
+ there might already be a function template made by the Appwrite community that fits your needs.
+ Function templates are Appwrite Functions repositories that you can clone and add to your Appwrite instance.
+
+Learn more about using function templates
+
+ Appwrite Functions are designed to be maintainable and fit into a familiar development workflow.
+ You can deploy them from a GitHub repository branch or using the Appwrite CLI.
+
+Learn more about using deploying functions
+
+Appwrite Functions can be executed directly through a request to the API, or triggered by events, webhooks, or scheduled executions.
+This flexible execution models unlocks many potential usecases for Appwrite functions.
+Explore using Appwrite Functions to execute a complex routine of logic, or execute background tasks on a schedule.
+
+Learn more about using executing functions
+
+Writing Appwrite Functions should feel familiar to writing controllers in an HTTP server.
+In your function, you'll receive a request object, add transformations and logic, then return a response.
+Almost anything can be executed as code in an Appwrite Function.
+
+Learn more about using function syntax
+
+Appwrite supports many open-source runtimes. Find your prefered language and start writing your functions.
+
+Learn more about using runtimes
+
+Let's be honest, we spend more time debugging our code than writing our code.
+So it's important to be able to log, debug, and test your Appwrite Functions in development and production.
+
+Learn more about debugging functions
+
- The quickest way to experience Appwrite functions is to [TODO: @matej What's a good example to show to give devs an idea of what Appwrite Functions workflow is like?]
+ Appwrite Functions unlock limitless possibilities, but it's simple to get started. You can deploy your first function and execute it in minutes.
To fully harness the power of Appwrite Functions, explore the following features.
@@ -35,6 +150,16 @@ $runtimes = $this->getParam('runtimes', []);
Learn more about using function templates
+Writing Appwrite Functions should feel familiar to writing controllers in an HTTP server.
+In your function, you'll receive a request object, add transformations and logic, then return a response.
+Almost anything can be executed as code in an Appwrite Function.
+
+Learn more about using function syntax
+
Appwrite Functions are designed to be maintainable and fit into a familiar development workflow.
@@ -54,15 +179,6 @@ Explore using Appwrite Functions to execute a complex routine of logic, or execu
Learn more about using executing functions
-Writing Appwrite Functions should feel familiar to writing controllers in an HTTP server.
-In your function, you'll receive a request object, add transformations and logic, then return a response.
-Almost anything can be executed as code in an Appwrite Function.
-
-Learn more about using function syntax
-
Appwrite supports many open-source runtimes. Find your prefered language and start writing your functions.
diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml
index 7d9bb0b45..8b772de6c 100644
--- a/app/views/docs/index.phtml
+++ b/app/views/docs/index.phtml
@@ -96,9 +96,9 @@ $cols = [
Functions
+ Appwrite Functions... do we need this page?
+
+ Appwrite Functions are mini application in Appwrite with their own endpoint.
+ Each function can have many deployments, which can be thought of as versions of the mini-application.
+
+ Functions can be deployed in different ways to meet your unique development habbits.
+ 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.
+
+ The recommended way to manage your Appwrite Function deployments is to use a version control system, such as GitHub.
+ This offers simple versioning and collaboration that will easily fit into the rest of your development workflow.
+ Deployments will go through the following states throughout their life cycle.
+ Appwrite Functions offer a familiar interface if you've developed REST endpoints.
+ Each function is handled following a request and response pattern.
+ Here's what you need to know to start writing your first Appwrite Function.
+
+ Appwrite Functions executions can be invoked in several ways.
+ Functions can be invoked through the Appwrite SDK and visting its preview link. Functions can also be triggered by events, webhooks, and scheduled executions.
+ Here are all the different ways to consume your new Appwrite Functions.
+
+
+
+ Each Appwrite function also has its own preview link.
+ When requests are made to this link, whether through a browser or through an HTTP requests,
+ the request information like request headers and request body will be passed to the function.
+ This unlocks interesting ways to integrate other apps and backends to your Appwrite project.
+
+
+
+
+
+
+
+
+ Appwrite Functions supports ...
+ wait. wut we do with runtimes not yet on cloud???
+
-Learn more about using function syntax
+Learn more about using function syntax
Learn more about debugging functions
-
+ Appwrite Functions received major upgrades in Appwrite version 1.4.
+ If you still have functions from previous versions, [TODO: @matej what is the consequence what should they do?]
+
- Appwrite Functions... do we need this page?
-
- The recommended way to manage your Appwrite Function deployments is to use a version control system, such as GitHub.
+ The recommended way to manage your Appwrite Function deployments is to use Git.
This offers simple versioning and collaboration that will easily fit into the rest of your development workflow.
Deployments will go through the following states throughout their life cycle.
Appwrite Functions executions can be invoked in several ways.
- Functions can be invoked through the Appwrite SDK and visting its preview link. Functions can also be triggered by events, webhooks, and scheduled executions.
+ Functions can be invoked through the Appwrite SDK and visting its REST endpoint. Functions can also be triggered by events and scheduled executions.
Here are all the different ways to consume your new Appwrite Functions.
-
-
- Each Appwrite function also has its own preview link.
+ Each Appwrite function has its own domain. (can be custom)
When requests are made to this link, whether through a browser or through an HTTP requests,
the request information like request headers and request body will be passed to the function.
This unlocks interesting ways to integrate other apps and backends to your Appwrite project.
-
+
-
Writing Appwrite Functions should feel familiar to writing controllers in an HTTP server.
In your function, you'll receive a request object, add transformations and logic, then return a response.
From 3610aadf00ef588ead24a9a00ba24d1789146a20 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" If you prefer to learn through examples, explore the recipes section.
+ 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. Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax.
+ 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
+ If you need to pass constants or secrets to Appwrite Functions, you can use environment variables.
+
+ You can access the environment variables through the systems library of each language.
+
+ Appwrite Functions help you start small and scale big.
+ Now you've created your first Appwrite Function, it's time to learn the different ways to develop, deploy, and execute your Appwrite Functions.
To fully harness the power of Appwrite Functions, explore the following features.
-Learn more about using function syntax
+Learn more about developing functions
-Learn more about using deploying functions
+Learn more about using deploying functions
-Learn more about using executing functions
+Learn more about using executing functions
+ If you pass data into an Appwrite function, it'll be found in the request object.
+ This includes all invokation methods, such as data from Appwrite SDKs, HTTP calls, Appwrite events, and browsers visiting the configured domain.
+ Explore the request object with the following function, which logs all request params to the Appwrite Console.
+
+ 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.
+
diff --git a/app/views/js.js b/app/views/js.js
new file mode 100644
index 000000000..e56b14ce6
--- /dev/null
+++ b/app/views/js.js
@@ -0,0 +1,32 @@
+export default async ({ req, res, log }) => {
+ switch (req.body) {
+ case 'send':
+ return res.send(
+ "This is a text response",
+ 200,
+ {
+ "content-type": "application/text"
+ }
+ );
+ case 'json':
+ return res.json(
+ {
+ "type": "This is a JSON response"
+ },
+ 200,
+ {
+ "content-type": "application/json"
+ }
+ );
+ case 'redirect':
+ return res.json(
+ "https://appwrite.io",
+ 301,
+ {
+ "content-type": "application/json"
+ }
+ );
+ default:
+ return res.empty();
+ }
+};
\ No newline at end of file
From 71439b8ee898d03eaf5e490ebd18cbee59031de3 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" Here's an example of using logs and errors. You can access these logs through the following steps.
If you need to pass constants or secrets to Appwrite Functions, you can use environment variables.
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml
new file mode 100644
index 000000000..a8149e25f
--- /dev/null
+++ b/app/views/docs/functions-recipes.phtml
@@ -0,0 +1,6 @@
+
+ Appwrite Functions is all about flexibility.
+ Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
+ Take a look at the following.
+
+ To deploy with the Appwrite CLI, your function's folder structure must be configured in a specific way.
+ The folder path is then added to a config file called
+ 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
+ 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.
+ Deployments will go through the following states throughout their life cycle. If you prefer to learn through examples, explore the recipes section.
+ There is a clear flow for all Appwrite Functions, from beginning to end.
+ Here's everything that happens during a function execution.
+
Context is an object passed into every function to handle communication to both the end users, and logging to the Appwrite console.
@@ -25,19 +39,19 @@
Here's an example of using logs and errors. You can access these logs through the following steps.
+ We have a dedicated page of recipes to implement common functionalities in Appwrite Functions, like parsing request path and params, or making requests to third party APIs.
+
+Explore examples and recipes
+ Libraries dependent on compiled binaries not available on the executors cannot be installed.
-
+ TODO: Describe steps to navigate the UI
-
- 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.
+ 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 with a generated or custom domain, permissions are disabled for this function.
+ Anyone visiting this domain will be able to execute the function.
+ If you need to enforce permissions for functions with a domain, use authentication methods like JWT.
+
Appwrite Functions supports ...
wait. wut we do with runtimes not yet on cloud???
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. 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. First, navigate inside the folder that contains your dependency file. Package your code files into the Next, navigate to your Appwrite console and upload the function.
- Appwrite Functions supports ...
- wait. wut we do with runtimes not yet on cloud???
+ Appwrite Functions supports an extensive list of runtimes to meet your unique tech preferences.
+ Not all runtimes are available on Appwrite Cloud, check for the
- Functions can be deployed in different ways to meet your unique development habbits.
+ 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.
Before deploying your function with Git, create a new function attached to your Git repo.
From db2286b61f6200f67c82a8fde7559d930b9a4386 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Mon, 31 Jul 2023 16:34:00 +0100
Subject: [PATCH 15/80] feat: translate json response snippets
---
app/views/docs/functions.phtml | 114 +++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 28 deletions(-)
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index b3cadd9b7..f1727b4e9 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -25,9 +25,9 @@ $runtimes = $this->getParam('runtimes', []);
- Appwrite Functions is all about flexibility.
+ Appwrite Functions is all about flexibility.
Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
Take a look at the following.
Congratulations! You've built a powerful currency conversion function using Appwrite! Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax. Here's an example of using logs and errors. You can access these logs through the following steps.
If you need to pass constants or secrets to Appwrite Functions, you can use environment variables.
+ Environmental variables can be global, or function specific.
+
+ Local variables will only be accessible in the function they belong to.
+ Local variables will override global variables when they have conflicting names.
+
+ Global variables are accessible to all Appwrite Functions.
+ Local variables will override global variables when they have conflicting names.
You can access the environment variables through the systems library of each language.
Explore examples and recipes
- Libraries dependent on compiled binaries not available on the executors cannot be installed. After deploying a function, you can find the status of the deployment and build logs in the Appwrite Console. 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's folder structure must be configured in a specific way.
The folder path is then added to a config file called
- TODO: Describe steps to navigate the UI
+ Changes in Appwrite emit events.
+ You can configure Functions to be executed in response to these events.
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 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 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 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 by running this command in the folder holding your 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 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 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's folder structure must be configured in a specific way.
- The folder path is then added to a config file called
+ Run the following command in the folder holding the
- Appwrite Functions is all about flexibility.
- Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
- Take a look at the following.
+ Appwrite Functions is all about flexibility.
+ Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
+ Take a look at the following.
+ In this recipe, we'll build a simple function for currency conversion.
+ Create a new file, `index.js`. Add the following code to `index.js`. Create a new file, `index.php`. Add the following code to `index.php`. Create a new file, `index.py`. Add the following code to `index.py`. Create a new file, `index.dart`. Add the following code to `index.dart`. Create a new file, `index.rb`. Add the following code to `index.rb`. This code will return `1.13` when the function is called, because 1€ equals approximately 1.13$. Now, create a function in the Appwrite console, adding your Git repository as the remote source and using the path file you created as the entry point. Now, let's update the function to use the request payload. You can use a query string to pass data to your function. For example, `ghrfu9ewji.functions.appwrite.app?amount=5` will pass `5` as the `amount` parameter. Update `index.js` to use `req.query.amount` to access the `amount` parameter, and return the conversion result. Update `index.php` to use `$context->req->query['amount']` to access the `amount` parameter, and return the conversion result. Commit your changes and push them to your Git repository.
+ Execute the function and visit the URL (like `ghrfu9ewji.functions.appwrite.app?amount=5`) to see the response.
+
+ You should see the result of the conversion, like `5.65`.
+ Run the following bash command to create a `package.json` file. This file is used to manage your Node.js project's dependencies. Install the `undici` library. This library includes a `fetch` function that you can use to make HTTP requests. Finally, we need to add `npm install` to your function's build commands in the Appwrite console. Use `fetch` from `undici` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. Deploy your changes After your function has updated, you can test it by visiting the URL and providing different amounts to convert in the query string. The conversion rate should now be more precise because we're using the current conversion rate. Let's add support multiple paths like `/eur` and `/inr`. Each path will convert from that currency to dollars.
+ After your function has updated, you can try out the new paths. For example, `ghrfu9ewji.functions.appwrite.app/eur?amount=5` should convert Euros to Dollars, while `ghrfu9ewji.functions.appwrite.app/inr?amount=100` should convert Indian Rupees to Dollars. Congratulations! You've built a powerful currency conversion function using Appwrite! Update `index.py` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result. Update `index.dart` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result. Update `index.rb` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result. Commit your changes and push them to your Git repository. Finally, we need to add `npm install` to your function's build commands in the Appwrite console. Finally, add `npm install` to your function's build commands in the Appwrite console. You can use Composer to manage your PHP project's dependencies. Install it from getcomposer.org/download. Run the following bash command to create a `composer.json` file. This file is used to manage your PHP project's dependencies. Install the `guzzlehttp/guzzle` library. This library includes a `get` function that you can use to make HTTP requests. Finally, add `composer install` to your function's build commands in the Appwrite console. Run the following bash command to create a `requirements.txt` file. This file is used to manage your Python project's dependencies. Install the `requests` library. This library includes a `get` function that you can use to make HTTP requests. Finally, add `pip install -r requirements.txt` to your function's build commands in the Appwrite console.
+ Create a `pubspec.yaml` file with the following contents. This file is used to manage your Dart project's dependencies.
+
+ Install the `http` library. This library includes a `get` function that you can use to make HTTP requests.
+
+ Finally, add `pub get` to your function's build commands in the Appwrite console.
+
+ Create a `Gemfile` file with the following contents. This file is used to manage your Ruby project's dependencies.
+
+ Install the `httparty` library. This library includes a `get` function that you can use to make HTTP requests.
+
+ Finally, add `bundle install` to your function's build commands in the Appwrite console.
+
+ Use `get` from `requests` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. Use `get` from `http` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. Use `get` from `httparty` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. Deploy your changes
+
+
+ After your function has updated, you can try out the new paths. For example, `ghrfu9ewji.functions.appwrite.app/eur?amount=5` should convert Euros to Dollars, while `ghrfu9ewji.functions.appwrite.app/inr?amount=100` should convert Indian Rupees to Dollars. Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax. Some languages support destructuring. You'll see us use destructing in examples, which has the following syntax.
+
+
-
- Getting Started
-
-
-appwrite init functionappwrite.json file. Go ahead and deploy your function using :
-appwrite deploy functionappwrite deploy command to instantly deploy your changes to the Appwrite server. Writing your own Function
-
-
-
-
-
-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,
- });
-};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,
- ]);
-};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,
- })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,
- })
-endGemfile 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,
- });
-};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,
- });
-}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,
- ])
-}Package.swift file with your function, Appwrite handles the rest!.NET
-
- public async TaskFunction.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
- ))
-}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();
-
- Mapdeps.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);
-}CMakeLists.txt file with your function, Appwrite handles the rest!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.
-
-
-
-
-
-
-
- Property
- Description
-
-
- headers
- An object containing all the request headers.
-
-
- payload
- A JSON string containing the data when you created the execution.
-
-
-
-variables
- An object containing all the function variables. This includes variables automatically added by Appwrite.
- 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:
-
-
-
-
-
-
-
- Function
- Description
-
-
- 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
-
-Deploy Your Function
-
-
-
-
-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 createDeployment `
- --functionId=6012cc93d5a7b `
- --activate=true `
- --entrypoint="index.js" `
- --code="."
-
-
-
-
-
-
-
- Name
- Description
-
-
- functionId
- The ID of the Function you created in the previous step. You can find your function ID on your function page in your project dashboard.
-
-
- entrypoint
- The file name of your custom code that is executed when the function is triggered.
-
-
-
-code
- Path 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.
- Manual Deployment
-
-.
-├── package.json
-└── index.js
-.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 .
-
-
-
-index.js. code.tar.gz.Builds
-buildId from the deployment.deploymentId.Build Times
- Execute
-
-
-
-
-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
-
-
-
-
-
-
-
-
- Cron Expression
- Schedule
-
-
- */15 * * * *
- Every 15 minutes
-
-
- 0 * * * *
- Every Hour
-
-
- 0 0 * * *
- Every day at 00:00
-
-
-
-0 0 * * 1
- Every monday at 00:00
- Abuse and Limits
-
-appwrite.json for up to 900 seconds.Ignore Files
-
-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.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" ]
- },
- ...
- ],
-}node_modules and the file .env..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..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
-
-
-
-
-
-
-
-
-
- $runtime): ?>
-
- Name
- Image
- Architectures
-
-
-
-
-
- escape($key); ?>
- escape($runtime['image'] ?? ''); ?>
- escape(implode(' / ', $runtime['supports'] ?? [])); ?>
- node-16.0, php-8.0, python-3.9, ruby-3.0, and dart-2.17.Function Variables
-
-
-
-
-
-
-
-
-
- Name
- Description
-
-
-
- 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
-
- 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
-
- Your function's project ID.
-
-
-
- APPWRITE_FUNCTION_USER_ID
-
- 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
-
- A JSON Web Token generated for the user that executes your function.
-
-
-
- APPWRITE_FUNCTION_EVENT_PAYLOAD
-
- Your function event payload. Deprecated in favor of APPWRITE_FUNCTION_EVENT_DATA in version 0.8.0.
-
-
-
- APPWRITE_FUNCTION_ENV_NAME
-
- Your function environment name. Can be any of Appwrite supported execution environments.
-
-
-
-
- APPWRITE_FUNCTION_ENV_VERSION
-
- Your function environment version.
- Using an Appwrite SDK in Your Function
- 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.'https://localhost/v1'. Localhost inside the function's runtime container is not the same as localhost of your machine.Appwrite SDKs in Functions
-
-APPWRITE_FUNCTION_PROJECT_ID.Monitor & Debug
-
-Demos & Examples
-
-Getting Started
+Explore Features
+Templates
+Deploy
+Execute
+Syntax
+Runtime
+Debug
+Getting Started
+
+
+
Node.js
+
+
+
+ PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Explore Features
Syntax
+Deploy
Syntax
-Runtime
Version Control Systems
+Create
+Deploy
+...
+Profit?!
+
+Templates
+
+CLI
+[TODO]
+
+Manual
+[TODO]
+
+Deployment Life Cycle
+Function Life Cycle
+[TODO: @matej, describe the life cycle of a function, maybe build a UML and give to jade to mock up (optional)]
+
+The Context Object
+
+Request
+
+Response
+
+Logging
+
+Accessing Environment Variables
+
+Using Appwrite in a Function
+
+Limitations
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
new file mode 100644
index 000000000..acc4ac356
--- /dev/null
+++ b/app/views/docs/functions-execute.phtml
@@ -0,0 +1,35 @@
+SDK
+Preview Link
+Events
+Webhooks
+Schedule
+Deploy
@@ -193,4 +193,10 @@ So it's important to be able to log, debug, and test your Appwrite Functions in
Upgrade
+
-
Version Control Systems
+Git
Create
+- Install Appwrite on your GitHub account/organization
+- Select a repository
+- Select a production branch
+- Define root directory
+- Silent mode -> No comments on PRs
+- Build commands
Deploy
-...
-Profit?!
+- Prod branch is automatically deployed on push and activated
+ - Non prod branches are also built but not activated automatically
+- Push to branch
+Debugging Builds
+- Check logs and errors
+- Redeploy button for non-code issues [TODO: @matej write an example]
Templates
+- Select repo -> Specify path
+- Make repository
CLI
[TODO]
@@ -30,8 +42,10 @@
Manual
[TODO]
+[tar --exclude code.tar.gz -czf code.tar.gz .]
+
Deployment Life Cycle
Function Life Cycle
-[TODO: @matej, describe the life cycle of a function, maybe build a UML and give to jade to mock up (optional)]
+[TODO: CTA if you just want examples, click this link]
The Context Object
@@ -14,9 +13,17 @@
Response
Logging
+-> LIST WHAT WE SHOW AND WHAT WE DONT SHOW
Accessing Environment Variables
+Depencies
+
Using Appwrite in a Function
+[TODO: 2 examples -> JWT and API keys]
+
+Recipes
+[TODO: Matej and Luke write examples]
Limitations
+
\ No newline at end of file
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index acc4ac356..174d7d771 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -1,35 +1,38 @@
SDK
+Domain
Preview Link
-Events
+DOMAIN IGNORE PERMISSIONS AOSDHFGAKSHDJG
+
+SDK
+- two examples
+ -> sync
+ -> async
+ -> pass body
Webhooks
+Events
Schedule
-Node.js
+
-
- export default async ({ res }) => {
+ return res.json({
+ motto: 'Build Fast. Scale Big. All in One Place.'
+ });
+};Syntax
+Develop
Just want the code?
+ The Context Object
+
+
+
+
+
+
+
+
+ Property
+ Description
+
+
+ context.req
+ Contains request information like method, body, and headers. See full examples here.
+
+
+ context.res
+ Contains methods to build a response and return information. See full examples here.
+
+
+ context.log
+ Logs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
+
+
+
+context.error
+ Logs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
+
+
+
Node.js
+
+
+
+ PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Request
+[TODO: full table of what's in a request]
+[TODO: full examples of what's in a request]
Response
+[TODO: Full table of what's in a res]
+[TODO: full examples of what's in a res]
+
Logging
+context.log() and context.error() methods.
+ These logs are only visible to developers with access to the Appwrite Console.
+Accessing Environment Variables
+Depencies
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 86266c49a..b3cadd9b7 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -138,6 +138,8 @@ $runtimes = $this->getParam('runtimes', []);
Explore Features
Deploy
@@ -168,7 +170,7 @@ Almost anything can be executed as code in an Appwrite Function.
You can deploy them from a GitHub repository branch or using the Appwrite CLI.
Execute
@@ -178,7 +180,7 @@ This flexible execution models unlocks many potential usecases for Appwrite func
Explore using Appwrite Functions to execute a complex routine of logic, or execute background tasks on a schedule.
Runtime
From 3858af8bc65bec51f93ea40f6d84d776a78ed4c1 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" Request
-[TODO: full table of what's in a request]
-[TODO: full examples of what's in a request]
+
+
Node.js
+
+ export default async ({ req, res, log }) => {
+ log(req.bodyString); // Raw request body, contains request data
+ log(req.body); // Body parsed on content-type, only supports JSON
+ log(req.headers); // Request headers
+ 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(req.query); // Parsed query params. For example, req.query.limit
+
+ return res.send("All the request parameters are logged to the Appwrite Console.");
+};PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Response
-[TODO: Full table of what's in a res]
-[TODO: full examples of what's in a res]
+
+
Node.js
+
+ export default async ({ req, res, log }) => {
+ switch (req.body) {
+ case 'send':
+ return res.send(
+ "This is a text response",
+ 200,
+ {
+ "content-type": "application/text"
+ }
+ );
+ case 'json':
+ return res.json(
+ {
+ "type": "This is a JSON response"
+ },
+ 200,
+ {
+ "content-type": "application/json"
+ }
+ );
+ case 'redirect':
+ return res.json(
+ "https://appwrite.io",
+ 301,
+ {
+ "content-type": "application/json"
+ }
+ );
+ default:
+ return res.empty();
+ }
+};PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Logging
context.log() and context.error() methods.
These logs are only visible to developers with access to the Appwrite Console.
Accessing Environment Variables
CLI
-[TODO]
+- Setup cli
+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 shell function.
+
+appwrite init functionManual
-[TODO]
+appwrite.json file.
+
+appwrite deploy functionDeployment Life Cycle
-Manual
+[TODO]
-[TODO: @matej What else?]
\ No newline at end of file
+[tar --exclude code.tar.gz -czf code.tar.gz .]
\ No newline at end of file
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 8053f3f87..28ee83399 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -9,6 +9,20 @@
Function Flow
+
+
+
+
context.res, when the user code throws an exception, or times out.The Context Object
-
context.req
+ context.reqContains request information like method, body, and headers. See full examples here.
-
context.res
+ context.resContains methods to build a response and return information. See full examples here.
-
context.log
+ context.logLogs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
-
@@ -450,7 +464,122 @@
context.error
+ context.errorLogs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
+
Node.js
+
+ export default async ({ res, log, error }) => {
+ log("This is a log, use for logging information to console");
+ error("This is an error, use for logging errors to console")
+
+ return res.send("Check the Appwrite Console to see logs and errors!");
+};PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Accessing Environment Variables
@@ -468,8 +597,133 @@
Using Appwrite in a Function
[TODO: 2 examples -> JWT and API keys]
+Quick Example
+
+
+
+Node.js
+
+
+
+ PHP
+
+
+
+ Python
+
+
+
+ Ruby
+
+
+
+ Deno
+
+
+
+ Dart
+
+
+
+ Swift
+
+
+
+ .NET
+
+
+
+ Kotlin
+
+
+
+ Java
+
+
+
+ C++
+
+
+
+ Using Multiple Files
+
+
Recipes
-[TODO: Matej and Luke write examples]
+Limitations
-
\ No newline at end of file
+SDK
-- two examples
- -> sync
- -> async
- -> pass body
+TODO: two examples running the function sync and async form the SDK
Events
Schedule
-
+
+
-[TODO: EXECUTION ARTIFACTS/LOGS/STUFF]
+
+
+
+
+ Cron Expression
+ Schedule
+
+
+ */15 * * * *
+ Every 15 minutes
+
+
+ 0 * * * *
+ Every Hour
+
+
+ 0 0 * * *
+ Every day at 00:00
+
+
+
+0 0 * * 1
+ Every monday at 00:00
+ Permissions
+Logs and results
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml
index df6e9baac..a6e6f7e09 100644
--- a/app/views/docs/functions-recipes.phtml
+++ b/app/views/docs/functions-recipes.phtml
@@ -3,4 +3,5 @@
Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
Take a look at the following.
-[TODO: @matej @luke -> Let's have some simple recipes here for common actions]
\ No newline at end of file
+[TODO: @matej @luke -> Let's have some simple recipes here for common actions]
+[TODO: @matej @luke -> Example with JWT, show both client and server code]
\ No newline at end of file
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 5686a2d28..3ef464840 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -1,5 +1,43 @@
+getParam('events', []);
+$runtimes = $this->getParam('runtimes', []);
+
+?>
+
+
Supported Runtimes
+
+
+
+
+
+[TODO: Label which ones are cloud only]
From db582b56e9c942f3410f2f48b4850d2e09159456 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
+
+
+
+ $runtime): ?>
+
+ Name
+ Image
+ Architectures
+
+
+
+
+
+ escape($key); ?>
+ escape($runtime['image'] ?? ''); ?>
+ escape(implode(' / ', $runtime['supports'] ?? [])); ?>
+
-appwrite deploy functionManual
-[TODO]
+Manual Deployment
+
+.
+├── package.json
+└── index.js
+.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 .
+
\ No newline at end of file
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 3ef464840..4e56f2812 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -9,8 +9,8 @@ $runtimes = $this->getParam('runtimes', []);
index.js. code.tar.gz.Cloud label in each listed runtime to know whichones are available.
Supported Runtimes
From 4a5643369fbf11613961f1f98866179992d8aa82 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" Create Funcion
+
+
-Create
-- Install Appwrite on your GitHub account/organization
-- Select a repository
-- Select a production branch
-- Define root directory
-- Silent mode -> No comments on PRs
-- Build commands
Deploy
-- Prod branch is automatically deployed on push and activated
- - Non prod branches are also built but not activated automatically
-- Push to branch
+
+
Debugging Builds
- Check logs and errors
- Redeploy button for non-code issues [TODO: @matej write an example]
-Templates
-- Select repo -> Specify path
-- Make repository
-
CLI
- Setup cli
export default async ({ res }) => {
- return res.json({
- motto: 'Build Fast. Scale Big. All in One Place.'
- });
+ return res.json({
+ motto: 'Build Fast. Scale Big. All in One Place.'
+ });
};PHP
+
-
- return function ($context) {
+ return $context->res->json([
+ 'motto' => 'Build Fast. Scale Big. All in One Place.'
+ ]);
+}Python
+
-
- def main(context):
+ return context.res.json({
+ "motto": "Build Fast. Scale Big. All in One Place.",
+})Ruby
+
-
- def main(context)
+ return context.res.json(
+ {
+ "motto": "Build Fast. Scale Big. All in One Place."
+ }
+ )
+endDeno
+
-
- export default ({ req, res, log, error }: any) => {
+ return res.json({
+ motto: "Build Fast. Scale Big. All in One Place."
+ });
+};Dart
+
+Futureimport 'dart:async';
- Swift
+
+ func main(context: RuntimeContext) async throws -> RuntimeOutput {
+ return try context.res.json([
+ "motto": "Build Fast. Scale Big. All in One Place."
+ ])
+}import Foundation
- .NET
+
-
- namespace DotNetRuntime;
+public class Handler {
+ public async TaskKotlin
+
+import io.openruntimes.kotlin.RuntimeContext
+import io.openruntimes.kotlin.RuntimeOutput
+
+class Main {
+ fun main(context: RuntimeContext): RuntimeOutput {
+ 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"
+ ))
+ }
+}package io.openruntimes.kotlin.src
- Java
+
+public class Main {
+ public RuntimeOutput main(RuntimeContext context) throws Exception {
+ Mappackage io.openruntimes.java.src;
+
+import io.openruntimes.java.RuntimeContext;
+import io.openruntimes.java.RuntimeOutput;
+import java.util.HashMap;
- C++
+
+namespace runtime {
+ class Handler {
+ public:
+ static RuntimeOutput main(RuntimeContext &context) {
+ Json::Value response;
+ response["motto"] = "Build Fast. Scale Big. All in One Place.";
+ return context.res.json(response);
+ }
+ };
+}#include "../RuntimeResponse.h"
+#include "../RuntimeRequest.h"
+#include "../RuntimeOutput.h"
+#include "../RuntimeContext.h"
- Section 1: My First Function
+
+Creating the function
+
+
+
+
+
+module.exports = async function ({ res }) {
+ return res.end('1.13');
+};
+git init
+git add index.js
+git commit -m "Initial commit"
+Section 2: Let's Use Payload
+
+Updating the function
+
+
+
+
+
+module.exports = async function ({ req, res }) {
+ const amountInEuros = Number(req.query.amount);
+ const amountInDollars = amountInEuros * 1.13;
+ return res.end(amountInDollars.toString());
+};Testing the function
+
+
+
+
+Section 3: Installing Dependencies
+
+Preparing for dependencies
+
+
+
+
+Updating the function
+
+
+
+
+
+const { fetch } = require('undici');
+
+module.exports = async function ({ req, res }) {
+ const amountInEuros = Number(req.query.amount);
+ const response = await fetch('https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/eur/usd.json');
+ const data = await response.json();
+ const amountInDollars = amountInEuros * data.usd;
+ return res.end(amountInDollars.toString());
+};Testing the function
+
+
+
+
+Section 4: More Routes
+
+Updating the function
+
+
+
+
+Testing the function
+
+
+
+
+
From 31c7c44813afa7fd43a4e8628a0a1985ea061a49 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" Node.js
@@ -181,6 +181,8 @@
Explore the request object with the following function, which logs all request params to the Appwrite Console.
+[TODO: @luke Let's make sure we show an example for evert runtime with good string manip methods.]
+
From 29fc3c15d9a80f6cfcda58f546d5f0a8ab543d32 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" Node.js
@@ -313,6 +315,8 @@
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.
+
+[TODO: @luke Let's make sure we show an example for evert runtime with good string manip methods.]
Node.js
@@ -464,6 +468,7 @@
Node.js
@@ -581,21 +586,54 @@
+
+
Accessing Environment Variables
Local Environment Variables
+
+
+
+.env file.Global Variables
+
+
.env file.Depencies
+[TODO: @luke is this different for every language? Idk what to put here, do we need to also @matej?]
+
Using Appwrite in a Function
-[TODO: 2 examples -> JWT and API keys]
+[TODO: @luke @matej 2 examples -> JWT and API keys]
Quick Example
@@ -713,6 +751,7 @@
Using Multiple Files
+[TODO: @luke show how you can use multiple files in the same project]
Recipes
@@ -722,8 +761,4 @@
Limitations
-Debugging Builds
-- Check logs and errors
-- Redeploy button for non-code issues [TODO: @matej write an example]
+
+
CLI
-- Setup cli
+CLI Setup
+ appwrite.json that tells the CLI where each function is stored.
diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml
index 44007ad43..d82d95a21 100644
--- a/app/views/docs/index.phtml
+++ b/app/views/docs/index.phtml
@@ -96,11 +96,11 @@ $cols = [
Functions
SDK
-TODO: two examples running the function sync and async form the SDK
+[TODO: @luke @matej, two examples running the function sync and async form the SDK]
Events
+
Schedule
@@ -70,3 +81,4 @@ TODO: two examples running the function sync and async form the SDK
Logs and results
+[TODO: @matej, decide what needs to go here.]
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml
index 230b58619..33f6c0834 100644
--- a/app/views/docs/functions-recipes.phtml
+++ b/app/views/docs/functions-recipes.phtml
@@ -110,4 +110,22 @@ module.exports = async function ({ req, res }) {
[TODO: @luke -> translate code for other runtimes]
-[TODO: @matej @luke -> Example with JWT, show both client and server code]
\ No newline at end of file
+[TODO: @matej @luke -> Example with JWT, show both client and server code]
+
+
+
+
\ No newline at end of file
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 4e56f2812..0a1e057e9 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -40,4 +40,4 @@ $runtimes = $this->getParam('runtimes', []);
Deploying Appwrite Functions
-appwrite.json file.appwrite init function
@@ -36,7 +36,9 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,
✓ Successappwrite.json file.appwrite deploy function
@@ -47,7 +49,9 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,
Deploying Databases and Collections
-appwrite.json file.
@@ -57,15 +61,17 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,
appwrite deploy collectionappwrite.json file. appwrite deploy teamDeploying Storage Buckets
appwrite.json file. appwrite deploy bucketappwrite.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 shell function.
+ 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 shell function, then paste in your function code.
+appwrite.json file.
From 2296a8b69b1d9936466be531c538fe691039d594 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Mon, 7 Aug 2023 12:23:53 +0100
Subject: [PATCH 21/80] feat: port functions recipes
---
.vscode/settings.json | 9 +
app/views/docs/functions-recipes.phtml | 280 ++++++++++++------
composer.lock | 374 ++++++++++++++++---------
3 files changed, 437 insertions(+), 226 deletions(-)
create mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..8e639cda8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,9 @@
+{
+ "editor.formatOnSave": false,
+ "[html][phtml]": {
+ "editor.formatOnSave": false
+ },
+ "[php]": {
+ "editor.formatOnSave": false
+ }
+}
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml
index 230b58619..75287d4d4 100644
--- a/app/views/docs/functions-recipes.phtml
+++ b/app/views/docs/functions-recipes.phtml
@@ -1,111 +1,213 @@
appwrite init functionSection 1: My First Function
+Getting Started
-Creating the function
-
-
-
module.exports = async function ({ res }) {
- return res.end('1.13');
+
+
+
+Node.js
+
-export default async function ({ res }) {
+ return res.send('1.13');
};
-git init
-git add index.js
-git commit -m "Initial commit"
-Section 2: Let's Use Payload
-
-Updating the function
-
-
-
module.exports = async function ({ req, res }) {
+ PHP
+
+ <?php
+return function ($context) {
+ return $context->res->send('1.13');
+};Python
+
+ def main(context):
+ return context.res.send('1.13')Dart
+
+ import 'dart:async';
+
+Future<dynamic> main(final context) async {
+ return context.res.send('1.13');
+}Ruby
+
+ def main(context)
+ return context.res.send('1.13')
+endCurrency Conversion
+
+
+
Node.js
+
-export default async function ({ req, res }) {
const amountInEuros = Number(req.query.amount);
const amountInDollars = amountInEuros * 1.13;
- return res.end(amountInDollars.toString());
+ return res.send(amountInDollars.toString());
};Testing the function
-
-
-
-
-Section 3: Installing Dependencies
-
-Preparing for dependencies
+ PHP
+
+ <?php
+return function ($context) {
+ $amountInEuros = $context->req->query['amount'];
+ $amountInDollars = $amountInEuros * 1.13;
+ return $context->res->send($amountInDollars);
+};
-
+Updating the function
-
-
Testing the function
-const { fetch } = require('undici');
+Adding Dependencies
+
+
+
+
+Node.js
+
+ npm init -y
+ npm install undiciUsing Dependencies
+
+
+
Node.js
+
-import { fetch } from 'undici';
+
+export default async function ({ req, res }) {
const amountInEuros = Number(req.query.amount);
- const response = await fetch('https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/eur/usd.json');
+ const response = await fetch('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
const data = await response.json();
- const amountInDollars = amountInEuros * data.usd;
- return res.end(amountInDollars.toString());
+ const amountInDollars = amountInEuros * data.rates.USD;
+ return res.send(amountInDollars.toString());
};Testing the function
-
-
-
-
-Section 4: More Routes
-
-Updating the function
-
-
-
-
-Testing the function
-
-
-
+ Adding More Routes
+
+
+
+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
+
+ def main(context):
+ amountInEuros = context.req.query['amount']
+ amountInDollars = amountInEuros * 1.13
+ return context.res.send(amountInDollars)Dart
+
+ import 'dart:async';
+
+Future<dynamic> main(final context) async {
+ final amountInEuros = context.req.query['amount'];
+ final amountInDollars = amountInEuros * 1.13;
+ return context.res.send(amountInDollars);
+}Ruby
+
+ def main(context)
+ amountInEuros = context.req.query['amount']
+ amountInDollars = amountInEuros * 1.13
+ return context.res.send(amountInDollars)
+endnpm install undiciPHP
+
+ composer init -y
+ composer require guzzlehttp/guzzlePython
+
+ touch requirements.txt
+ echo "requests" >> requirements.txt
+pip -r requirements.txt
+ Dart
+
+
+ name: appwrite_function
+description: Appwrite Function
+version: 1.0.0
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+
+ pub install http
+
+ Ruby
+
+
+ source 'https://rubygems.org'
+
+ echo "gem 'httparty'" >> Gemfile
+bundle installPHP
+
+ <?php
+
+require(__DIR__ . '/../vendor/autoload.php');
+
+use GuzzleHttp\Client;
+
+return function ($context) {
+ $amountInEuros = $context->getRequest()->getQuery('amount');
+ $client = new Client();
+ $response = $client->get('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
+ $data = json_decode($response->getBody(), true);
+ $amountInDollars = $amountInEuros * $data['rates']['USD'];
+ return $context->res->send(strval($amountInDollars));
+};Python
+
+ import requests
+
+def main(context):
+ 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))Dart
+
+ import 'dart:async';
+import 'package:http/http.dart' as http;
+
+Future<dynamic> main(final context) async {
+ 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());
+}Ruby
+
+ require 'httparty'
+
+def main(context)
+ 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)
+endPython
+
+ 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.request.path == '/eur'
+ amount_in_euros = context.request.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.response.send(amount_in_dollars.to_s)
+ end
+
+ if context.request.path == '/inr'
+ amount_in_rupees = context.request.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.response.send(amount_in_dollars.to_s)
+ end
+
+ return 'Invalid path'
+end
Node.js
-
-
- PHP
-
-
-
- Python
-
-
-
- Ruby
-
+
-
- export default async function ({ req, res, log, error }) {
+ log('This is a log!');
+ error('This is an error!');
+ return res.send(`This function was called with ${req.method} method!`)
+}Deno
-
-
- Dart
-
-
-
- Swift
-
-
-
- .NET
-
-
-
- Kotlin
-
-
-
- Java
-
-
-
- C++
-
+
-
- export default async function ({ req, res, log, error }: any) {
+ log('This is a log!');
+ error('This is an error!');
+ return res.send(`This function was called with ${req.method} method!`)
+}
export default async ({ req, res, log }) => {
- log(req.bodyString); // Raw request body, contains request data
+ log(req.bodyRaw); // Raw request body, contains request data
log(req.body); // Body parsed on content-type, only supports JSON
log(req.headers); // Request headers
log(req.scheme); // Value of the x-forwarded-proto header, usually http or https
@@ -538,7 +538,97 @@
You can access the environment variables through the systems library of each language.
-[TODO: @luke show how you access environment varibles for every language (sorry for the pain!)]
+
+ -
+
Node.js
+
+
+ process.env.MY_VAR
+
+
+
+ -
+
PHP
+
+
+ getenv('MY_VAR')
+
+
+
+ -
+
Python
+
+
+ os.environ['MY_VAR']
+
+
+
+ -
+
Ruby
+
+
+ ENV['MY_VAR']
+
+
+
+ -
+
Deno
+
+
+ Deno.env.get('MY_VAR')
+
+
+
+ -
+
Dart
+
+
+ Platform.environment['MY_VAR']
+
+
+
+ -
+
Swift
+
+
+ ProcessInfo.processInfo.environment["MY_VAR"]
+
+
+
+ -
+
.NET
+
+
+ Environment.GetEnvironmentVariable("MY_VAR")
+
+
+
+ -
+
Kotlin
+
+
+ System.getenv("MY_VAR")
+
+
+
+
+ -
+
Java
+
+
+ System.getenv("MY_VAR")
+
+
+
+ -
+
C++
+
+
+ std::getenv("MY_VAR")
+
+
+
+
Depencies
From df0754825a99e89179ba643178f9463ee1960f09 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Tue, 8 Aug 2023 15:10:29 +0100
Subject: [PATCH 25/80] feat: discussion
---
app/views/docs/functions-develop.phtml | 22 +++--
app/views/docs/functions-execute.phtml | 119 ++++++++++++++++++++++++-
app/views/docs/functions-recipes.phtml | 117 ++++++++++++------------
app/views/docs/functions.phtml | 4 +-
4 files changed, 195 insertions(+), 67 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 998b51f6a..0ff6a2dca 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -102,8 +102,8 @@
export default async ({ req, res, log }) => {
log(req.bodyRaw); // Raw request body, contains request data
- log(req.body); // Body parsed on content-type, only supports JSON
- log(req.headers); // Request headers
+ log(JSON.stringify(req.body)); // Body parsed on content-type, only supports JSON
+ log(JSON.stringify(req.headers)); // Request headers
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
@@ -235,13 +235,13 @@
export default async ({ req, res, log }) => {
- switch (req.body) {
+ switch (req.query.type) {
case 'send':
return res.send(
"This is a text response",
200,
{
- "content-type": "application/text"
+ "content-type": "text/plain"
}
);
case 'json':
@@ -630,10 +630,22 @@
-Depencies
+Dependencies
[TODO: @luke is this different for every language? Idk what to put here, do we need to also @matej?]
+- The NodeJS runtime has npm installed.
+- The PHP runtime has composer installed.
+- The Python runtime has pip installed.
+- The Ruby runtime has bundler installed.
+- The Deno runtime has deno installed.
+- The Dart runtime has pub installed.
+- The Swift runtime has swift installed.
+- The .NET runtime has nuget installed.
+- The Kotlin runtime has gradle installed.
+- The Java runtime has gradle installed.
+
+
Using Appwrite in a Function
[TODO: @luke @matej 2 examples -> JWT and API keys]
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 387ca1dc3..d3080d5c1 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -16,9 +16,126 @@
SDK
[TODO: @luke @matej, two examples running the function sync and async form the SDK]
-
+ You can invoke your Appwrite Functions directly from the Appwrite SDKs.
+Learn more about using the Appwrite SDKs
+
+
+ -
+
Node.js
+
+
+
+
+
+
+
+ -
+
PHP
+
+
+
+
+
+
+
+
+ -
+
Python
+
+
+
+
+
+
+
+
+ -
+
Ruby
+
+
+
+
+
+
+
+
+ -
+
Deno
+
+
+
+
+
+
+
+
+ -
+
Dart
+
+
+
+
+
+
+
+
+ -
+
Swift
+
+
+
+
+
+
+
+
+ -
+
.NET
+
+
+
+
+
+
+
+
+ -
+
Kotlin
+
+
+
+
+
+
+
+
+
+ -
+
Java
+
+
+
+
+
+
+
+
+ -
+
C++
+
+
+
+
+
+
+
+
+
+
+
+
Events
Changes in Appwrite emit events.
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml
index b5cb305a7..d8896f77c 100644
--- a/app/views/docs/functions-recipes.phtml
+++ b/app/views/docs/functions-recipes.phtml
@@ -15,8 +15,8 @@
-
Node.js
- Create a new file, `index.js`.
- Add the following code to `index.js`.
+ Create a new file, index.js.
+ Add the following code to index.js.
export default async function ({ res }) {
return res.send('1.13');
@@ -27,12 +27,12 @@
-
PHP
- Create a new file, `index.php`.
- Add the following code to `index.php`.
+ Create a new file, index.php.
+ Add the following code to index.php.
<?php
return function ($context) {
- return $context->res->send('1.13');
+ return $context->res->send('1.13');
};
@@ -40,8 +40,8 @@ return function ($context) {
-
Python
- Create a new file, `index.py`.
- Add the following code to `index.py`.
+ Create a new file, index.py.
+ Add the following code to index.py.
def main(context):
return context.res.send('1.13')
@@ -51,12 +51,12 @@ return function ($context) {
-
Dart
- Create a new file, `index.dart`.
- Add the following code to `index.dart`.
+ Create a new file, index.dart.
+ Add the following code to index.dart.
import 'dart:async';
-Future<dynamic> main(final context) async {
+Future<dynamic> main(final context) async {
return context.res.send('1.13');
}
@@ -65,8 +65,8 @@ Future<dynamic> main(final context) async {
-
Ruby
- Create a new file, `index.rb`.
- Add the following code to `index.rb`.
+ Create a new file, index.rb.
+ Add the following code to index.rb.
def main(context)
return context.res.send('1.13')
@@ -76,20 +76,20 @@ end
-This code will return `1.13` when the function is called, because 1€ equals approximately 1.13$.
+This code will return 1.13 when the function is called, because 1€ equals approximately 1.13$.
Now, create a function in the Appwrite console, adding your Git repository as the remote source and using the path file you created as the entry point.
-- Finally, execute the function and visit the URL (like `ghrfu9ewji.functions.appwrite.app`) to see the response.
+- Finally, execute the function and visit the URL (like
ghrfu9ewji.functions.appwrite.app) to see the response.
Currency Conversion
Now, let's update the function to use the request payload.
-You can use a query string to pass data to your function. For example, `ghrfu9ewji.functions.appwrite.app?amount=5` will pass `5` as the `amount` parameter.
+You can use a query string to pass data to your function. For example, ghrfu9ewji.functions.appwrite.app?amount=5 will pass 5 as the amount parameter.
-
Node.js
- Update `index.js` to use `req.query.amount` to access the `amount` parameter, and return the conversion result.
+ Update index.js to use req.query.amount to access the amount parameter, and return the conversion result.
export default async function ({ req, res }) {
const amountInEuros = Number(req.query.amount);
@@ -102,13 +102,13 @@ end
-
PHP
- Update `index.php` to use `$context->req->query['amount']` to access the `amount` parameter, and return the conversion result.
+ Update index.php to use $context->req->query['amount'] to access the amount parameter, and return the conversion result.
<?php
return function ($context) {
- $amountInEuros = $context->req->query['amount'];
+ $amountInEuros = $context->req->query['amount'];
$amountInDollars = $amountInEuros * 1.13;
- return $context->res->send($amountInDollars);
+ return $context->res->send($amountInDollars);
};
@@ -116,7 +116,7 @@ return function ($context) {
-
Python
- Update `index.py` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result.
+ Update index.py to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
def main(context):
amountInEuros = context.req.query['amount']
@@ -128,11 +128,11 @@ return function ($context) {
-
Dart
- Update `index.dart` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result.
+ Update index.dart to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
import 'dart:async';
-Future<dynamic> main(final context) async {
+Future<dynamic> main(final context) async {
final amountInEuros = context.req.query['amount'];
final amountInDollars = amountInEuros * 1.13;
return context.res.send(amountInDollars);
@@ -143,7 +143,7 @@ Future<dynamic> main(final context) async {
-
Ruby
- Update `index.rb` to use `context.req.query['amount']` to access the `amount` parameter, and return the conversion result.
+ Update index.rb to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
def main(context)
amountInEuros = context.req.query['amount']
@@ -161,10 +161,10 @@ end
Testing the function
- Execute the function and visit the URL (like `ghrfu9ewji.functions.appwrite.app?amount=5`) to see the response.
+ Execute the function and visit the URL (like ghrfu9ewji.functions.appwrite.app?amount=5) to see the response.
- You should see the result of the conversion, like `5.65`.
+ You should see the result of the conversion, like 5.65.
Adding Dependencies
@@ -173,45 +173,45 @@ end
-
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.
+ 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.
+ 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.
+ Finally, add npm install to your function's build commands in the Appwrite console.
-
PHP
You can use Composer to manage your PHP project's dependencies. Install it from getcomposer.org/download.
- Run the following bash command to create a `composer.json` file. This file is used to manage your PHP project's dependencies.
+ 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.
+ 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.
+ 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.
+ 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.
+ Install the requests library. This library includes a get function that you can use to make HTTP requests.
- echo "requests" >> requirements.txt
+ echo "requests" >> requirements.txt
pip -r requirements.txt
- Finally, add `pip install -r requirements.txt` to your function's build commands in the Appwrite console.
+ Finally, add pip install -r requirements.txt to your function's build commands in the Appwrite console.
-
@@ -220,25 +220,25 @@ pip -r requirements.txt
- Create a `pubspec.yaml` file with the following contents. This file is used to manage your Dart project's dependencies.
+ 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'
+ 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.
+ 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.
+ Finally, add pub get to your function's build commands in the Appwrite console.
@@ -248,21 +248,21 @@ environment:
- Create a `Gemfile` file with the following contents. This file is used to manage your Ruby project's dependencies.
+ 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.
+ Install the httparty library. This library includes a get function that you can use to make HTTP requests.
- echo "gem 'httparty'" >> Gemfile
+ echo "gem 'httparty'" >> Gemfile
bundle install
- Finally, add `bundle install` to your function's build commands in the Appwrite console.
+ Finally, add bundle install to your function's build commands in the Appwrite console.
@@ -274,7 +274,7 @@ bundle install
-
Node.js
- Use `fetch` from `undici` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
+ Use fetch from undici to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
import { fetch } from 'undici';
@@ -300,12 +300,12 @@ require(__DIR__ . '/../vendor/autoload.php');
use GuzzleHttp\Client;
return function ($context) {
- $amountInEuros = $context->getRequest()->getQuery('amount');
+ $amountInEuros = $context->getRequest()->getQuery('amount');
$client = new Client();
- $response = $client->get('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
- $data = json_decode($response->getBody(), true);
+ $response = $client->get('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
+ $data = json_decode($response->getBody(), true);
$amountInDollars = $amountInEuros * $data['rates']['USD'];
- return $context->res->send(strval($amountInDollars));
+ return $context->res->send(strval($amountInDollars));
};
@@ -313,7 +313,7 @@ return function ($context) {
-
Python
- Use `get` from `requests` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
+ Use get from requests to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
import requests
@@ -329,12 +329,12 @@ def main(context):
-
Dart
- Use `get` from `http` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
+ Use get from http to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
import 'dart:async';
import 'package:http/http.dart' as http;
-Future<dynamic> main(final context) async {
+Future<dynamic> main(final context) async {
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);
@@ -347,7 +347,7 @@ Future<dynamic> main(final context) async {
-
Ruby
- Use `get` from `httparty` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
+ Use get from httparty to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
require 'httparty'
@@ -368,7 +368,7 @@ end
Adding More Routes
-Let's add support multiple paths like `/eur` and `/inr`. Each path will convert from that currency to dollars.
+Let's add support multiple paths like /eur and /inr. Each path will convert from that currency to dollars.
-
@@ -434,7 +434,7 @@ def main(context):
import 'dart:async';
import 'package:http/http.dart' as http;
-Future<dynamic> main(final context) async {
+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'));
@@ -488,24 +488,21 @@ end
-After your function has updated, you can try out the new paths. For example, `ghrfu9ewji.functions.appwrite.app/eur?amount=5` should convert Euros to Dollars, while `ghrfu9ewji.functions.appwrite.app/inr?amount=100` should convert Indian Rupees to Dollars.
+After your function has updated, you can try out the new paths. For example, ghrfu9ewji.functions.appwrite.app/eur?amount=5 should convert Euros to Dollars, while ghrfu9ewji.functions.appwrite.app/inr?amount=100 should convert Indian Rupees to Dollars.
Congratulations! You've built a powerful currency conversion function using Appwrite!
-[TODO: @luke -> translate code for other runtimes]
-
-[TODO: @matej @luke -> Example with JWT, show both client and server code]
+[TODO: @luke -> Example with JWT, show both client and server code]
+[TODO: @luke -> Example with API Key]
From a11daf828fcb4f7620489526072675c094ce1cfa Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 14 Aug 2023 19:57:00 +0000
Subject: [PATCH 43/80] Add information about environment variables that now
became headers
---
app/views/docs/functions-develop.phtml | 20 +++++++++++++++++++-
app/views/docs/functions.phtml | 3 +++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index fd43c4d4a..d32bdd973 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -26,7 +26,7 @@
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.
+ All input, output, anddlogging **must be** handled through the context object passed in.
You'll find these properties in the context object.
@@ -940,6 +940,24 @@ namespace runtime {
Environmental variables can be global, or function specific.
+Default Environment Variables
+Appwrite Runtimes have some default environment variables. These are always accesible
+
+
+
+ Variable
+ Description
+
+
+
+
+
+
+
+
+
+
+
Local Environment Variables
Local variables will only be accessible in the function they belong to.
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 686e75906..93715532d 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -299,5 +299,8 @@ So it's important to be able to log, debug, and test your Appwrite Functions in
This prevents confusing errors when functions are terminated prematurely before a response is sent.
Learn about response.
+
-
+ Some variables about how a function was triggered are now found in the
context.req object as headers.
+
From d3645b2d4b22e565e9e8ac85974f8fa4af8a0784 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 14 Aug 2023 20:44:50 +0000
Subject: [PATCH 44/80] Move upgrade checklist to develop
---
app/views/docs/functions-develop.phtml | 49 +++++++++++++++++++++++++-
app/views/docs/functions.phtml | 49 +-------------------------
2 files changed, 49 insertions(+), 49 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index d32bdd973..42771b3ae 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -2069,4 +2069,51 @@ public class Main {
Explore examples and recipes
-
\ No newline at end of file
+
+
+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.
+
+
+
+ -
+ The parameter passed into functions has changed.
+
req and res has been replaced by context, which contains new logger methods.
+ Learn about context.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ Some variables about how a function was triggered are now found in the
context.req object as headers.
+
+
\ No newline at end of file
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 93715532d..a014e4511 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -193,6 +193,7 @@ namespace runtime {
+[TODO: explore features should be like: Familiar HTTP concepts, many ways to execute, deploy from Git or xxx, built in templates, etc.]
Explore Features
@@ -256,51 +257,3 @@ So it's important to be able to log, debug, and test your Appwrite Functions in
Learn more about debugging functions
-
-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.
-
-
-
- -
- The parameter passed into functions has changed.
-
req and res has been replaced by context, which contains new logger methods.
- Learn about context.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- Some variables about how a function was triggered are now found in the
context.req object as headers.
-
-
-
From 1ffc8e293eef1a4ac0cbd795f65c8bc8c3857bbc Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 14 Aug 2023 21:00:37 +0000
Subject: [PATCH 45/80] Add cloud/self-hosted tags as labels in runtimes
---
app/views/docs/functions-runtimes.phtml | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 0a1e057e9..63d29e494 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -4,7 +4,12 @@ use Appwrite\Utopia\View;
$events = $this->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;
?>
@@ -26,6 +31,7 @@ $runtimes = $this->getParam('runtimes', []);
Name
Image
Architectures
+ Platforms
@@ -35,6 +41,12 @@ $runtimes = $this->getParam('runtimes', []);
escape($key); ?>
escape($runtime['image'] ?? ''); ?>
escape(implode(' / ', $runtime['supports'] ?? [])); ?>
+
+
+ Cloud
+
+ Self-hosted
+
From ca020879140790bfc666581366e531c570c01538 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 14 Aug 2023 23:21:35 +0000
Subject: [PATCH 46/80] Some minor improvements
---
app/views/docs/functions-deploy.phtml | 6 ++++-
app/views/docs/functions-execute.phtml | 32 ++++++++++++++++++-------
app/views/docs/functions-runtimes.phtml | 10 ++++----
3 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index c16a93e3d..0fac2e804 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -160,4 +160,8 @@
- Upload
code.tar.gz.
- Select Activate deployment after build to use your new function.
- Click Create to deploy your function.
-
\ No newline at end of file
+
+
+Domains
+
+[TODO: @matej steps to add a custom domain thanks]
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 88ca4327d..dbfb93d9c 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -4,11 +4,21 @@
Here are all the different ways to consume your new Appwrite Functions.
-Domain
+Domains
- Each Appwrite function has its own domain. You can find this in the Appwrite Console, under the Function overview.
- It looks something like this.https://64d4d22db370ae41a32e.functions.cloud.appwrite.io
- Alternatively you can add a custom domain to your Appwrite project, and use that instead.
+ 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.functions.cloud.appwrite.io
+
+
+
+ Alternatively you can add a custom domain to your Appwrite project.
@@ -18,10 +28,12 @@
REST API
-curl -X POST [APPWRITE_FUNCTION_DOMAIN] \
--H "X-Custom-Header: 123" \
--H "Content-Type: application/json" \
--d '{"foo":"bar"}'
+
+ curl -X POST https://64d4d22db370ae41a32e.functions.cloud.appwrite.io \
+ -H "X-Custom-Header: 123" \
+ -H "Content-Type: application/json" \
+ -d '{"data":"this is json data"}'
+
SDK
@@ -455,6 +467,8 @@ public static void main(String[] args) throws Exception {
Permissions
+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.
@@ -466,7 +480,7 @@ public static void main(String[] args) throws Exception {
If you need to enforce permissions for functions with a domain, use authentication methods like JWT.
-Logs and results
+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 it's executions.
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 63d29e494..cce760392 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -15,14 +15,12 @@ $runtimes['dart-2.17']["cloud"] = true;
Appwrite Functions supports an extensive list of runtimes to meet your unique tech preferences.
- Not all runtimes are available on Appwrite Cloud, check for the Cloud label in each listed runtime to know whichones are available.
+ Not all runtimes are available on Appwrite Cloud, check for the Cloud label in each listed runtime to know which ones are available.
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.
+Below is a list of supported Functions runtimes. The Appwrite team continually adds support for new runtimes.
@@ -52,4 +50,6 @@ $runtimes['dart-2.17']["cloud"] = true;
-[TODO: @matej Label which ones are cloud only, idk how to do cleanly]
+
+
- Learn more about permissions
+
\ No newline at end of file
From dbabc60a9d10d266804cb20e3796b96a791882cc Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 14 Aug 2023 23:24:35 +0000
Subject: [PATCH 47/80] Moved a p tag
---
app/views/docs/functions-execute.phtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index dbfb93d9c..54335a66b 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -21,13 +21,13 @@
Alternatively you can add a custom domain to your Appwrite project.
+REST API
When requests are made to this domain, whether through a browser or through an HTTP requests,
the request information like request headers and request body will be passed to the function.
This unlocks interesting ways to integrate other apps and backends to your Appwrite project.
-REST API
curl -X POST https://64d4d22db370ae41a32e.functions.cloud.appwrite.io \
-H "X-Custom-Header: 123" \
From 54097a42de357adf7e6ba1b668607241b1d043b1 Mon Sep 17 00:00:00 2001
From: "Luke B. Silver" <22452787+loks0n@users.noreply.github.com>
Date: Tue, 15 Aug 2023 13:20:29 +0100
Subject: [PATCH 48/80] fix: remove vscode settings
---
.vscode/settings.json | 9 ---------
1 file changed, 9 deletions(-)
delete mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 8e639cda8..000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "editor.formatOnSave": false,
- "[html][phtml]": {
- "editor.formatOnSave": false
- },
- "[php]": {
- "editor.formatOnSave": false
- }
-}
From b04e153eb7576ebb35aeb57b26d8e415c58067f3 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Tue, 15 Aug 2023 21:07:54 +0000
Subject: [PATCH 49/80] sell functions better in overview
---
app/views/docs/functions.phtml | 51 +++++++++++++---------------------
1 file changed, 20 insertions(+), 31 deletions(-)
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index a014e4511..971ac5fac 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -202,58 +202,47 @@ namespace runtime {
To fully harness the power of Appwrite Functions, explore the following features.
-Templates
+Familiar Concepts
- If you need to integrate Appwrite with a third-party API or add a function for common utilities,
- there might already be a function template made by the Appwrite community that fits your needs.
- Function templates are Appwrite Functions repositories that you can clone and add to your Appwrite instance.
+ Appwrite Functions follow common HTTP concepts you already know.
+ You can start building with minimal learning curve, without needing to learn niche concepts that don't apply elsewhere.
-
-Learn more about using function templates
-
-
-Develop
-
-Writing Appwrite Functions should feel familiar to writing controllers in an HTTP server.
-In your function, you'll receive a request object, add transformations and logic, then return a response.
-Almost anything can be executed as code in an Appwrite Function.
-
Learn more about developing functions
-Deploy
+Automated Deployment
- Appwrite Functions are designed to be maintainable and fit into a familiar development workflow.
- You can deploy them from a GitHub repository branch or using the Appwrite CLI.
+ Appwrite Functions can be deployed automatically from GitHub.
+ Integrate Appwrite Functions seemlessly into your existing development workflow, without needing annoying CI/CD configuration.
-Learn more about using deploying functions
+Learn more about deploying functions
-Execute
+Flexible Execution
-Appwrite Functions can be executed directly through a request to the API, or triggered by events, webhooks, or scheduled executions.
-This flexible execution models unlocks many potential usecases for Appwrite functions.
-Explore using Appwrite Functions to execute a complex routine of logic, or execute background tasks on a schedule.
+ Appwrite Functions can be executed through HTTP requests, async or synchronous SDK calls, webhooks, event or scheduled triggers, and even serve webpages to browsers.
+ Integrate Appwrite with infinite possibilities through a simple function.
-Learn more about using executing functions
+Learn more about executing functions
-Runtime
+All Your Favorite Runtimes
-Appwrite supports many open-source runtimes. Find your prefered language and start writing your functions.
+ Appwrite supports a growing list of 10+ runtimes.
+ Keep your codebase simple by writing functions in a language you already work with.
-Learn more about using runtimes
+Learn more about using function runtimes
-Debug
+Start with a Template
-Let's be honest, we spend more time debugging our code than writing our code.
-So it's important to be able to log, debug, and test your Appwrite Functions in development and production.
+ Appwrite Functions has many built in templates that help you jumpstart your creativity.
+ Add integrations by using templates out of the box, or clone the template to customize and fit your needs.
-Learn more about debugging functions
-
+Learn more about using function templates
+
\ No newline at end of file
From f088a1e8114b0562ef5cbea23d82a899bd0ddf5a Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 17 Aug 2023 03:09:04 +0000
Subject: [PATCH 50/80] Add headers + env vars
---
app/views/docs/functions-develop.phtml | 109 ++++++++++++++++++++++++-
app/views/docs/functions.phtml | 1 -
2 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 42771b3ae..0fde8fa78 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -353,6 +353,67 @@ public class Main {
+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.
+
+
+
+
+
+ Variable
+ Description
+
+
+
+
+ x-appwrite-trigger
+
+ Describes how the function execution was invoked.
+
+
+
+ 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
+
+ [TODO: @meldiron whats this]
+
+
+
+ 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.
@@ -941,7 +1002,19 @@ namespace runtime {
Default Environment Variables
-Appwrite Runtimes have some default environment variables. These are always accesible
+
+ Appwrite runtimes passes in some environment variables by default.
+ These are always accesible 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.
+
+
+
@@ -951,13 +1024,43 @@ namespace runtime {
-
+ 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.
-
Local Environment Variables
Local variables will only be accessible in the function they belong to.
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 971ac5fac..970befc03 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -193,7 +193,6 @@ namespace runtime {
-[TODO: explore features should be like: Familiar HTTP concepts, many ways to execute, deploy from Git or xxx, built in templates, etc.]
Explore Features
From 2cd56dd807e90646a67e3c60989085f407b4faec Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 17 Aug 2023 22:34:44 +0000
Subject: [PATCH 51/80] Improve overview page for functions and rename recipes
to examples
---
app/views/docs/functions-develop.phtml | 10 +-
...recipes.phtml => functions-examples.phtml} | 0
app/views/docs/functions.phtml | 229 ++----------------
app/views/docs/index.phtml | 2 +-
4 files changed, 27 insertions(+), 214 deletions(-)
rename app/views/docs/{functions-recipes.phtml => functions-examples.phtml} (100%)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 0fde8fa78..84a562cc7 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -6,7 +6,7 @@
Just want the code?
- If you prefer to learn through examples, explore the recipes section.
+ If you prefer to learn through examples, explore the examples page.
Function Flow
@@ -2165,14 +2165,6 @@ public class Main {
-Recipes
-
- We have a dedicated page of recipes to implement common functionalities in Appwrite Functions, like parsing request path and params, or making requests to third party APIs.
-
-
-
-Explore examples and recipes
-
Upgrade
diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-examples.phtml
similarity index 100%
rename from app/views/docs/functions-recipes.phtml
rename to app/views/docs/functions-examples.phtml
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 970befc03..39b8c8a27 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -2,246 +2,67 @@
use Appwrite\Utopia\View;
-$events = $this->getParam('events', []);
-$runtimes = $this->getParam('runtimes', []);
-
?>
- Appwrite Functions let you extend Appwrite by adding your own code and logic.
- You can think of them as code snippets that are triggered by server events, webhooks, scheduled executions, or user invokation.
+ 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, scheduled executions.
Each function will have their own URL, execute in their own isolated container, and have their own configurable environment variables and permissions.
- With these features, Appwrite Functions unlock limitless potential to expand Appwrite's capabilities with custom logic and integrations.
Getting Started
- Appwrite Functions unlock limitless possibilities, but it's simple to get started. You can deploy your first function and execute it in minutes.
+ Appwrite Functions let you build anything you can imagine, but this flexibility makes is 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.
-
- -
-
Node.js
-
-
- export default async ({ res }) => {
- return res.json({
- motto: 'Build Fast. Scale Big. All in One Place.'
- });
-};
-
-
-
- -
-
PHP
-
-
- return function ($context) {
- return $context->res->json([
- 'motto' => 'Build Fast. Scale Big. All in One Place.'
- ]);
-}
-
-
-
- -
-
Python
-
-
- def main(context):
- return context.res.json({
- "motto": "Build Fast. Scale Big. All in One Place.",
-})
-
-
-
- -
-
Ruby
-
-
- def main(context)
- return context.res.json(
- {
- "motto": "Build Fast. Scale Big. All in One Place."
- }
- )
-end
-
-
-
- -
-
Deno
-
-
- export default ({ req, res, log, error }: any) => {
- return res.json({
- motto: "Build Fast. Scale Big. All in One Place."
- });
-};
-
-
-
- -
-
Dart
-
-
- import 'dart:async';
-
-Future main(final context) async {
- return context.res.json({
- 'motto': 'Build Fast. Scale Big. All in One Place.',
- });
-}
-
-
-
- -
-
Swift
-
-
- import Foundation
-
- func main(context: RuntimeContext) async throws -> RuntimeOutput {
- return try context.res.json([
- "motto": "Build Fast. Scale Big. All in One Place."
- ])
-}
-
-
-
- -
-
.NET
-
-
- namespace DotNetRuntime;
-public class Handler {
- public async Task Main(RuntimeContext Context)
- {
- return Context.Res.Json(new Dictionary()
- {
- { "motto", "Build Fast. Scale Big. All in One Place." }
- });
- }
-}
-
-
-
- -
-
Kotlin
-
-
- package io.openruntimes.kotlin.src
-
-import io.openruntimes.kotlin.RuntimeContext
-import io.openruntimes.kotlin.RuntimeOutput
-
-class Main {
- fun main(context: RuntimeContext): RuntimeOutput {
- return context.res.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;
-
-public class Main {
- public RuntimeOutput main(RuntimeContext context) throws Exception {
- Map json = new HashMap<>();
- json.put("motto", "Build Fast. Scale Big. All in One Place.");
- return context.getRes().json(json);
- }
-}
-
-
-
- -
-
C++
-
-
- #include "../RuntimeResponse.h"
-#include "../RuntimeRequest.h"
-#include "../RuntimeOutput.h"
-#include "../RuntimeContext.h"
-
-namespace runtime {
- class Handler {
- public:
- static RuntimeOutput main(RuntimeContext &context) {
- Json::Value response;
- response["motto"] = "Build Fast. Scale Big. All in One Place.";
- return context.res.json(response);
- }
- };
-}
-
-
-
-
-
+setParam('srcLight', '/images-ee/docs/functions-starter-light.png')
+ ->setParam('srcDark', '/images-ee/docs/functions-starter-dark.png')
+ ->setParam('alt', 'Function settings page.')
+ ->setParam('description', 'Function settings page.')
+ ->render();
+?>
Explore Features
- Appwrite Functions help you start small and scale big.
- Now you've created your first Appwrite Function, it's time to learn the different ways to develop, deploy, and execute your Appwrite Functions.
- To fully harness the power of Appwrite Functions, explore the following features.
-
-
-Familiar Concepts
-
- Appwrite Functions follow common HTTP concepts you already know.
- You can start building with minimal learning curve, without needing to learn niche concepts that don't apply elsewhere.
+ Appwrite Functions use familiar HTTP concepts, so you can learn quickly and grain transferable skills.
-
Learn more about developing functions
-Automated Deployment
- Appwrite Functions can be deployed automatically from GitHub.
- Integrate Appwrite Functions seemlessly into your existing development workflow, without needing annoying CI/CD configuration.
+ 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
-Flexible Execution
- Appwrite Functions can be executed through HTTP requests, async or synchronous SDK calls, webhooks, event or scheduled triggers, and even serve webpages to browsers.
- Integrate Appwrite with infinite possibilities through a simple function.
+ Appwrite Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, scheduled executions.
+ Explore how Appwrite Functions can be invoked.
Learn more about executing functions
-All Your Favorite Runtimes
- Appwrite supports a growing list of 10+ runtimes.
- Keep your codebase simple by writing functions in a language you already work with.
+ 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
-Start with a Template
+
- Appwrite Functions has many built in templates that help you jumpstart your creativity.
- Add integrations by using templates out of the box, or clone the template to customize and fit your needs.
+ Like to learn from examples?
+ Here's a curated list of examples that showcase Appwrite Function's capabilies.
-Learn more about using function templates
+Learn more about using function examples
\ No newline at end of file
diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml
index d82d95a21..f4cc3e7be 100644
--- a/app/views/docs/index.phtml
+++ b/app/views/docs/index.phtml
@@ -100,7 +100,7 @@ $cols = [
- Deploy
- Execute
- Runtimes
- - Recipes
+ - Examples
From e7b9b1cf6d48a301181da7e8e7257efff7336b48 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 17 Aug 2023 23:03:49 +0000
Subject: [PATCH 52/80] Fix style in index and add alt text to functions
---
app/views/docs/functions.phtml | 4 ++--
app/views/docs/index.phtml | 1 -
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 39b8c8a27..0dc52264d 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -22,8 +22,8 @@ $image = new View(__DIR__.'/../general/image.phtml');
echo $image
->setParam('srcLight', '/images-ee/docs/functions-starter-light.png')
->setParam('srcDark', '/images-ee/docs/functions-starter-dark.png')
- ->setParam('alt', 'Function settings page.')
- ->setParam('description', 'Function settings page.')
+ ->setParam('alt', '"Create Function" page.')
+ ->setParam('description', '"Create Function" page.')
->render();
?>
diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml
index f4cc3e7be..b1e885dbe 100644
--- a/app/views/docs/index.phtml
+++ b/app/views/docs/index.phtml
@@ -94,7 +94,6 @@ $cols = [
-
Functions
-
- Develop
- Deploy
From 780b5e408ce5b03df62ed4a474583b286d91a104 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Fri, 18 Aug 2023 15:53:48 +0000
Subject: [PATCH 53/80] Talk about JWT and trigger headers
---
app/views/docs/functions-develop.phtml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 84a562cc7..c3174a8c1 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -370,7 +370,8 @@ public class Main {
x-appwrite-trigger
- Describes how the function execution was invoked.
+ Describes how the function execution was invoked.
+ Possible values are http, schedule or event.
@@ -389,7 +390,8 @@ public class Main {
x-appwrite-user-jwt
- [TODO: @meldiron whats this]
+ JWT token generated from the invoking user's session. Used to authenticate Server SDKs to respect access permissions.
+ Learn more about JWT tokens.
From b2902ed45317760ea295233e8d4ea94a73294a8b Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Mon, 21 Aug 2023 20:19:15 +0000
Subject: [PATCH 54/80] Improve formatting and arrange items more logically
---
app/views/docs/functions-deploy.phtml | 4 +-
app/views/docs/functions-develop.phtml | 944 +++++++++++++++---------
app/views/docs/functions-execute.phtml | 21 +-
app/views/docs/functions-runtimes.phtml | 6 +-
4 files changed, 605 insertions(+), 370 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 0fac2e804..0244a4e5f 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -9,9 +9,9 @@
Here's everything you need to know to deploy your first Appwrite Function.
-Git
+VCS (Version Control System)
- The recommended way to manage your Appwrite Function deployments is to use 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.
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index c3174a8c1..aa5cfc8b1 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1,14 +1,8 @@
Appwrite Functions offer a familiar interface if you've developed REST endpoints.
Each function is handled following a request and response pattern.
- Here's what you need to know to start writing your first Appwrite Function.
-
- Just want the code?
- If you prefer to learn through examples, explore the examples page.
-
-
Function Flow
There is a clear flow for all Appwrite Functions, from beginning to end.
@@ -16,17 +10,443 @@
- - Invocation, where Appwrite receives a event to execute a Function. This event could be a request from an SDK, a request to the function's domain, a scheduled execution, or an execution triggered by an event within your Appwrite project.
- - After a function is invoked, Appwrite passes request information to your function's executor.
- - The executor runs the function code you deployed and waits for it to return.
- - Function terminates either when the user returns with a method from
res, when the user code throws an exception, or times out.
+ - The function is invoked.
+ - Appwrite passes in request information like headers and environment variables through the
context.req object.
+ - The runtime executes the code you defined, you can log through the
context.log or context.error methods.
+ - Function terminates when you return results using
context.res.
+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, anddlogging **must be** handled through the context object passed in.
+ All input, output, anddlogging must be handled through the context object passed in.
You'll find these properties in the context object.
@@ -58,11 +478,11 @@
+Destructuring Assignment
Some languages, namely JavaScript, support destructuring. You'll see us use destructing in examples, which has the following syntax.
-
Node.js
-
export default async function ({ req, res, log, error }) {
log('This is a log!');
@@ -70,11 +490,9 @@
return res.send(`This function was called with ${req.method} method!`)
}
-
-
Deno
-
export default async function ({ req, res, log, error }: any) {
log('This is a log!');
@@ -82,7 +500,6 @@
return res.send(`This function was called with ${req.method} method!`)
}
-
@@ -96,7 +513,6 @@
-
Node.js
-
export default async ({ req, res, log }) => {
log(req.bodyRaw); // Raw request body, contains request data
@@ -114,11 +530,9 @@
return res.send("All the request parameters are logged to the Appwrite Console.");
};
-
-
PHP
-
<?php
return function ($context) {
@@ -137,11 +551,9 @@ return function ($context) {
return $context->res->send("All the request parameters are logged to the Appwrite Console.");
}
-
-
Python
-
import json
@@ -160,11 +572,9 @@ def main(context):
return context.res.send("All the request parameters are logged to the Appwrite Console.")
-
-
Ruby
-
require 'json'
@@ -184,11 +594,9 @@ def main(context)
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
@@ -205,11 +613,9 @@ end
return res.send("All the request parameters are logged to the Appwrite Console.");
-
-
Dart
-
import 'dart:async';
import 'dart:convert';
@@ -230,11 +636,9 @@ Future<dynamic> main(final context) async {
return context.res.send("All the request parameters are logged to the Appwrite Console.");
}
-
-
Swift
-
import Foundation
import Foundation
@@ -255,11 +659,9 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return try context.res.send("All the request parameters are logged to the Appwrite Console.")
}
-
-
.NET
-
namespace DotNetRuntime;
@@ -284,11 +686,9 @@ public class Handler {
}
}
-
-
Kotlin
-
package io.openruntimes.kotlin.src
@@ -316,12 +716,9 @@ class Main {
}
}
-
-
-
Java
-
package io.openruntimes.java;
@@ -349,7 +746,6 @@ public class Main {
}
}
-
@@ -426,199 +822,115 @@ public class Main {
-
Node.js
-
export default async ({ req, res, log }) => {
switch (req.query.type) {
case 'text':
- return res.send(
- "This is a text response",
- 200
- );
+ return res.send("This is a text response", 200);
case 'json':
- return res.json(
- {
- "type": "This is a JSON response"
- },
- 200
- );
+ return res.json({"type": "This is a JSON response"}, 200);
case 'redirect':
- return res.redirect(
- "https://appwrite.io",
- 301
- );
+ return res.redirect("https://appwrite.io", 301);
case 'html':
return res.send(
- "<h1>This is an HTML response</h1>",
- 200,
- {
+ "<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
- );
+ return $context->res->send("This is a text response", 200);
case 'json':
- return $context->res->json(
- [
- "type" => "This is a JSON response"
- ],
- 200
- );
+ return $context->res->json(["type" => "This is a JSON response"], 200);
case 'redirect':
- return $context->res->redirect(
- "https://appwrite.io",
- 301
- );
+ 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"
- ]
- );
+ 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
- )
+ return context.res.send("This is a text response", 200)
case 'json':
- return context.res.json(
- {
- "type": "This is a JSON response"
- },
- 200
- )
+ return context.res.json({"type": "This is a JSON response"}, 200)
case 'redirect':
- return context.res.redirect(
- "https://appwrite.io",
- 301
- )
+ 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"
- }
- )
+ 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
- )
+ return context.res.send("This is a text response", 200)
when 'json'
- return context.res.json(
- {
- "type": "This is a JSON response"
- },
- 200
- )
+ return context.res.json({"type": "This is a JSON response"}, 200)
when 'redirect'
- return context.res.redirect(
- "https://appwrite.io",
- 301
- )
+ 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"
- }
- )
+ 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
- );
+ return res.send("This is a text response", 200);
case 'json':
- return res.json(
- {
- "type": "This is a JSON response"
- },
- 200
- );
+ return res.json({type": "This is a JSON response"}, 200);
case 'redirect':
- return res.redirect(
- "https://appwrite.io",
- 301
- );
+ return res.redirect("https://appwrite.io", 301);
case 'html':
return res.send(
- "<h1>This is an HTML response</h1>",
- 200,
- {
+ "<h1>This is an HTML response</h1>", 200, {
"content-type": "text/html"
- }
- );
+ });
default:
return res.empty();
}
}
-
-
Dart
-
import 'dart:async';
@@ -629,9 +941,7 @@ Future<dynamic> main(final context) async {
.send('This is a text response', 200);
case 'json':
return context.res
- .json({
- 'type': 'This is a JSON response'
- });
+ .json({'type': 'This is a JSON response'});
case 'redirect':
return context.res
.redirect('https://appwrite.io', 301);
@@ -646,11 +956,9 @@ Future<dynamic> main(final context) async {
}
}
-
-
Swift
-
import Foundation
@@ -663,17 +971,17 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
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"])
+ 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;
@@ -689,18 +997,18 @@ public class Handler {
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" } });
+ 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
@@ -719,11 +1027,9 @@ class Main {
}
}
-
-
Java
-
package io.openruntimes.java.src;
@@ -751,11 +1057,9 @@ public class Main {
}
}
-
-
C++
-
#include "../RuntimeResponse.h"
#include "../RuntimeRequest.h"
@@ -787,7 +1091,6 @@ namespace runtime {
};
}
-
@@ -802,7 +1105,6 @@ namespace runtime {
-
Node.js
-
export default async ({ res, log, error }) => {
log("This is a log, use for logging information to console");
@@ -812,11 +1114,9 @@ namespace runtime {
return res.send("Check the Appwrite Console to see logs and errors!");
};
-
-
PHP
-
<?php
@@ -828,11 +1128,9 @@ return function ($context) {
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")
@@ -841,11 +1139,9 @@ return function ($context) {
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")
@@ -855,11 +1151,9 @@ return function ($context) {
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");
@@ -869,11 +1163,9 @@ end
return res.send("Check the Appwrite Console to see logs and errors!");
};
-
-
Dart
-
import 'dart:async';
@@ -885,11 +1177,9 @@ Future<dynamic> main(final context) async {
return context.send("Check the Appwrite Console to see logs and errors!");
}
-
-
Swift
-
import Foundation
@@ -901,11 +1191,9 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return try context.send("Check the Appwrite Console to see logs and errors!")
}
-
-
.NET
-
namespace DotNetRuntime;
@@ -920,11 +1208,9 @@ public class Handler {
}
}
-
-
Kotlin
-
package io.openruntimes.kotlin.src
@@ -941,11 +1227,9 @@ class Main {
}
}
-
-
Java
-
package io.openruntimes.java.src;
@@ -962,11 +1246,9 @@ public class Main {
}
}
-
-
C++
-
#include "../RuntimeResponse.h"
#include "../RuntimeRequest.h"
@@ -986,7 +1268,6 @@ namespace runtime {
};
}
-
You can access these logs through the following steps.
@@ -1057,16 +1338,17 @@ namespace runtime {
APPWRITE_FUNCTION_RUNTIME_VERSION
+
The runtime version of the running function.
-
+
Local Environment Variables
- Local variables will only be accessible in the function they belong to.
- Local variables will override global variables when they have conflicting names.
+ Local environment variables will only be accessible in the function they belong to.
+ Local environment variables will override global environment variables when they have conflicting names.
- In Appwrite Console, navigate to Functions.
@@ -1075,10 +1357,10 @@ namespace runtime {
- Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
-Global Variables
+Global Environment Variables
- Global variables are accessible to all Appwrite Functions.
- Local variables will override global variables when they have conflicting names.
+ Global environment variables are accessible to all Appwrite Functions.
+ Local environment variables will override global environment variables when they have conflicting names.
- In Appwrite Console, navigate to your project's Settings page.
@@ -1093,7 +1375,6 @@ namespace runtime {
-
Node.js
-
process.env.MY_VAR
@@ -1101,7 +1382,6 @@ namespace runtime {
-
PHP
-
getenv('MY_VAR')
@@ -1109,75 +1389,57 @@ namespace runtime {
-
Python
-
os.environ['MY_VAR']
-
-
Ruby
-
ENV['MY_VAR']
-
-
Deno
-
Deno.env.get('MY_VAR')
-
-
Dart
-
Platform.environment['MY_VAR']
-
-
Swift
-
ProcessInfo.processInfo.environment["MY_VAR"]
-
-
.NET
-
Environment.GetEnvironmentVariable("MY_VAR")
-
-
Kotlin
-
System.getenv("MY_VAR")
-
-
Java
-
System.getenv("MY_VAR")
-
-
C++
-
std::getenv("MY_VAR")
-
@@ -1196,7 +1458,7 @@ namespace runtime {
Language
Package Manager
- Install Command
+ Commands
@@ -1262,13 +1524,15 @@ namespace runtime {
Authenticating with Appwrite is done via an API key or a JWT token. You can read more about authentication in the Server Authentication section of the docs.
-
-
-Using JWT
+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';
@@ -1277,13 +1541,9 @@ export default async ({ req, res, log }) => {
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);
- if (req.headers['x-appwrite-jwt']) {
- client.setJWT(req.headers['x-appwrite-jwt'])
- } else {
- return res.send("Please sign in, JWT not found")
- }
-
const databases = new Databases(client);
try {
@@ -1295,11 +1555,9 @@ export default async ({ req, res, log }) => {
return res.send("Document created")
}
-
-
PHP
-
<?php
@@ -1315,12 +1573,8 @@ return function ($context) {
$client
->setEndpoint('https://cloud.appwrite.io/v1')
->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
-
- if (isset($context->req->headers['x-appwrite-jwt'])) {
- $client->setJWT($context->req->headers['x-appwrite-jwt']);
- } else {
- return $context->res->send("Please sign in, JWT not found");
- }
+ // Pass in your API key as an environment variable. Never share API keys with users.
+ ->setKey(getenv('APPWRITE_API_KEY'));
$databases = new Databases($client);
@@ -1333,11 +1587,9 @@ return function ($context) {
return $context->res->send("Document created");
};
-
-
Python
-
from appwrite.client import Client
from appwrite.services.databases import Databases
@@ -1345,19 +1597,15 @@ 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"])
)
- if "x-appwrite-jwt" in context.req.headers:
- client.set_jwt(context.req.headers["x-appwrite-jwt"])
- else:
- return context.res.send("Please sign in, JWT not found")
-
databases = Databases(client)
try:
@@ -1367,11 +1615,9 @@ def main(context):
return context.response.send("Document created")
-
-
Ruby
-
require "appwrite"
@@ -1380,12 +1626,8 @@ def main(context)
client
.set_endpoint('https://cloud.appwrite.io/v1')
.set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
-
- if context.request.headers['x-appwrite-jwt']
- client.set_jwt(context.request.headers['x-appwrite-jwt'])
- else
- return context.response.send("Please sign in, JWT not found")
- end
+ # 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)
@@ -1398,11 +1640,9 @@ def main(context)
return context.response.send("Document created")
end
-
-
Deno
-
import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
@@ -1411,12 +1651,8 @@ export default function ({req, res}: any){
client
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
-
- if (req.headers["x-appwrite-jwt"]) {
- client.setJWT(req.headers["x-appwrite-jwt"]);
- } else {
- return res.send("Please sign in, JWT not found");
- }
+ // 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);
@@ -1429,11 +1665,9 @@ export default function ({req, res}: any){
return res.send("Document created");
}
-
-
Dart
-
import 'dart:async';
import 'package:dart_appwrite/dart_appwrite.dart';
@@ -1443,12 +1677,8 @@ 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-jwt'] != null) {
- client.setJWT(context.req.headers['x-appwrite-jwt']);
- } else {
- return context.res.send("Please sign in, JWT not found");
- }
+ // 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);
@@ -1461,11 +1691,9 @@ Future<dynamic> main(final context) async {
return context.res.send("Document created");
}
-
-
Swift
-
import Appwrite
import AppwriteModels
@@ -1475,12 +1703,8 @@ 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-jwt"] {
- client.setJWT(jwt)
- } else {
- return context.res.send("Please sign in, JWT not found")
- }
+ // 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)
@@ -1493,11 +1717,9 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return context.res.send("Document created")
}
-
-
.NET
-
namespace DotNetRuntime;
@@ -1512,30 +1734,24 @@ public class Handler {
var client = new Client()
.SetEndpoint("http://cloud.appwrite.io/v1")
.SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
-
- if (Context.Req.Headers.ContainsKey("x-appwrite-jwt")) {
- client.SetJWT(Context.Req.Headers["x-appwrite-jwt"]);
- } else {
- return Context.Res.Send("Please sign in, JWT not found");
- }
+ // 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) {
- return Context.Res.Send("We messed up, document not created");
+ return Context.Response.Send("We messed up, document not created");
}
- return Context.Res.Send("Document created");
+ return Context.Response.Send("Document created");
}
}
-
-
Kotlin
-
package io.openruntimes.kotlin.src
@@ -1551,12 +1767,8 @@ class Main {
val client = Client().apply {
setEndpoint("https://cloud.appwrite.io/v1")
setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
- }
-
- if (context.req.headers["x-appwrite-jwt"] != null) {
- client.setJWT(context.req.headers["x-appwrite-jwt"])
- } else {
- return context.res.send("Please sign in, JWT not found")
+ // 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)
@@ -1571,11 +1783,9 @@ class Main {
}
}
-
-
Java
-
package io.openruntimes.java.src;
@@ -1590,12 +1800,8 @@ public class Main {
client
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
-
- if (context.req.headers.containsKey("x-appwrite-jwt")) {
- client.setJWT(context.req.headers.get("x-appwrite-jwt"));
- } else {
- return context.res.send("Please sign in, JWT not found");
- }
+ // 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);
@@ -1610,15 +1816,24 @@ public class Main {
}
}
-
-Using with API Key
+
+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';
@@ -1627,9 +1842,13 @@ export default async ({ req, res, log }) => {
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
- // Put your secret key in environment variables, so it doesn't leak
- .setKey(process.env.APPWRITE_API_KEY);
+ 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 {
@@ -1641,11 +1860,9 @@ export default async ({ req, res, log }) => {
return res.send("Document created")
}
-
-
PHP
-
<?php
@@ -1661,8 +1878,12 @@ return function ($context) {
$client
->setEndpoint('https://cloud.appwrite.io/v1')
->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
- // Put your secret key in environment variables, so it doesn't leak
- ->setKey(getenv('APPWRITE_API_KEY'));
+
+ 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);
@@ -1675,11 +1896,9 @@ return function ($context) {
return $context->res->send("Document created");
};
-
-
Python
-
from appwrite.client import Client
from appwrite.services.databases import Databases
@@ -1693,10 +1912,13 @@ def main(context):
Client()
.set_endpoint("https://cloud.appwrite.io/v1")
.set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"])
- # Put your secret key in environment variables, so it doesn't leak
- .set_key(os.environ["APPWRITE_API_KEY"])
)
+ 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:
@@ -1706,11 +1928,9 @@ def main(context):
return context.response.send("Document created")
-
-
Ruby
-
require "appwrite"
@@ -1719,8 +1939,12 @@ def main(context)
client
.set_endpoint('https://cloud.appwrite.io/v1')
.set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
- # Put your secret key in environment variables, so it doesn't leak
- .set_key(req.variables['APPWRITE_API_KEY'])
+
+ 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)
@@ -1733,11 +1957,9 @@ def main(context)
return context.response.send("Document created")
end
-
-
Deno
-
import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
@@ -1746,8 +1968,12 @@ export default function ({req, res}: any){
client
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
- // Put your secret key in environment variables, so it doesn't leak
- .setKey(Deno.env.get("APPWRITE_API_KEY") || "");
+
+ 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);
@@ -1760,11 +1986,9 @@ export default function ({req, res}: any){
return res.send("Document created");
}
-
-
Dart
-
import 'dart:async';
import 'package:dart_appwrite/dart_appwrite.dart';
@@ -1774,8 +1998,12 @@ Future<dynamic> main(final context) async {
final client = Client()
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
- // Put your secret key in environment variables, so it doesn't leak
- .setKey(process.env.APPWRITE_API_KEY);
+
+ 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);
@@ -1788,11 +2016,9 @@ Future<dynamic> main(final context) async {
return context.res.send("Document created");
}
-
-
Swift
-
import Appwrite
import AppwriteModels
@@ -1802,8 +2028,12 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject(ProcessInfo.processInfo.environment["APPWRITE_FUNCTION_PROJECT_ID"])
- // Put your secret key in environment variables, so it doesn't leak
- .setKey(ProcessInfo.processInfo.environment["APPWRITE_API_KEY"]);
+
+ 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)
@@ -1816,11 +2046,9 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return context.res.send("Document created")
}
-
-
.NET
-
namespace DotNetRuntime;
@@ -1835,26 +2063,28 @@ public class Handler {
var client = new Client()
.SetEndpoint("http://cloud.appwrite.io/v1")
.SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
- // Put your secret key in environment variables, so it doesn't leak
- .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
+
+ 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) {
- return Context.Response.Send("We messed up, document not created");
+ return Context.Res.Send("We messed up, document not created");
}
- return Context.Response.Send("Document created");
+ return Context.Res.Send("Document created");
}
}
-
-
Kotlin
-
package io.openruntimes.kotlin.src
@@ -1870,8 +2100,12 @@ class Main {
val client = Client().apply {
setEndpoint("https://cloud.appwrite.io/v1")
setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
- // Put your secret key in environment variables, so it doesn't leak
- setKey(System.getenv("APPWRITE_API_KEY"))
+ }
+
+ 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)
@@ -1886,11 +2120,9 @@ class Main {
}
}
-
-
Java
-
package io.openruntimes.java.src;
@@ -1905,8 +2137,12 @@ public class Main {
client
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
- // Put your secret key in environment variables, so it doesn't leak
- .setKey(System.getenv("APPWRITE_API_KEY"));
+
+ 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);
@@ -1921,15 +2157,19 @@ public class Main {
}
}
-
-Using Multiple Files
+
+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
@@ -1947,11 +2187,9 @@ export defaut function ({res}) {
return res.send(add(1, 2));
}
-
-
PHP
-
// src/utils.php
@@ -1972,7 +2210,6 @@ return function ($context) {
-
Python
-
// src/utils.py
@@ -1988,11 +2225,9 @@ import utils
def main(context):
return context.res.send(utils.add(1, 2))
-
-
Ruby
-
# lib/utils.rb
@@ -2009,11 +2244,9 @@ def main(context)
return context.res.send(add(1, 2))
end
-
-
Deno
-
// src/utils.ts
@@ -2030,11 +2263,9 @@ export default function ({res}: {res: any}) {
return res.send(add(1, 2));
}
-
-
Dart
-
// lib/utils.dart
@@ -2050,11 +2281,9 @@ Future<dynamic> main(final context) async {
return context.res.send(add(1, 2));
}
-
-
Swift
-
// Sources/utils.swift
@@ -2072,11 +2301,9 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return context.res.send(add(1, 2))
}
-
-
.NET
-
// src/Utils.cs
@@ -2102,11 +2329,9 @@ public class Handler {
}
}
-
-
Kotlin
-
// src/Utils.kt
@@ -2133,11 +2358,9 @@ class Main {
}
}
-
-
Java
-
// src/Utils.java
@@ -2163,7 +2386,6 @@ public class Main {
}
}
-
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 54335a66b..4447b3e81 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -14,7 +14,7 @@
The generated domains will look like this.
- https://64d4d22db370ae41a32e.functions.cloud.appwrite.io
+ https://64d4d22db370ae41a32e.appwrite.global
@@ -29,7 +29,7 @@
- curl -X POST https://64d4d22db370ae41a32e.functions.cloud.appwrite.io \
+ curl -X POST https://64d4d22db370ae41a32e.appwrite.global \
-H "X-Custom-Header: 123" \
-H "Content-Type: application/json" \
-d '{"data":"this is json data"}'
@@ -41,7 +41,9 @@
You can invoke your Appwrite Functions directly from the Appwrite SDKs.
+
Learn more about using the Appwrite SDKs
+
Client SDKs
@@ -416,6 +418,21 @@ public static void main(String[] args) throws Exception {
+Console
+
+ Another easy way to test a function is directly in the Appwrite console.
+ You test a function by hitting the Execute now button and
+
+
+setParam('srcLight', '/images-ee/docs/functions-execute-light.png')
+ ->setParam('srcDark', '/images-ee/docs/functions-execute-dark.png')
+ ->setParam('alt', '"Create Function" page.')
+ ->setParam('description', '"Create Function" page.')
+ ->render();
+?>
Events
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index cce760392..96119f04d 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -48,8 +48,4 @@ $runtimes['dart-2.17']["cloud"] = true;
-
-
-
-
- Learn more about permissions
-
\ No newline at end of file
+
\ No newline at end of file
From e4e8b0ac2adb26053953c61ddb1f27da490b6483 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Wed, 23 Aug 2023 14:43:27 +0000
Subject: [PATCH 55/80] fix view import
---
app/views/docs/functions-execute.phtml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 4447b3e81..e66d845da 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -1,3 +1,8 @@
+
Appwrite Functions executions can be invoked in several ways.
Functions can be invoked through the Appwrite SDK and visting its REST endpoint. Functions can also be triggered by events and scheduled executions.
From 75e79cbfcdbe59fcfe41dd08b97fb13bab03b8fe Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Wed, 23 Aug 2023 15:26:17 +0000
Subject: [PATCH 56/80] fix view import + improve env var examples
---
app/views/docs/functions-develop.phtml | 148 ++++++++++++++++++++++---
1 file changed, 132 insertions(+), 16 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index aa5cfc8b1..89f5a3d2a 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1372,73 +1372,191 @@ namespace runtime {
You can access the environment variables through the systems library of each language.
+
+
+
+ Variable
+ Description
+
+
+
+
+ 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
- process.env.MY_VAR
-
+ export default async ({ req, res, log }) => {
+ return res.send(process.env.MY_VAR, 200);
+}
-
PHP
- getenv('MY_VAR')
-
+ <?php
+
+return function ($context) {
+ return $context->res->send(getenv('MY_VAR'), 200);
+};
-
Python
- os.environ['MY_VAR']
+ def main(context):
+ return context.res.send(os.environ['MY_VAR'], 200)
-
Ruby
- ENV['MY_VAR']
+ def main(context)
+ return context.res.send(ENV['MY_VAR'], 200)
+end
-
Deno
- Deno.env.get('MY_VAR')
+ export default async ({ req, res, log }) => {
+ return res.send(Deno.env.get('MY_VAR'), 200);
+}
-
Dart
- Platform.environment['MY_VAR']
+ import 'dart:async';
+
+Future<dynamic> main(final context) async {
+ return context.res.send(Platform.environment['MY_VAR'], 200);
+}
-
Swift
- ProcessInfo.processInfo.environment["MY_VAR"]
+ import Foundation
+
+func main(context: RuntimeContext) async throws -> RuntimeOutput {
+ return try await context.send(ProcessInfo.processInfo.environment["MY_VAR"], 200)
+}
-
.NET
- Environment.GetEnvironmentVariable("MY_VAR")
+ namespace DotNetRuntime;
+
+public class Handler {
+ public async Task<RuntimeOutput> Main(RuntimeContext Context)
+ {
+ return await Context.Send(Environment.GetEnvironmentVariable("MY_VAR"), 200);
+ }
+}
-
Kotlin
- System.getenv("MY_VAR")
+ 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
- System.getenv("MY_VAR")
+ 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++
- std::getenv("MY_VAR")
+ #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);
+ };
+}
@@ -2206,7 +2324,6 @@ return function ($context) {
return $context->res->send(add(1, 2));
};
-
-
Python
@@ -2362,8 +2479,7 @@ class Main {
-
Java
-
-// src/Utils.java
+ // src/Utils.java
package io.openruntimes.java.src;
From 0f51947fb0562267bc42bb1655aefc56a23b3778 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Wed, 23 Aug 2023 16:47:30 +0000
Subject: [PATCH 57/80] Add Domain name steps in deploy
---
app/views/docs/functions-deploy.phtml | 33 ++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 0244a4e5f..7be004807 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -164,4 +164,35 @@
Domains
-[TODO: @matej steps to add a custom domain thanks]
+
+ Each deployed function can have it's own domain.
+ By default, one is generated for each of your functions.
+ You can find the generated domain for your function like this.
+
+
+
+ - Navigate to the Appwrite Console's Functions page.
+ - Navigate to the Domains tab.
+ - In the table, you'll find a link formatted similar to
https://64d4d22db370ae41a32e.appwrite.global. This is your preview.
+
+
+
+ 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.
+
+
+
+ - Navigate to the Appwrite Console's Functions page.
+ - Navigate to the Domains tab.
+ - Click on Create domain.
+ - Input your domain in the Domain input field and click Next.
+ - Copy the CNAME record provided to you, and add it to your domain registar.
+ - Click Go to console and wait for the domain name to be verified and certificate to generate.
+
+
+
+ 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.
+
\ No newline at end of file
From ab0cab25181919551aee5283618bda7a71ccc47c Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Wed, 23 Aug 2023 18:04:13 +0000
Subject: [PATCH 58/80] Fix some wrong links
---
app/views/docs/functions.phtml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 0dc52264d..f45f4415b 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -48,7 +48,7 @@ $image = new View(__DIR__.'/../general/image.phtml');
Explore how Appwrite Functions can be invoked.
-Learn more about executing functions
+Learn more about executing functions
@@ -64,5 +64,5 @@ $image = new View(__DIR__.'/../general/image.phtml');
Here's a curated list of examples that showcase Appwrite Function's capabilies.
-Learn more about using function examples
+Learn more about using function examples
\ No newline at end of file
From 4d5419288713c0143bd60c529c7ab725dfe2975a Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Wed, 23 Aug 2023 20:54:10 +0000
Subject: [PATCH 59/80] deno cache command fixed
---
app/views/docs/functions-develop.phtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 89f5a3d2a..c251a31ae 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1602,7 +1602,7 @@ namespace runtime {
Deno
deno
- deno cache
+ deno cache [ENTRYPOINT_FILE]
Dart
From 86d262a673eaef85043def166f989218639e7a19 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Wed, 23 Aug 2023 22:11:38 +0100
Subject: [PATCH 60/80] feat: better functions error handling
---
app/views/docs/functions-develop.phtml | 1810 ++++++++++++------------
1 file changed, 915 insertions(+), 895 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index c251a31ae..4817eb1aa 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -10,10 +10,10 @@
- - The function is invoked.
- - Appwrite passes in request information like headers and environment variables through the
context.req object.
- - The runtime executes the code you defined, you can log through the
context.log or context.error methods.
- - Function terminates when you return results using
context.res.
+ - The function is invoked.
+ - Appwrite passes in request information like headers and environment variables through the
context.req object.
+ - The runtime executes the code you defined, you can log through the
context.log or context.error methods.
+ - Function terminates when you return results using
context.res.
You'll find all of these steps in a simple function like this.
@@ -452,29 +452,29 @@ public class Main {
You'll find these properties in the context object.
-
- Property
- Description
-
+
+ Property
+ Description
+
-
- req
- Contains request information like method, body, and headers. See full examples here.
-
-
- res
- Contains methods to build a response and return information. See full examples here.
-
-
- log
- Logs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
-
-
- error
- Logs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
-
-
+
+ req
+ Contains request information like method, body, and headers. See full examples here.
+
+
+ res
+ Contains methods to build a response and return information. See full examples here.
+
+
+ log
+ Logs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
+
+
+ error
+ Logs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
+
+
@@ -505,7 +505,7 @@ public class Main {
Request
- If you pass data into an Appwrite function, it'll be found in the request object.
+ If you pass data into an Appwrite function, it'll be found in the request object.
This includes all invocation methods, such as data from Appwrite SDKs, HTTP calls, Appwrite events, and browsers visiting the configured domain.
Explore the request object with the following function, which logs all request params to the Appwrite Console.
@@ -750,80 +750,80 @@ public class Main {
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.
-
-
-
-
-
- Variable
- Description
-
-
-
-
- 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 }) => {
+
+ 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.
+
+
+
+
+
+ Variable
+ Description
+
+
+
+
+ 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':
@@ -841,12 +841,12 @@ public class Main {
return res.empty();
}
}
-
-
- -
-
PHP
-
- <?php
+
+
+ -
+
PHP
+
+ <?php
return function ($context) {
switch ($context->req->query['type']) {
@@ -864,12 +864,12 @@ return function ($context) {
return $context->res->empty();
}
};
-
-
- -
-
Python
-
- def main(context):
+
+
+ -
+
Python
+
+ def main(context):
switch context.req.query['type']:
case 'text':
return context.res.send("This is a text response", 200)
@@ -883,12 +883,12 @@ return function ($context) {
})
default:
return context.res.empty()
-
-
- -
-
Ruby
-
- def main(context)
+
+
+ -
+
Ruby
+
+ def main(context)
case context.req.query['type']
when 'text'
return context.res.send("This is a text response", 200)
@@ -904,12 +904,12 @@ return function ($context) {
return context.res.empty()
end
end
-
-
- -
-
Deno
-
- export default async ({ req, res, log }) => {
+
+
+ -
+
Deno
+
+ export default async ({ req, res, log }) => {
switch (req.query.type) {
case 'text':
@@ -927,12 +927,12 @@ end
return res.empty();
}
}
-
-
- -
-
Dart
-
- import 'dart:async';
+
+
+ -
+
Dart
+
+ import 'dart:async';
Future<dynamic> main(final context) async {
switch (context.req.query['type']) {
@@ -955,12 +955,12 @@ Future<dynamic> main(final context) async {
.empty();
}
}
-
-
- -
-
Swift
-
- import Foundation
+
+
+ -
+
Swift
+
+ import Foundation
func main(context: RuntimeContext) async throws -> RuntimeOutput {
switch context.req.query["type"] {
@@ -978,12 +978,12 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return try await context.empty()
}
}
-
-
- -
-
.NET
-
- namespace DotNetRuntime;
+
+
+ -
+
.NET
+
+ namespace DotNetRuntime;
public class Handler {
public async Task<RuntimeOutput> Main(RuntimeContext Context)
@@ -1005,12 +1005,12 @@ public class Handler {
}
}
}
-
-
- -
-
Kotlin
-
- package io.openruntimes.kotlin.src
+
+
+ -
+
Kotlin
+
+ package io.openruntimes.kotlin.src
import io.openruntimes.kotlin.RuntimeContext
import io.openruntimes.kotlin.RuntimeOutput
@@ -1026,12 +1026,12 @@ class Main {
}
}
}
-
-
- -
-
Java
-
- package io.openruntimes.java.src;
+
+
+ -
+
Java
+
+ package io.openruntimes.java.src;
import io.openruntimes.java.RuntimeContext;
import io.openruntimes.java.RuntimeOutput;
@@ -1056,12 +1056,12 @@ public class Main {
}
}
}
-
-
- -
-
C++
-
- #include "../RuntimeResponse.h"
+
+
+ -
+
C++
+
+ #include "../RuntimeResponse.h"
#include "../RuntimeRequest.h"
#include "../RuntimeOutput.h"
#include "../RuntimeContext.h"
@@ -1090,35 +1090,35 @@ namespace runtime {
}
};
}
-
-
-
-
-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 }) => {
+
+
+
+
+ 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
+
+
+ -
+
PHP
+
+ <?php
return function ($context) {
$context->log("This is a log, use for logging information to console");
@@ -1127,47 +1127,47 @@ return function ($context) {
return $context->send("Check the Appwrite Console to see logs and errors!");
};
-
-
- -
-
Python
-
- def main(context):
+
+
+ -
+
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)
+
+
+ -
+
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) => {
+
+
+ -
+
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';
+
+
+ -
+
Dart
+
+ import 'dart:async';
Future<dynamic> main(final context) async {
context.log("This is a log, use for logging information to console");
@@ -1176,12 +1176,12 @@ Future<dynamic> main(final context) async {
return context.send("Check the Appwrite Console to see logs and errors!");
}
-
-
- -
-
Swift
-
- import Foundation
+
+
+ -
+
Swift
+
+ import Foundation
func main(context: RuntimeContext) async throws -> RuntimeOutput {
context.log("This is a log, use for logging information to console")
@@ -1190,12 +1190,12 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
return try context.send("Check the Appwrite Console to see logs and errors!")
}
-
-
- -
-
.NET
-
- namespace DotNetRuntime;
+
+
+ -
+
.NET
+
+ namespace DotNetRuntime;
public class Handler {
public async Task<RuntimeOutput> Main(RuntimeContext Context)
@@ -1207,12 +1207,12 @@ public class Handler {
return await Context.Send("Check the Appwrite Console to see logs and errors!");
}
}
-
-
- -
-
Kotlin
-
- package io.openruntimes.kotlin.src
+
+
+ -
+
Kotlin
+
+ package io.openruntimes.kotlin.src
import io.openruntimes.kotlin.RuntimeContext
import io.openruntimes.kotlin.RuntimeOutput
@@ -1226,12 +1226,12 @@ class Main {
return context.send("Check the Appwrite Console to see logs and errors!")
}
}
-
-
- -
-
Java
-
- package io.openruntimes.java.src;
+
+
+ -
+
Java
+
+ package io.openruntimes.java.src;
import io.openruntimes.java.RuntimeContext;
import io.openruntimes.java.RuntimeOutput;
@@ -1245,12 +1245,12 @@ public class Main {
return context.send("Check the Appwrite Console to see logs and errors!");
}
}
-
-
- -
-
C++
-
- #include "../RuntimeResponse.h"
+
+
+ -
+
C++
+
+ #include "../RuntimeResponse.h"
#include "../RuntimeRequest.h"
#include "../RuntimeOutput.h"
#include "../RuntimeContext.h"
@@ -1267,394 +1267,394 @@ namespace runtime {
}
};
}
-
-
-
-You can access these logs through the following steps.
-
- - In Appwrite Console, navigate to Functions.
- - Click to open a function you wish to inspect.
- - Under the Executions tab, click on an execution.
- - In the Response section, you'll be able to view logs under the Logs and Errors tabs.
-
+
+
+
+ You can access these logs through the following steps.
+
+ - In Appwrite Console, navigate to Functions.
+ - Click to open a function you wish to inspect.
+ - Under the Executions tab, click on an execution.
+ - In the Response section, you'll be able to view logs under the Logs and Errors tabs.
+
+
+ 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 accesible 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.
+
+
+
+
+
+
+ Variable
+ Description
+
+
+
+
+ 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.
+
+
+
+
+
+ Local Environment Variables
+
+ Local environment variables will only be accessible in the function they belong to.
+ Local environment variables will override global environment variables when they have conflicting names.
+
+
+ - In Appwrite Console, navigate to Functions.
+ - Click to open a function you wish to add variables to.
+ - Under the Settings tab, navigate to Environment variables.
+ - Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
+
+
+ Global Environment Variables
+
+ Global environment variables are accessible to all Appwrite Functions.
+ Local environment variables will override global environment variables when they have conflicting names.
+
+
+ - In Appwrite Console, navigate to your project's Settings page.
+ - Navigate to Global variables section.
+ - Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
+
+
+
+ You can access the environment variables through the systems library of each language.
+
+
+
+
+
+ Variable
+ Description
+
+
+
+
+ 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 }) => {
+ return res.send(process.env.MY_VAR, 200);
+}
+
+
+ -
+
PHP
+
+ <?php
-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.
-
+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';
-Default Environment Variables
-
- Appwrite runtimes passes in some environment variables by default.
- These are always accesible for every function at runtime.
-
+Future<dynamic> main(final context) async {
+ return context.res.send(Platform.environment['MY_VAR'], 200);
+}
+
+
+ -
+
Swift
+
+ import Foundation
-
- 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.
-
-
+func main(context: RuntimeContext) async throws -> RuntimeOutput {
+ return try await context.send(ProcessInfo.processInfo.environment["MY_VAR"], 200)
+}
+
+
+ -
+
.NET
+
+ namespace DotNetRuntime;
-
-
-
- Variable
- Description
-
-
-
-
- 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.
-
-
+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:
+
+
+
+ To install your dependencies before your function is built, you should add the relevant install command to the top your functions Build Commands script.
+
+
+
+
+
+ Language
+ Package Manager
+ Commands
+
+
- APPWRITE_FUNCTION_PROJECT_ID
-
- The project ID of the running function.
-
+ Node.js
+ npm
+ npm install
- APPWRITE_FUNCTION_RUNTIME_NAME
-
- The runtime of the running function.
-
+ PHP
+ Composer
+ composer install
- APPWRITE_FUNCTION_RUNTIME_VERSION
-
- The runtime version of the running function.
-
+ Python
+ pip
+ pip install -r requirements.txt
-
-
-
-Local Environment Variables
-
- Local environment variables will only be accessible in the function they belong to.
- Local environment variables will override global environment variables when they have conflicting names.
-
-
- - In Appwrite Console, navigate to Functions.
- - Click to open a function you wish to add variables to.
- - Under the Settings tab, navigate to Environment variables.
- - Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
-
-
-Global Environment Variables
-
- Global environment variables are accessible to all Appwrite Functions.
- Local environment variables will override global environment variables when they have conflicting names.
-
-
- - In Appwrite Console, navigate to your project's Settings page.
- - Navigate to Global variables section.
- - Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
-
-
-
- You can access the environment variables through the systems library of each language.
-
-
-
-
- Variable
- Description
+ Ruby
+ Bundler
+ bundle install
-
-
- x-appwrite-trigger
-
- Describes how the function execution was invoked.
- Possible values are http, schedule or event.
-
+ Deno
+ deno
+ deno cache [ENTRYPOINT_FILE]
- x-appwrite-event
-
- If the function execution was triggered by an event, describes the triggering event.
-
+ Dart
+ pub
+ pub get
- 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.
-
+ Swift
+ Swift Package Manager
+ N/A
- 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.
-
+ .NET
+ NuGet
+ N/A
- x-appwrite-country-code
-
- Displays the country code of the configured locale.
-
+ Kotlin
+ Gradle
+ N/A
- x-appwrite-continent-code
-
- Displays the continent code of the configured locale.
-
+ Java
+ Gradle
+ N/A
- x-appwrite-continent-eu
-
- Describes if the configured local is within the EU.
-
+ C++
+ None
+ N/A
-
-
+
+ Using Appwrite in a Function
-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 }) => {
- 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';
+ 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. You can read more about authentication in the Server Authentication section of the docs.
-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;
+ 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';
-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:
-
-
-
- To install your dependencies before your function is built, you should add the relevant install command to the top your functions Build Commands script.
-
-
-
-
-
- Language
- Package Manager
- Commands
-
-
-
- Node.js
- npm
- npm install
-
-
- PHP
- Composer
- composer install
-
-
- Python
- pip
- pip install -r requirements.txt
-
-
- Ruby
- Bundler
- bundle install
-
-
- Deno
- deno
- deno cache [ENTRYPOINT_FILE]
-
-
- Dart
- pub
- pub get
-
-
- Swift
- Swift Package Manager
- N/A
-
-
- .NET
- NuGet
- N/A
-
-
- Kotlin
- Gradle
- N/A
-
-
- Java
- Gradle
- N/A
-
-
- C++
- None
- N/A
-
-
-
-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. 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 }) => {
+export default async ({ req, res, log, error }) => {
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1')
@@ -1667,17 +1667,18 @@ export default async ({ req, res, log }) => {
try {
databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {})
} catch (e) {
- return res.send("We messed up, document not created")
+ error("Failed to create document: " + e.message)
+ return res.send("Failed to create document")
}
return res.send("Document created")
}
-
-
- -
-
PHP
-
- <?php
+
+
+ -
+
PHP
+
+ <?php
require(__DIR__ . '/../vendor/autoload.php');
@@ -1699,17 +1700,18 @@ return function ($context) {
try {
$databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []);
} catch (Exception $e) {
- return $context->res->send("We messed up, document not created");
+ $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
+
+
+ -
+
Python
+
+ from appwrite.client import Client
from appwrite.services.databases import Databases
from appwrite.id import ID
@@ -1729,15 +1731,16 @@ def main(context):
try:
databases.create_document("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {})
except Exception as e:
- return context.response.send("We messed up, document not created")
+ 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"
+
+
+ -
+
Ruby
+
+ require "appwrite"
def main(context)
client = Appwrite::Client.new
@@ -1752,19 +1755,20 @@ def main(context)
begin
databases.create_document('[DATABASE_ID]', '[COLLECTION_ID]', Appwrite::ID.unique(), {})
rescue Appwrite::Exception => e
- return context.response.send("We messed up, document not created")
+ 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";
+
+
+ -
+
Deno
+
+ import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
-export default function ({req, res}: any){
+export default function ({req, res, error}: any){
const client = new Client();
client
.setEndpoint("https://cloud.appwrite.io/v1")
@@ -1777,17 +1781,18 @@ export default function ({req, res}: any){
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {});
} catch (e) {
- return res.send("We messed up, document not created");
+ error("Failed to create document: " + e.message);
+ return res.send("Failed to create document");
}
return res.send("Document created");
-}
-
-
- -
-
Dart
-
- import 'dart:async';
+}
+
+
+ -
+
Dart
+
+ import 'dart:async';
import 'package:dart_appwrite/dart_appwrite.dart';
@@ -1803,17 +1808,18 @@ Future<dynamic> main(final context) async {
try {
await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
} catch (e) {
- return context.res.send("We messed up, document not created");
+ 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
+
+
+ -
+
Swift
+
+ import Appwrite
import AppwriteModels
import Foundation
@@ -1829,17 +1835,18 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
do {
try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:])
} catch {
- return context.res.send("We messed up, document not created")
+ 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;
+
+
+ -
+
.NET
+
+ namespace DotNetRuntime;
using Appwrite;
using Appwrite.Services;
@@ -1860,18 +1867,19 @@ public class Handler {
try {
await databases.CreateDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), new Dictionary<string, object>());
} catch (Exception e) {
- return Context.Response.Send("We messed up, document not created");
+ 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
+
+
+ -
+
Kotlin
+
+ package io.openruntimes.kotlin.src
import io.openruntimes.kotlin.RuntimeContext
import io.openruntimes.kotlin.RuntimeOutput
@@ -1894,18 +1902,19 @@ class Main {
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap())
} catch (e: Exception) {
- return context.res.send("We messed up, document not created")
+ 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;
+
+
+ -
+
Java
+
+ package io.openruntimes.java.src;
import io.openruntimes.java.RuntimeContext;
import io.openruntimes.java.RuntimeOutput;
@@ -1926,34 +1935,35 @@ public class Main {
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), new HashMap<>());
} catch (Exception e) {
- return context.res.send("We messed up, document not created");
+ 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.
-
+ 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.
-
+
+ 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';
+
+ -
+
Node.js
+
+ import { Client, Databases, ID } from 'node-appwrite';
export default async ({ req, res, log }) => {
@@ -1972,17 +1982,18 @@ export default async ({ req, res, log }) => {
try {
databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {})
} catch (e) {
- return res.send("We messed up, document not created")
+ log("Failed to create document: " + e.message)
+ return res.send("Failed to create document")
}
return res.send("Document created")
}
-
-
- -
-
PHP
-
- <?php
+
+
+ -
+
PHP
+
+ <?php
require(__DIR__ . '/../vendor/autoload.php');
@@ -2008,17 +2019,18 @@ return function ($context) {
try {
$databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []);
} catch (Exception $e) {
- return $context->res->send("We messed up, document not created");
+ $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
+
+
+ -
+
Python
+
+ from appwrite.client import Client
from appwrite.services.databases import Databases
from appwrite.id import ID
@@ -2042,15 +2054,16 @@ def main(context):
try:
databases.create_document("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {})
except Exception as e:
- return context.response.send("We messed up, document not created")
+ 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"
+
+
+ -
+
Ruby
+
+ require "appwrite"
def main(context)
client = Appwrite::Client.new
@@ -2069,19 +2082,20 @@ def main(context)
begin
databases.create_document('[DATABASE_ID]', '[COLLECTION_ID]', Appwrite::ID.unique(), {})
rescue Appwrite::Exception => e
- return context.response.send("We messed up, document not created")
+ 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";
+
+
+ -
+
Deno
+
+ import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
-export default function ({req, res}: any){
+export default function ({req, res, error}: any){
const client = new Client();
client
.setEndpoint("https://cloud.appwrite.io/v1")
@@ -2098,17 +2112,18 @@ export default function ({req, res}: any){
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {});
} catch (e) {
- return res.send("We messed up, document not created");
+ error("Failed to create document: " + e.message)
+ return res.send("Failed to create document");
}
return res.send("Document created");
-}
-
-
- -
-
Dart
-
- import 'dart:async';
+}
+
+
+ -
+
Dart
+
+ import 'dart:async';
import 'package:dart_appwrite/dart_appwrite.dart';
@@ -2128,17 +2143,18 @@ Future<dynamic> main(final context) async {
try {
await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
} catch (e) {
- return context.res.send("We messed up, document not created");
+ 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
+
+
+ -
+
Swift
+
+ import Appwrite
import AppwriteModels
import Foundation
@@ -2158,17 +2174,18 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
do {
try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:])
} catch {
- return context.res.send("We messed up, document not created")
+ 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;
+
+
+ -
+
.NET
+
+ namespace DotNetRuntime;
using Appwrite;
using Appwrite.Services;
@@ -2193,18 +2210,19 @@ public class Handler {
try {
await databases.CreateDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), new Dictionary<string, object>());
} catch (Exception e) {
- return Context.Res.Send("We messed up, document not created");
+ 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
+
+
+ -
+
Kotlin
+
+ package io.openruntimes.kotlin.src
import io.openruntimes.kotlin.RuntimeContext
import io.openruntimes.kotlin.RuntimeOutput
@@ -2231,18 +2249,19 @@ class Main {
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap())
} catch (e: Exception) {
- return context.res.send("We messed up, document not created")
+ 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;
+
+
+ -
+
Java
+
+ package io.openruntimes.java.src;
import io.openruntimes.java.RuntimeContext;
import io.openruntimes.java.RuntimeOutput;
@@ -2267,162 +2286,163 @@ public class Main {
try {
databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), new HashMap<>());
} catch (Exception e) {
- return context.res.send("We messed up, document not created");
+ 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
+
+
+
+
+
+ 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
+
+
+ // src/main.js
import { add } from './utils.js';
export defaut function ({res}) {
return res.send(add(1, 2));
}
-
-
- -
-
PHP
-
- // src/utils.php
+
+
+ -
+
PHP
+
+ // src/utils.php
function add($a, $b) {
return $a + $b;
}
-
-
- // src/main.php
+
+
+ // src/main.php
include 'utils.php';
return function ($context) {
return $context->res->send(add(1, 2));
};
-
-
- -
-
Python
-
- // src/utils.py
+
+
+ -
+
Python
+
+ // src/utils.py
def add(a, b):
return a + b;
-
-
- // src/main.py
+
+
+ // src/main.py
import utils
def main(context):
return context.res.send(utils.add(1, 2))
-
-
- -
-
Ruby
-
- # lib/utils.rb
+
+
+ -
+
Ruby
+
+ # lib/utils.rb
def add(a, b)
return a + b
end
-
-
- # lib/main.rb
+
+
+ # lib/main.rb
require_relative 'utils'
def main(context)
return context.res.send(add(1, 2))
end
-
-
- -
-
Deno
-
- // src/utils.ts
+
+
+ -
+
Deno
+
+ // src/utils.ts
export function add(a: number, b: number): number {
return a + b;
-}
-
-
- // src/main.ts
+}
+
+
+ // src/main.ts
import { add } from './utils.ts';
export default function ({res}: {res: any}) {
return res.send(add(1, 2));
}
-
-
- -
-
Dart
-
- // lib/utils.dart
+
+
+ -
+
Dart
+
+ // lib/utils.dart
int add(int a, int b) {
return a + b;
}
-
-
- // lib/main.dart
+
+
+ // lib/main.dart
import 'dart:async';
Future<dynamic> main(final context) async {
return context.res.send(add(1, 2));
}
-
-
- -
-
Swift
-
- // Sources/utils.swift
+
+
+ -
+
Swift
+
+ // Sources/utils.swift
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
-
-
- // Sources/index.swift
+
+
+ // Sources/index.swift
import Foundation
func main(context: RuntimeContext) async throws -> RuntimeOutput {
return context.res.send(add(1, 2))
}
-
-
- -
-
.NET
-
- // src/Utils.cs
+
+
+ -
+
.NET
+
+ // src/Utils.cs
namespace DotNetRuntime
@@ -2433,9 +2453,9 @@ public static class Utils
return a + b;
}
}
-
-
- // src/Index.cs
+
+
+ // src/Index.cs
namespace DotNetRuntime
@@ -2445,12 +2465,12 @@ public class Handler {
return Context.Res.Send(Utils.Add(1, 2));
}
}
-
-
- -
-
Kotlin
-
- // src/Utils.kt
+
+
+ -
+
Kotlin
+
+ // src/Utils.kt
package io.openruntimes.kotlin.src
@@ -2459,9 +2479,9 @@ class Utils {
return a + b
}
}
-
-
- // src/Main.kt
+
+
+ // src/Main.kt
package io.openruntimes.kotlin.src
@@ -2474,12 +2494,12 @@ class Main {
return context.res.send(Utils.add(1, 2))
}
}
-
-
- -
-
Java
-
- // src/Utils.java
+
+
+ -
+
Java
+
+ // src/Utils.java
package io.openruntimes.java.src;
@@ -2488,9 +2508,9 @@ class Utils {
return a + b;
}
}
-
-
- package io.openruntimes.java.src;
+
+
+ package io.openruntimes.java.src;
import io.openruntimes.java.RuntimeContext;
import io.openruntimes.java.RuntimeOutput;
@@ -2501,54 +2521,54 @@ public class Main {
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.
-
-
-
- -
- The parameter passed into functions has changed.
-
req and res has been replaced by context, which contains new logger methods.
- Learn about context.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- 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.
-
- -
- Some variables about how a function was triggered are now found in the
context.req object as headers.
-
-
\ No newline at end of file
+
+
+
+
+
+ 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.
+
+
+
+ -
+ The parameter passed into functions has changed.
+
req and res has been replaced by context, which contains new logger methods.
+ Learn about context.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ 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.
+
+ -
+ Some variables about how a function was triggered are now found in the
context.req object as headers.
+
+
\ No newline at end of file
From 4548a4d2a0e1c7132e6aa408e9e893dace0f97c4 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Wed, 23 Aug 2023 22:13:31 +0100
Subject: [PATCH 61/80] fix: await document create
---
app/views/docs/functions-develop.phtml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 4817eb1aa..aaab1175b 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1665,7 +1665,7 @@ export default async ({ req, res, log, error }) => {
const databases = new Databases(client);
try {
- databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {})
+ 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")
@@ -1980,7 +1980,7 @@ export default async ({ req, res, log }) => {
const databases = new Databases(client);
try {
- databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {})
+ 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")
From 3f57c8df1b8be4cbaf9634334f12cf040d28b1db Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 24 Aug 2023 12:12:00 -0400
Subject: [PATCH 62/80] Update app/views/docs/functions-deploy.phtml
Co-authored-by: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com>
---
app/views/docs/functions-deploy.phtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 7be004807..5d8eed8fb 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -53,7 +53,7 @@
Deploy
-
- Checkout your prodction branch in Git.
+ Checkout your production branch in Git.
-
Create a new commit.
From c0e4011fc3be15bbcfc529f9ec56015cbc86da3b Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 24 Aug 2023 16:19:17 +0000
Subject: [PATCH 63/80] Add entry file and html tags got deno
---
app/views/docs/functions-develop.phtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index c251a31ae..3febbd757 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1602,7 +1602,7 @@ namespace runtime {
Deno
deno
- deno cache [ENTRYPOINT_FILE]
+ deno cache <ENTRYPOINT_FILE>
Dart
From c6e548cf6a61b4b2a8932a4792bd6f5f105f8222 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 24 Aug 2023 19:56:05 +0000
Subject: [PATCH 64/80] add debug and redeploy
---
app/views/docs/functions-deploy.phtml | 40 +++++++++++++++++++--------
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 5d8eed8fb..0405d7445 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -16,7 +16,7 @@
Create Funcion
-Before deploying your function with Git, create a new function attached to your Git repo.
+Before deploying your function with VCS, create a new function attached to your VCS repo.
-
Navigate to Functions from the side bar of the Appwrite Console.
@@ -43,7 +43,8 @@
Name your function, select a runtime that matches your function, and enter an entry point path, relative to the root directory from the previous step.
-
- If you have build steps, like installing dependencies, input the commands into the Build settings heading's Command field.
+ 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.
-
Finally, configure the execute permissions of the function. For security, only provide execute permissions to the necessary roles.
@@ -65,14 +66,6 @@
A new deployment will be automatically created. Deployments will be automatically activated when new commits are added to the production branch.
-Debugging Builds
-After deploying a function, you can find the status of the deployment and build logs in the Appwrite Console.
-
- - In Appwrite Console, navigate to Functions.
- - Click to open a function you wish to inspect.
- - Under the Deployments tab, you'll find the status of the current active deployment and previous inactive deployments.
- - 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.
-
CLI
@@ -163,7 +156,6 @@
Domains
-
Each deployed function can have it's own domain.
By default, one is generated for each of your functions.
@@ -195,4 +187,30 @@
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.
+
+ - In Appwrite Console, navigate to Functions.
+ - Click to open a function you wish to inspect.
+ - Under the Deployments tab, you'll find the status of the current active deployment and previous inactive deployments.
+ - 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.
+
+
+Redeploy Builds
+
+ After updateing 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.
+
+
+ - In Appwrite Console, navigate to Functions.
+ - Click to open a function you wish to inspect.
+ - Under the Deployments tab, you'll find the status of the current active deployment.
+ - You can redeploy by clicking the Redeploy button.
+
+
+ The redeployment behavior varies depending on how the initial deployment is created.
+ For VCS 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
From 8337b4ecd8183cba949ffd43436ef837d4225258 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Thu, 24 Aug 2023 20:04:27 +0000
Subject: [PATCH 65/80] Fix modal text
---
app/views/docs/functions-execute.phtml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index e66d845da..685756b8f 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -434,8 +434,8 @@ $image = new View(__DIR__.'/../general/image.phtml');
echo $image
->setParam('srcLight', '/images-ee/docs/functions-execute-light.png')
->setParam('srcDark', '/images-ee/docs/functions-execute-dark.png')
- ->setParam('alt', '"Create Function" page.')
- ->setParam('description', '"Create Function" page.')
+ ->setParam('alt', '"Execute Function" modal.')
+ ->setParam('description', '"Execute Function" modal.')
->render();
?>
From 28cd6fe65bfcea30e128c7170d01d4d073c2a465 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Thu, 24 Aug 2023 21:50:58 +0100
Subject: [PATCH 66/80] feat: simplify function examples
---
app/views/docs/functions-examples.phtml | 413 +++++-------------------
1 file changed, 83 insertions(+), 330 deletions(-)
diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml
index e125d902e..d7971d657 100644
--- a/app/views/docs/functions-examples.phtml
+++ b/app/views/docs/functions-examples.phtml
@@ -1,176 +1,16 @@
Appwrite Functions is all about flexibility.
- Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster.
+ Behind the simple workflow hides some useful examples that can help you accomplish your goals faster.
Take a look at the following.
-[TODO: @matej @luke -> Let's have some simple recipes here for common actions]
Currency Conversion API
-Getting Started
-
-
- In this recipe, we'll build a simple function for currency conversion.
- Let's start with a static converstion rate. We'll show you how to integrate an API later in this example.
-
-
-
- -
-
Node.js
-
- Create a new file, index.js.
- Add the following code to index.js.
-
- export default async function ({ res }) {
- return res.send('1.13');
-};
-
-
-
- -
-
PHP
-
- Create a new file, index.php.
- Add the following code to index.php.
-
- <?php
-return function ($context) {
- return $context->res->send('1.13');
-};
-
-
-
- -
-
Python
-
- Create a new file, index.py.
- Add the following code to index.py.
-
- def main(context):
- return context.res.send('1.13')
-
-
-
- -
-
Dart
-
- Create a new file, index.dart.
- Add the following code to index.dart.
-
- import 'dart:async';
-
-Future<dynamic> main(final context) async {
- return context.res.send('1.13');
-}
-
-
-
- -
-
Ruby
-
- Create a new file, index.rb.
- Add the following code to index.rb.
-
- def main(context)
- return context.res.send('1.13')
-end
-
-
-
-
-
-This code will return 1.13 when the function is called, because 1€ equals approximately 1.13$.
-Now, create a function in the Appwrite console, adding your Git repository as the remote source and using the path file you created as the entry point.
-Finally, execute the function and visit the URL (like ghrfu9ewji.functions.appwrite.app) to see the response.
-
-Adding the Business Logic
-
-Now, let's update the function to use the request payload.
-You can use a query string to pass data to your function. For example, ghrfu9ewji.functions.appwrite.app?amount=5 will pass 5 as the amount parameter.
-
-
- -
-
Node.js
-
- Update index.js to use req.query.amount to access the amount parameter, and return the conversion result.
-
- export default async function ({ req, res }) {
- const amountInEuros = Number(req.query.amount);
- const amountInDollars = amountInEuros * 1.13;
- return res.send(amountInDollars.toString());
-};
-
-
-
- -
-
PHP
-
- Update index.php to use $context->req->query['amount'] to access the amount parameter, and return the conversion result.
-
- <?php
-return function ($context) {
- $amountInEuros = $context->req->query['amount'];
- $amountInDollars = $amountInEuros * 1.13;
- return $context->res->send($amountInDollars);
-};
-
-
-
- -
-
Python
-
- Update index.py to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
-
- def main(context):
- amountInEuros = context.req.query['amount']
- amountInDollars = amountInEuros * 1.13
- return context.res.send(amountInDollars)
-
-
-
- -
-
Dart
-
- Update index.dart to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
-
- import 'dart:async';
-
-Future<dynamic> main(final context) async {
- final amountInEuros = context.req.query['amount'];
- final amountInDollars = amountInEuros * 1.13;
- return context.res.send(amountInDollars);
-}
-
-
-
- -
-
Ruby
-
- Update index.rb to use context.req.query['amount'] to access the amount parameter, and return the conversion result.
-
- def main(context)
- amountInEuros = context.req.query['amount']
- amountInDollars = amountInEuros * 1.13
- return context.res.send(amountInDollars)
-end
-
-
-
-
-
-Commit your changes and push them to your Git repository.
-
-
-Testing our Function
-
-
- Execute the function and visit the URL (like ghrfu9ewji.functions.appwrite.app?amount=5) to see the response.
-
- You should see the result of the conversion, like 5.65.
+ 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.
-Adding Dependencies
+Prerequisites
-
@@ -190,7 +30,6 @@ end
-
PHP
- You can use Composer to manage your PHP project's dependencies. Install it from getcomposer.org/download.
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
@@ -236,9 +75,7 @@ environment:
Install the http library. This library includes a get function that you can use to make HTTP requests.
-
- pub install http
-
+ pub install http
Finally, add pub get to your function's build commands in the Appwrite console.
@@ -254,8 +91,7 @@ environment:
Create a Gemfile file with the following contents. This file is used to manage your Ruby project's dependencies.
- source 'https://rubygems.org'
-
+ source 'https://rubygems.org'
Install the httparty library. This library includes a get function that you can use to make HTTP requests.
@@ -271,106 +107,7 @@ bundle install
-
Using Dependencies
-
-
- -
-
Node.js
-
- Use fetch from undici to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
-
- import { fetch } from 'undici';
-
-export default async function ({ req, res }) {
- 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());
-};
-
-
-
- -
-
PHP
-
-
-
- <?php
-
-require(__DIR__ . '/../vendor/autoload.php');
-
-use GuzzleHttp\Client;
-
-return function ($context) {
- $amountInEuros = $context->getRequest()->getQuery('amount');
- $client = new Client();
- $response = $client->get('https://api.exchangerate.host/latest?base=EUR&symbols=USD');
- $data = json_decode($response->getBody(), true);
- $amountInDollars = $amountInEuros * $data['rates']['USD'];
- return $context->res->send(strval($amountInDollars));
-};
-
-
-
- -
-
Python
-
- Use get from requests to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
-
- import requests
-
-def main(context):
- 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))
-
-
-
- -
-
Dart
-
- Use get from http to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
-
- import 'dart:async';
-import 'package:http/http.dart' as http;
-
-Future<dynamic> main(final context) async {
- 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());
-}
-
-
-
- -
-
Ruby
-
- Use get from httparty to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars.
-
- require 'httparty'
-
-def main(context)
- 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
-
-
-
-
-
-After your function has updated, you can test it by visiting the URL and providing different amounts to convert in the query string. The conversion rate should now be more precise because we're using the current conversion rate.
-
-Adding Multiple Routes
-
-Let's add support multiple paths like /eur and /inr. Each path will convert from that currency to dollars.
+Code
-
@@ -490,44 +227,78 @@ end
-After your function has updated, you can try out the new paths. For example, ghrfu9ewji.functions.appwrite.app/eur?amount=5 should convert Euros to Dollars, while ghrfu9ewji.functions.appwrite.app/inr?amount=100 should convert Indian Rupees to Dollars.
-Congratulations! You've built a currency conversion API using Appwrite functions!
-
-Voting System Using Appwrite
-
-Getting Started
-
- In this recipe, you will build a simple voting system that allows users to vote on various topics. Appwrite functions and the server SDK will be used to enforce voting rules and prevent multiple votes from the same user for a single topic.
+ 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.
-Setting Up
-
- -
-
Appwrite Project
-
- 1. Create a new Appwrite project.
- 2. Add your development domain to your Appwrite project's trusted domains.
-
-
- -
-
Create Collections
-
- Create two collections named "topics" and "votes."
- For "topics" collection, have fields: title and description.
- For "votes" collection, have fields: topicId, userId, and vote.
-
-
-
+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.
+
-Building the Voting Function
+Prerequisites
+
+Create a Topics collection with the following attributes:
+
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ title
+ string
+ The name of the topic
+
+
+ description
+ string
+ Long form description of the topic
+
+
+
+
+Create a Votes collection with the following attributes:
+
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ userId
+ string
+ The ID of the user who cast the vote
+
+
+ topicId
+ string
+ The ID of the topic that was voted on
+
+
+ vote
+ string
+ The vote cast by the user. Must be either "yes" or "no"
+
+
+
+
+Code
-
Node.js
- Create a new located at functions/vote/src/main.js.
import { Client, Databases, Query } from 'node-appwrite';
@@ -539,7 +310,7 @@ export default async function ({ req, res }) {
};
if (vote.vote !== 'yes' && vote.vote !== 'no') {
- return res.json({ ok: false, message: 'You must vote yes or no.' });
+ return res.json({ ok: false, message: 'You must vote yes or no.' }, 400);
}
const client = new Client();
@@ -556,7 +327,7 @@ export default async function ({ req, res }) {
]);
if (existingVotes.total > 0) {
- return res.json({ message: 'You have already voted on this topic.' });
+ return res.json({ ok: false, message: 'You have already voted on this topic.' }, 400);
}
const voteDocument = await database.createDocument('[VOTES_COLLECTION_ID]', {
@@ -567,7 +338,7 @@ export default async function ({ req, res }) {
return res.json({ ok: true, message: 'Vote cast.', vote: voteDocument });
}
-
+
-
@@ -588,7 +359,7 @@ def main(context):
}
if vote['vote'] != 'yes' and vote['vote'] != 'no':
- return context.res.json({'ok': False, 'message': 'You must vote yes or 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')
@@ -606,7 +377,7 @@ def main(context):
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'],
@@ -640,7 +411,7 @@ return function ($context) {
];
if ($vote['vote'] !== 'yes' && $vote['vote'] !== 'no') {
- return $context->res->json(['ok' => false, 'message' => 'You must vote yes or no.']);
+ return $context->res->json(['ok' => false, 'message' => 'You must vote yes or no.'], 400);
}
$client = new Client();
@@ -660,7 +431,7 @@ return function ($context) {
return $context->res->json([
'ok' => false,
'message' => 'You have already voted on this topic.'
- ]);
+ ], 400);
}
$voteDocument = $database->createDocument('[VOTES_COLLECTION_ID]', [
@@ -686,7 +457,6 @@ return function ($context) {
require "appwrite"
def main(context)
-
vote = {
'userId' => context.req.query['userId'],
'topicId' => context.req.query['topicId'],
@@ -694,7 +464,7 @@ def main(context)
}
if vote['vote'] != 'yes' and vote['vote'] != 'no'
- return context.res.json({'ok': false, 'message': 'You must vote yes or no.'})
+ return context.res.json({'ok': false, 'message': 'You must vote yes or no.'}, 400)
end
client = Appwrite::Client.new()
@@ -714,7 +484,7 @@ def main(context)
return context.res.json({
'ok': false,
'message': 'You have already voted on this topic.'
- })
+ }, 400)
end
vote_document = database.create_document('[VOTES_COLLECTION_ID]', {
@@ -748,7 +518,7 @@ Future main(final context) async {
};
if (vote['vote'] != 'yes' && vote['vote'] != 'no') {
- return context.res.json({'ok': false, 'message': 'You must vote yes or no.'});
+ return context.res.json({'ok': false, 'message': 'You must vote yes or no.'}, 400);
}
final client = Client()
@@ -767,7 +537,7 @@ Future main(final context) async {
return context.res.json({
'ok': false,
'message': 'You have already voted on this topic.'
- });
+ }, 400);
}
final voteDocument = await database.createDocument('[VOTES_COLLECTION_ID]', {
@@ -804,7 +574,7 @@ def main(context):
}
if vote['vote'] != 'yes' and vote['vote'] != 'no':
- return context.res.json({'ok': False, 'message': 'You must vote yes or 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')
@@ -822,7 +592,7 @@ def main(context):
return context.res.json({
'ok': False,
'message': 'You have already voted on this topic.'
- })
+ }, 400)
vote_document = database.create_document('[VOTES_COLLECTION_ID]', vote)
@@ -836,28 +606,11 @@ def main(context):
-In the Appwrite console, create a function and use the file you created as the entry point.
-
-Testing the Function
-
- Execute the function and visit the URL, passing the required parameters [YOUR_FUNCTION_URL]?userId=[USER_ID]&topicId=[TOPIC_ID];&vote=yes to cast a vote. You should see a response confirming the vote. Trying to vote again with the same user ID and topic ID should result in a message indicating that the user has already voted on this topic.
+ 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.
-Conclusion
-
-
- To further improve this function, try adding the following checks:
-
- - Check that the user ID and topic ID exist.
- - Replace the user ID query parameter with the
x-appwrite-user-id header, so votes may only be cast by logged in users.
- - Convert the function to POST requests with a JSON body to cast votes, so that the vote data is not visible in the URL.
-
-
-
-
- Congratulations! You've built a voting system that leverages Appwrite functions and the Appwrite server SDK to enforce business logic and ensure that users can only vote once per topic.
-
[TODO: @luke -> Example with JWT, show both client and server code]
From 9673f0446197b9c0e9c9b5e4d9b175a0af11c880 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Thu, 24 Aug 2023 22:37:31 +0100
Subject: [PATCH 67/80] feat: html form function example
---
app/views/docs/functions-examples.phtml | 331 +++++++++++++++++++++++-
1 file changed, 328 insertions(+), 3 deletions(-)
diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml
index d7971d657..a8dd01968 100644
--- a/app/views/docs/functions-examples.phtml
+++ b/app/views/docs/functions-examples.phtml
@@ -611,6 +611,334 @@ def main(context):
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 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:
+
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ name
+ string
+ The name of the message author
+
+ email
+ string
+ The email of the message author
+
+
+ content
+ string
+ The 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.
+
[TODO: @luke -> Example with JWT, show both client and server code]
@@ -618,15 +946,12 @@ def main(context):
\ No newline at end of file
From 8872899bf9a2c9b672d99039cbdd633ac4161644 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sat, 26 Aug 2023 20:37:18 +0000
Subject: [PATCH 68/80] Runtimes merged on one line
---
app/views/docs/functions-runtimes.phtml | 56 +++++++++++++++++--------
1 file changed, 39 insertions(+), 17 deletions(-)
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 96119f04d..928071a3f 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -4,12 +4,26 @@ use Appwrite\Utopia\View;
$events = $this->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;
+}
+
+$sorted_runtimes['Node.js']["cloud"] = true;
+$sorted_runtimes['PHP']["cloud"] = true;
+$sorted_runtimes['Ruby']["cloud"] = true;
+$sorted_runtimes['Python']["cloud"] = true;
+$sorted_runtimes['Dart']["cloud"] = true;
?>
@@ -26,24 +40,32 @@ $runtimes['dart-2.17']["cloud"] = true;
- Name
+ Name
Image
- Architectures
- Platforms
+ Architectures
+ Platforms
- $runtime): ?>
+ $runtime): ?>
- ![Function Env.]()
- escape($key); ?>
- escape($runtime['image'] ?? ''); ?>
- escape(implode(' / ', $runtime['supports'] ?? [])); ?>
-
+
+
+
+ escape($key); ?>
+
+
+ $version): ?>
+ escape($version['image'] ?? ''); ?>
+
+
+ escape(implode(' / ', $runtime['versions'][0]['supports'] ?? [])); ?>
+
+ Self-hosted
+
Cloud
-
- Self-hosted
+
From 77337c1edf209eb235fe60155e818c3d447bdff1 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sat, 26 Aug 2023 20:50:20 +0000
Subject: [PATCH 69/80] Fix response code examples
---
app/views/docs/functions-develop.phtml | 338 ++++++++++++++++++++-----
1 file changed, 279 insertions(+), 59 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index a780b61e7..8f5c4cd8a 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -1301,7 +1301,7 @@ namespace runtime {
- Variable
+ Variable
Description
@@ -1372,64 +1372,7 @@ namespace runtime {
You can access the environment variables through the systems library of each language.
-
-
-
- Variable
- Description
-
-
-
-
- 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.
@@ -1561,6 +1504,283 @@ namespace runtime {
+
Response
+
+
+ -
+
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();
+ }
+ }
+ };
+}
+
+
+
+
Dependencies
From 7228e69949d250284603ecd10341e36a2ae0700f Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sat, 26 Aug 2023 21:16:52 +0000
Subject: [PATCH 70/80] Add link to Destructuring Assignment
---
app/views/docs/functions-develop.phtml | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 8f5c4cd8a..ae7ea3d84 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -3,7 +3,7 @@
Each function is handled following a request and response pattern.
-Function Flow
+Function Flow
There is a clear flow for all Appwrite Functions, from beginning to end.
Here's everything that happens during a function execution.
@@ -478,8 +478,11 @@ public class Main {
-Destructuring Assignment
-Some languages, namely JavaScript, support destructuring. You'll see us use destructing in examples, which has the following syntax.
+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
From 7a24d8eb3e2e6d113f651b8b05f63ae113b007b9 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sat, 26 Aug 2023 22:02:27 +0000
Subject: [PATCH 71/80] ChatGPT reviewed grammar and spelling:
---
app/views/docs/functions-deploy.phtml | 10 +++++-----
app/views/docs/functions-develop.phtml | 8 ++++----
app/views/docs/functions-execute.phtml | 26 +++++++++++++-------------
app/views/docs/functions.phtml | 14 +++++++-------
4 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 0405d7445..9071a415f 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -1,5 +1,5 @@
- Appwrite Functions are mini application in Appwrite with their own endpoint.
+ 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.
@@ -15,7 +15,7 @@
This offers simple versioning and collaboration that will easily fit into the rest of your development workflow.
-Create Funcion
+Create Function
Before deploying your function with VCS, create a new function attached to your VCS repo.
-
@@ -157,7 +157,7 @@
Domains
- Each deployed function can have it's own domain.
+ 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.
@@ -179,7 +179,7 @@
- Navigate to the Domains tab.
- Click on Create domain.
- Input your domain in the Domain input field and click Next.
- - Copy the CNAME record provided to you, and add it to your domain registar.
+ - Copy the CNAME record provided to you, and add it to your domain registrar.
- Click Go to console and wait for the domain name to be verified and certificate to generate.
@@ -200,7 +200,7 @@
Redeploy Builds
- After updateing the configuration of your Appwrite Function, you need to redeploy your function for the changes to take effect.
+ 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.
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index ae7ea3d84..f3afdaee5 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -446,7 +446,7 @@ public class Main {
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, anddlogging must be handled through the context object passed in.
+ All input, output, and logging must be handled through the context object passed in.
You'll find these properties in the context object.
@@ -1284,13 +1284,13 @@ namespace runtime {
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.
+ Environmental variables can be global, or function-specific.
Default Environment Variables
Appwrite runtimes passes in some environment variables by default.
- These are always accesible for every function at runtime.
+ These are always accessible for every function at runtime.
@@ -2544,7 +2544,7 @@ export function add(a, b) {
import { add } from './utils.js';
-export defaut function ({res}) {
+export default function ({res}) {
return res.send(add(1, 2));
}
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 685756b8f..4fc4dc929 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -4,8 +4,8 @@ use Appwrite\Utopia\View;
?>
- Appwrite Functions executions can be invoked in several ways.
- Functions can be invoked through the Appwrite SDK and visting its REST endpoint. Functions can also be triggered by events and scheduled executions.
+ 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 new Appwrite Functions.
@@ -73,7 +73,7 @@ try {
})
console.log(data)
} catch (err) {
- console.err(err.message)
+ console.error(err.message)
}
@@ -175,7 +175,7 @@ try {
})
console.log(data)
} catch (err) {
- console.err(err.message)
+ console.error(err.message)
}
@@ -274,7 +274,7 @@ try {
})
console.log(data)
} catch (err) {
- console.err(err.message)
+ console.error(err.message)
}
@@ -425,8 +425,9 @@ public static void main(String[] args) throws Exception {
Console
- Another easy way to test a function is directly in the Appwrite console.
- You test a function by hitting the Execute now button and
+ 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.
- In Appwrite Console, navigate to Functions.
- - Click to open a function you wish to add variables to.
+ - Click to open a function you wish to configure.
- Under the Settings tab, navigate to Events.
- Add one or multiple events as triggers for the function.
-
Be careful to avoid selecting events that can be caused by the function itself.
- This can cause the function to trigger it's own execution, resulting in infinite recursions.
+ This can cause the function to trigger its own execution, resulting in infinite recursions.
@@ -488,7 +489,6 @@ $image = new View(__DIR__.'/../general/image.phtml');
-Permissions
Permissions
@@ -497,15 +497,15 @@ $image = new View(__DIR__.'/../general/image.phtml');
Server SDKs require an API key with the correct scopes.
- If your function with a generated or custom domain, permissions are disabled for this function.
- Anyone visiting this domain will be able to execute the function.
+ If your function has a generated or custom domain, execute permissions are ignored for this function.
+ Anyone visiting the configured domains will be able to execute the function.
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 it's executions.
+ Navigate to Functions and click on a function to view its executions.
For security reasons, Appwrite does not store the response of function executions.
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index f45f4415b..9fb059feb 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -6,14 +6,14 @@ use Appwrite\Utopia\View;
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, scheduled executions.
- Each function will have their own URL, execute in their own isolated container, and have their own configurable environment variables and permissions.
+ 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.
Getting Started
- Appwrite Functions let you build anything you can imagine, but this flexibility makes is difficult to know where to start.
+ 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.
@@ -29,7 +29,7 @@ $image = new View(__DIR__.'/../general/image.phtml');
Explore Features
- Appwrite Functions use familiar HTTP concepts, so you can learn quickly and grain transferable skills.
+ Appwrite Functions use familiar HTTP concepts, so you can learn quickly and gain transferable skills.
Learn more about developing functions
@@ -44,7 +44,7 @@ $image = new View(__DIR__.'/../general/image.phtml');
- Appwrite Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, scheduled executions.
+ Appwrite Functions can be triggered by HTTP requests, SDK methods, server events, webhooks, and scheduled executions.
Explore how Appwrite Functions can be invoked.
@@ -61,7 +61,7 @@ $image = new View(__DIR__.'/../general/image.phtml');
Like to learn from examples?
- Here's a curated list of examples that showcase Appwrite Function's capabilies.
+ Here's a curated list of examples that showcase Appwrite Functions' capabilities.
Learn more about using function examples
From e3683ed4a1bdd1ff3497af9b1afc79794868777c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Sun, 27 Aug 2023 13:37:11 +0000
Subject: [PATCH 72/80] PR review changes
---
app/views/docs/functions-develop.phtml | 316 ++----------------------
app/views/docs/functions-examples.phtml | 28 +--
2 files changed, 22 insertions(+), 322 deletions(-)
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index f3afdaee5..369b8148d 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -11,9 +11,9 @@
- The function is invoked.
- - Appwrite passes in request information like headers and environment variables through the
context.req object.
- - The runtime executes the code you defined, you can log through the
context.log or context.error methods.
- - Function terminates when you return results using
context.res.
+ - Appwrite passes in request information like headers, body or path through the
context.req object.
+ - The runtime executes the code you defined, you can log through the
context.log() or context.error() methods.
+ - Function terminates when you return results using
return context.res.send(), return context.res.json() or similar.
You'll find all of these steps in a simple function like this.
@@ -445,7 +445,7 @@ public class Main {
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.
+ 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.
@@ -467,12 +467,12 @@ public class Main {
Contains methods to build a response and return information. See full examples here.
- log
- Logs information to the Appwrite Console, end users will not be able to see these logs. 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
- Logs errors to the Appwrite Console, end users will not be able to see these errors. 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.
@@ -508,8 +508,8 @@ public class Main {
Request
- If you pass data into an Appwrite function, it'll be found in the request object.
- This includes all invocation methods, such as data from Appwrite SDKs, HTTP calls, Appwrite events, and browsers visiting the configured domain.
+ 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.
@@ -528,7 +528,7 @@ public class Main {
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(req.query); // Parsed query params. For example, req.query.limit
+ 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.");
};
@@ -612,7 +612,7 @@ end
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(req.query); // Parsed query params. For example, req.query.limit
+ 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.");
@@ -1348,10 +1348,10 @@ namespace runtime {
- Local Environment Variables
+ Function Environment Variables
- Local environment variables will only be accessible in the function they belong to.
- Local environment variables will override global environment variables when they have conflicting names.
+ Function environment variables will only be accessible in the function they belong to.
+ Function environment variables will override global environment variables when they have conflicting names.
- In Appwrite Console, navigate to Functions.
@@ -1362,7 +1362,7 @@ namespace runtime {
Global Environment Variables
- Global environment variables are accessible to all Appwrite Functions.
+ Global environment variables are accessible to all Appwrite Functions in your project.
Local environment variables will override global environment variables when they have conflicting names.
@@ -1375,13 +1375,6 @@ namespace runtime {
You can access the environment variables through the systems library of each language.
-
-
- 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
@@ -1507,283 +1500,6 @@ namespace runtime {
- Response
-
-
- -
-
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();
- }
- }
- };
-}
-
-
-
-
Dependencies
diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml
index a8dd01968..d30c0b827 100644
--- a/app/views/docs/functions-examples.phtml
+++ b/app/views/docs/functions-examples.phtml
@@ -24,7 +24,7 @@
npm install undici
- Finally, add npm install to your function's build commands in the Appwrite console.
+ Finally, add npm install to your function's build commands in the Appwrite Console.
-
@@ -38,7 +38,7 @@
composer require guzzlehttp/guzzle
- Finally, add composer install to your function's build commands in the Appwrite console.
+ Finally, add composer install to your function's build commands in the Appwrite Console.
-
@@ -53,7 +53,7 @@
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.
+ Finally, add pip install -r requirements.txt to your function's build commands in the Appwrite Console.
-
@@ -78,7 +78,7 @@ environment:
pub install http
- Finally, add pub get to your function's build commands in the Appwrite console.
+ Finally, add pub get to your function's build commands in the Appwrite Console.
@@ -101,7 +101,7 @@ environment:
bundle install
- Finally, add bundle install to your function's build commands in the Appwrite console.
+ Finally, add bundle install to your function's build commands in the Appwrite Console.
@@ -608,7 +608,7 @@ def main(context):
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.
+ For example, [YOUR_FUNCTION_URL]/?userId=[USER_ID]&topicId=[TOPIC_ID]&vote=yes to cast a vote.
HTML Contact Form
@@ -939,19 +939,3 @@ Future main(final context) async {
Use the function by navigating to the function URL in the browser. Submit the form to store the message in the collection.
-
-
-[TODO: @luke -> Example with JWT, show both client and server code]
-
-
-
-
\ No newline at end of file
From 67f2c434162c53a2530230f4c777865611f6f635 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Sun, 27 Aug 2023 13:37:31 +0000
Subject: [PATCH 73/80] Fix console name spelling
---
app/views/docs/authentication-security.phtml | 4 ++--
app/views/docs/authentication.phtml | 4 ++--
app/views/docs/custom-domains.phtml | 2 +-
app/views/docs/email-delivery.phtml | 2 +-
app/views/docs/functions-deploy.phtml | 6 +++---
app/views/docs/getting-started-for-android.phtml | 4 ++--
app/views/docs/getting-started-for-apple.phtml | 2 +-
app/views/docs/getting-started-for-flutter.phtml | 4 ++--
app/views/docs/getting-started-for-server.phtml | 2 +-
app/views/docs/getting-started-for-web.phtml | 2 +-
app/views/docs/keys.phtml | 2 +-
app/views/docs/permissions-old.phtml | 2 +-
app/views/docs/permissions.phtml | 2 +-
app/views/docs/production.phtml | 2 +-
app/views/docs/self-hosting.phtml | 2 +-
15 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml
index 241e6893e..fe26070e9 100644
--- a/app/views/docs/authentication-security.phtml
+++ b/app/views/docs/authentication-security.phtml
@@ -87,10 +87,10 @@
Password History
Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password everytime it's changed.
-Password history 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.
\ No newline at end of file
+Password dictionary can be enabled in the Auth service's Security tab on the Appwrite Console.
\ No newline at end of file
diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml
index 9910bc286..065b96683 100644
--- a/app/views/docs/authentication.phtml
+++ b/app/views/docs/authentication.phtml
@@ -513,7 +513,7 @@ mutation {
- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks.
+ Only redirect URLs to domains added as a platform on your Appwrite Console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks.
@@ -898,7 +898,7 @@ let session = try await account.get()
- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks.
+ Only redirect URLs to domains added as a platform on your Appwrite Console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks.
diff --git a/app/views/docs/custom-domains.phtml b/app/views/docs/custom-domains.phtml
index 74c087140..5c178c322 100644
--- a/app/views/docs/custom-domains.phtml
+++ b/app/views/docs/custom-domains.phtml
@@ -356,7 +356,7 @@ $dns = [
Confirm and Verify Your Domain
-Once you added your new CNAME record to your DNS settings, you will need to verify your new domain name from your Appwrite console. Enter your custom domains tab from your project settings, click the DNS Settings link and click on the 'Confirm and Verify" button. If everything went well, Appwrite will approve your domain and generate a new SSL certificate for it in the background.
+Once you added your new CNAME record to your DNS settings, you will need to verify your new domain name from your Appwrite Console. Enter your custom domains tab from your project settings, click the DNS Settings link and click on the 'Confirm and Verify" button. If everything went well, Appwrite will approve your domain and generate a new SSL certificate for it in the background.
Enjoy your Free SSL Certificate
diff --git a/app/views/docs/email-delivery.phtml b/app/views/docs/email-delivery.phtml
index ad8000572..1ad88c091 100644
--- a/app/views/docs/email-delivery.phtml
+++ b/app/views/docs/email-delivery.phtml
@@ -66,4 +66,4 @@ The next possible source of error is the configuration in your .env file. Make s
docker compose up -d --build --force-recreate
-Now you can head over to your Appwrite console, logout from your account and try to recover your password or send invites to other team members from your Appwrite console using your newly configured SMTP provider.
+Now you can head over to your Appwrite Console, logout from your account and try to recover your password or send invites to other team members from your Appwrite Console using your newly configured SMTP provider.
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 9071a415f..100d4e95a 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -101,14 +101,14 @@
Overwrite Warning
- If you made changes in the Appwrite console that is different from your appwrite.json,
+ 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 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.
+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.
.
@@ -143,7 +143,7 @@
-Next, navigate to your Appwrite console and upload the function.
+Next, navigate to your Appwrite Console and upload the function.
- Navigate to the function you want to deploy.
diff --git a/app/views/docs/getting-started-for-android.phtml b/app/views/docs/getting-started-for-android.phtml
index 74d35cbf0..207aed6af 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 fc6ce3038..fd431809c 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 6bd614873..47355fa81 100644
--- a/app/views/docs/getting-started-for-flutter.phtml
+++ b/app/views/docs/getting-started-for-flutter.phtml
@@ -19,7 +19,7 @@ $version = (isset($versions['flutter'])) ? $versions['flutter'] : '';
Add your Flutter Platform
-To init your SDK and start interacting with Appwrite services, you need to add a new Flutter platform to your project. To add a new platform, go to your Appwrite console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.
+To init your SDK and start interacting with Appwrite services, you need to add a new Flutter platform to your project. To add a new platform, go to your Appwrite Console, choose the project you created in the step before, and click the 'Add Platform' button. Only API requests initiated from platforms added to your Appwrite project will be accepted. This prevents unauthorized apps from accessing your Appwrite project.
From the options, choose to add a new Flutter platform and add your app credentials. Appwrite Flutter SDK currently supports building apps for Android, iOS, Linux, Mac OS, Web and Windows.
@@ -29,7 +29,7 @@ $version = (isset($versions['flutter'])) ? $versions['flutter'] : '';
For Android first add your app name and package name, Your package name is generally the applicationId in your app-level build.gradle file. By registering your new app platform, you are allowing your app to communicate with the Appwrite API.
-In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in you project settings screen in your Appwrite console.
+In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in you project settings screen in your Appwrite Console.
escape('
diff --git a/app/views/docs/getting-started-for-server.phtml b/app/views/docs/getting-started-for-server.phtml
index e5ede12fe..b05dd86e3 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 d7ec5bc2a..979053852 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/keys.phtml b/app/views/docs/keys.phtml
index cfff198a4..a63fff508 100644
--- a/app/views/docs/keys.phtml
+++ b/app/views/docs/keys.phtml
@@ -2,7 +2,7 @@
$scopes = $this->getParam('scopes', );
?>
-Using your API Keys, you can access Appwrite services using the SDK of your choice. To create a new API key, go to your API keys tab in your project setting using your Appwrite console and click the 'Add API Key' button.
+Using your API Keys, you can access Appwrite services using the SDK of your choice. To create a new API key, go to your API keys tab in your project setting using your Appwrite Console and click the 'Add API Key' button.
When adding a new API Key, you can choose which scope to grant your application. If you need to replace your API Key, create a new key, update your app credentials and, once ready, delete your old key.
diff --git a/app/views/docs/permissions-old.phtml b/app/views/docs/permissions-old.phtml
index ac8cb8ecb..a1d7ff4c5 100644
--- a/app/views/docs/permissions-old.phtml
+++ b/app/views/docs/permissions-old.phtml
@@ -10,7 +10,7 @@
For example, only users with a guest role can access authentication endpoints while access to member users is denied.
-You can change your project members' roles from your project settings in the Appwrite console.
+You can change your project members' roles from your project settings in the Appwrite Console.
diff --git a/app/views/docs/permissions.phtml b/app/views/docs/permissions.phtml
index adb1bbd3d..1c10fc523 100644
--- a/app/views/docs/permissions.phtml
+++ b/app/views/docs/permissions.phtml
@@ -18,7 +18,7 @@
Default Values
-If you create a resource using a Server SDK or the Appwrite console without explicit permissions, no one can access it by default because the permissions will be empty. If you create a resource using a Client SDK without explicit permissions, the creator will be granted read, update, and delete permissions on that resource by default.
+If you create a resource using a Server SDK or the Appwrite Console without explicit permissions, no one can access it by default because the permissions will be empty. If you create a resource using a Client SDK without explicit permissions, the creator will be granted read, update, and delete permissions on that resource by default.
Server Integration
diff --git a/app/views/docs/production.phtml b/app/views/docs/production.phtml
index 3133817d1..460e73f91 100644
--- a/app/views/docs/production.phtml
+++ b/app/views/docs/production.phtml
@@ -15,7 +15,7 @@
Limit Console Access
-Appwrite provides three different methods to limit access to your Appwrite console.
+Appwrite provides three different methods to limit access to your Appwrite Console.
- Whitelist a group of developers by IP using the
_APP_CONSOLE_WHITELIST_IPS environment variable.
diff --git a/app/views/docs/self-hosting.phtml b/app/views/docs/self-hosting.phtml
index 2aafd2f6f..2f6c39fd9 100644
--- a/app/views/docs/self-hosting.phtml
+++ b/app/views/docs/self-hosting.phtml
@@ -136,7 +136,7 @@
docker compose up -d --remove-orphans
-Once the Docker installation completes, go to your machine's hostname or IP address on your browser to access the Appwrite console. Please note that on hosts that are not Linux-native, the server might take a few minutes to start after installation completes.
+Once the Docker installation completes, go to your machine's hostname or IP address on your browser to access the Appwrite Console. Please note that on hosts that are not Linux-native, the server might take a few minutes to start after installation completes.
Stop
From 870726e6a2011b60b90ab45d88228b1698c200e5 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 09:50:26 -0400
Subject: [PATCH 74/80] Update app/views/docs/functions.phtml
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Matej Bačo
---
app/views/docs/functions.phtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml
index 9fb059feb..0d1f9e026 100644
--- a/app/views/docs/functions.phtml
+++ b/app/views/docs/functions.phtml
@@ -56,7 +56,7 @@ $image = new View(__DIR__.'/../general/image.phtml');
Avoid adding additional complexity to your codebase by coding in languages you already use and love.
-Learn more about using function runtimes
+Learn more about using function runtimes
From a84c5650b4becdd3b5043c1cf67ed4e7e75ce3ef Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 09:53:37 -0400
Subject: [PATCH 75/80] Apply suggestions from code review
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Matej Bačo
---
app/views/docs/functions-deploy.phtml | 19 ++++++++++---------
app/views/docs/functions-execute.phtml | 16 +++++++++-------
app/views/docs/functions-runtimes.phtml | 2 +-
3 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 100d4e95a..0a6c2b8e0 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -31,20 +31,21 @@
Search for the Git repository that hold your function and click connect.
-
- Select a production branch. New commits made to the production branch will be automatically deployed and activated.
+ 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.
-
- Input the root directory of the function inside the repository.
+ 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.
-
- If you don't want deploy comments to be made on your PRs, select Silent mode.
+ If you don't want deploy comments to be made on your pull requests or commits, select Silent mode.
-
- Name your function, select a runtime that matches your function, and enter an entry point path, relative to the root directory from the previous step.
+ 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.
-
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.
-
Finally, configure the execute permissions of the function. For security, only provide execute permissions to the necessary roles.
@@ -54,7 +55,7 @@
Deploy
-
- Checkout your production branch in Git.
+ Using Git, checkout the branch you configured as production branch when creating the Appwrite Function.
-
Create a new commit.
@@ -63,18 +64,18 @@
Push your new commit.
-
- A new deployment will be automatically created. Deployments will be automatically activated when new commits are added to the production branch.
+ A new deployment will be automatically created, built and activated.
CLI
CLI Setup
- Before you can deploy with the Appwrite CLI, make sure you've installed and initialized the CLI
+ 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 shell function, then paste in your function code.
+ 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.
@@ -151,7 +152,7 @@
- Select the Manual tab.
- Input the entry point of your function under Entrypoint. For the example above, it would be
index.js.
- Upload
code.tar.gz.
- - Select Activate deployment after build to use your new function.
+ - Select Activate deployment after build to use your new deployment.
- Click Create to deploy your function.
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 4fc4dc929..c017e601b 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -6,7 +6,7 @@ use Appwrite\Utopia\View;
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 new Appwrite Functions.
+ Here are all the different ways to consume your Appwrite Functions.
Domains
@@ -23,14 +23,14 @@ use Appwrite\Utopia\View;
- Alternatively you can add a custom domain to your Appwrite project.
+ 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 headers and request body will be passed to the function.
- This unlocks interesting ways to integrate other apps and backends to your Appwrite project.
+ 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.
@@ -68,8 +68,10 @@ client
const functions = new Functions(client)
try {
- const data = await functions.createExecution('[FUNCTION_ID]', {
+ const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
'foo': 'bar'
+ }), '/', 'GET', {
+ 'X-Custom-Header': '123'
})
console.log(data)
} catch (err) {
@@ -497,8 +499,8 @@ $image = new View(__DIR__.'/../general/image.phtml');
Server SDKs require an API key with the correct scopes.
- If your function has a generated or custom domain, execute permissions are ignored for this function.
- Anyone visiting the configured domains will be able to execute the function.
+ 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.
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 928071a3f..e1fe3be9c 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -29,7 +29,7 @@ $sorted_runtimes['Dart']["cloud"] = true;
Appwrite Functions supports an extensive list of runtimes to meet your unique tech preferences.
- Not all runtimes are available on Appwrite Cloud, check for the Cloud label in each listed runtime to know which ones are available.
+ 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
From f70b7671ebe7f25c1ef58427f75785ad93e58de9 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 14:22:32 +0000
Subject: [PATCH 76/80] Address matej's review comments
---
app/views/docs/functions-deploy.phtml | 13 +++++------
app/views/docs/functions-execute.phtml | 2 +-
app/views/docs/functions-runtimes.phtml | 30 +++++++++++++------------
3 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 0a6c2b8e0..62ee5219f 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -9,14 +9,14 @@
Here's everything you need to know to deploy your first Appwrite Function.
-VCS (Version Control System)
+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 VCS, create a new function attached to your VCS repo.
+Before deploying your function with Git, create a new function attached to your Git repo.
-
Navigate to Functions from the side bar of the Appwrite Console.
@@ -109,8 +109,7 @@
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.
-
+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
@@ -166,7 +165,7 @@
- Navigate to the Appwrite Console's Functions page.
- Navigate to the Domains tab.
- - In the table, you'll find a link formatted similar to
https://64d4d22db370ae41a32e.appwrite.global. This is your preview.
+ - In the table, you'll find a link formatted similar to
https://64d4d22db370ae41a32e.appwrite.global. This is your generated domain.
@@ -208,10 +207,10 @@
- In Appwrite Console, navigate to Functions.
- Click to open a function you wish to inspect.
- Under the Deployments tab, you'll find the status of the current active deployment.
- - You can redeploy by clicking the Redeploy button.
+ - You can redeploy by clicking the triple-dots beside an execution, and hitting the Redeploy button.
The redeployment behavior varies depending on how the initial deployment is created.
- For VCS deployments, redeploy uses the same commit hash but updated function settings.
+ 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-execute.phtml b/app/views/docs/functions-execute.phtml
index c017e601b..2df0337d3 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -47,7 +47,7 @@ use Appwrite\Utopia\View;
-Learn more about using the Appwrite SDKs
+Learn more about using the Appwrite SDKs
Client SDKs
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index e1fe3be9c..69a946b74 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -4,6 +4,12 @@ use Appwrite\Utopia\View;
$events = $this->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 = [];
@@ -18,12 +24,6 @@ foreach ($runtimes as $key => $item) {
$sorted_runtimes[$name]['versions'][] = $item;
}
-
-$sorted_runtimes['Node.js']["cloud"] = true;
-$sorted_runtimes['PHP']["cloud"] = true;
-$sorted_runtimes['Ruby']["cloud"] = true;
-$sorted_runtimes['Python']["cloud"] = true;
-$sorted_runtimes['Dart']["cloud"] = true;
?>
@@ -41,9 +41,9 @@ $sorted_runtimes['Dart']["cloud"] = true;
Name
+ version
Image
Architectures
- Platforms
@@ -53,7 +53,15 @@ $sorted_runtimes['Dart']["cloud"] = true;
- escape($key); ?>
+ escape($key); ?>
+
+
+
+ Self-hosted
+
+ Cloud
+
+
$version): ?>
@@ -61,12 +69,6 @@ $sorted_runtimes['Dart']["cloud"] = true;
escape(implode(' / ', $runtime['versions'][0]['supports'] ?? [])); ?>
-
- Self-hosted
-
- Cloud
-
-
From 7a307fb3a95fc98737d3cbab536226ea21c67660 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 14:23:35 +0000
Subject: [PATCH 77/80] Fix runtimes by showing only cloud tags beside relevant
items + return the copy button
---
app/views/docs/functions-runtimes.phtml | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml
index 69a946b74..663d4eaf0 100644
--- a/app/views/docs/functions-runtimes.phtml
+++ b/app/views/docs/functions-runtimes.phtml
@@ -40,10 +40,11 @@ foreach ($runtimes as $key => $item) {
- Name
- version
+ Name
+ Version
+
Image
- Architectures
+ Architectures
@@ -53,17 +54,21 @@ foreach ($runtimes as $key => $item) {
- escape($key); ?>
+ escape($key); ?>
-
- Self-hosted
-
- Cloud
-
-
+ $version): ?>
+ escape($version['version']); ?>
+
+ $version): ?>
+
+ Cloud
+
+
+
+
$version): ?>
escape($version['image'] ?? ''); ?>
From e9fb6375ccdebba92a5ba0295107ea2467e5993d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Sun, 27 Aug 2023 14:44:47 +0000
Subject: [PATCH 78/80] Improve SDK function execute code examples
---
app/views/docs/functions-execute.phtml | 99 ++++++++++++++++++++------
1 file changed, 77 insertions(+), 22 deletions(-)
diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml
index 2df0337d3..a6e52cfcb 100644
--- a/app/views/docs/functions-execute.phtml
+++ b/app/views/docs/functions-execute.phtml
@@ -85,6 +85,7 @@ try {
import 'package:appwrite/appwrite.dart';
+import 'dart:convert';
final client = Client();
client
@@ -94,8 +95,10 @@ client
final functions = Functions(client);
try {
- final response = await functions.createExecution('[FUNCTION_ID]', {
+ final response = await functions.createExecution('[FUNCTION_ID]', json.encode({
'foo': 'bar'
+ }), '/', 'GET', {
+ 'X-Custom-Header': '123'
});
print(response.data);
} catch (e) {
@@ -110,6 +113,7 @@ try {
import io.appwrite.Client;
import io.appwrite.services.Functions;
+import com.google.gson.Gson;
val client = new Client();
client
@@ -119,8 +123,10 @@ client
val functions = new Functions(client);
try {
- val response = await functions.createExecution('[FUNCTION_ID]', {
+ val response = await functions.createExecution('[FUNCTION_ID]', gson.toString({
'foo': 'bar'
+ }), '/', 'GET', {
+ 'X-Custom-Header': '123'
});
print(response.data);
} catch (e) {
@@ -134,6 +140,7 @@ try {
import Appwrite
+import Foundation
let client = Client()
client
@@ -143,7 +150,15 @@ client
let functions = Functions(client: client)
do {
- let response = try functions.createExecution(functionId: "[FUNCTION_ID]", data: ["foo": "bar"])
+ 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)
@@ -172,8 +187,10 @@ client
const functions = new Functions(client)
try {
- const data = await functions.createExecution('[FUNCTION_ID]', {
+ const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
'foo': 'bar'
+ }), '/', 'GET', {
+ 'X-Custom-Header': '123'
})
console.log(data)
} catch (err) {
@@ -203,7 +220,11 @@ $client
$functions = new Functions($client);
-$result = $functions->createExecution('[FUNCTION_ID]');
+$result = $functions->createExecution('[FUNCTION_ID]', json_encode([
+ 'foo' => 'bar'
+], '/', 'GET', [
+ 'X-Custom-Header': '123'
+]);
@@ -213,6 +234,7 @@ $result = $functions->createExecution('[FUNCTION_ID]');
from appwrite.client import Client
from appwrite.services.functions import Functions
+import json
client = Client()
@@ -224,11 +246,11 @@ client = Client()
functions = Functions(client)
-result = functions.create_execution('[FUNCTION_ID]',
- {
- 'foo': 'bar'
- }
-)
+result = functions.create_execution('[FUNCTION_ID]', json.dumps({
+ 'foo': 'bar'
+}, '/', 'GET', {
+ 'X-Custom-Header': '123'
+})
@@ -237,6 +259,7 @@ result = functions.create_execution('[FUNCTION_ID]',
require 'Appwrite'
+require 'json'
include Appwrite
@@ -247,8 +270,10 @@ client = Client.new
functions = Functions.new(client)
-response = functions.create_execution(function_id: '[FUNCTION_ID]', data: {
+response = functions.create_execution(function_id: '[FUNCTION_ID]', data: JSON.generate({
'foo': 'bar'
+}), '/', 'GET', {
+ 'X-Custom-Header': '123'
})
puts response.inspect
@@ -271,8 +296,10 @@ client
const functions = new Functions(client)
try {
- const data = await functions.createExecution('[FUNCTION_ID]', {
+ const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
'foo': 'bar'
+ }), '/', 'GET', {
+ 'X-Custom-Header': '123'
})
console.log(data)
} catch (err) {
@@ -286,6 +313,7 @@ try {
import 'package:dart_appwrite/dart_appwrite.dart';
+import 'dart:convert';
void main() {
Client client = Client();
@@ -299,8 +327,13 @@ void main() {
Future result = functions.createExecution(
functionId: '[FUNCTION_ID]',
- data: {
+ data: json.encode({
'foo': 'bar'
+ }),
+ xpath: '/',
+ method: 'GET',
+ headers: {
+ 'X-Custom-Header': '123'
}
);
@@ -319,6 +352,7 @@ void main() {
import Appwrite
+import Foundation
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1")
@@ -329,10 +363,14 @@ let functions = Functions(client)
let execution = try await functions.createExecution(
functionId: "[FUNCTION_ID]",
- data: [
+ data: NSJSONSerialization.jsonObject(with: [
"foo": "bar"
- ]
-)
+ ], options: [])!),
+ xpath: '/',
+ method: 'GET',
+ headers: [
+ "X-Custom-Header": "123"
+])
@@ -343,6 +381,7 @@ let execution = try await functions.createExecution(
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
+using System.Text.Json;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1")
@@ -353,10 +392,14 @@ var functions = new Functions(client);
Execution result = await functions.CreateExecution(
functionId: "[FUNCTION_ID]",
- data: new Dictionary<string, object> {
+ data: JsonSerializer.Serialize<object>(new Dictionary<string, object> {
{ "foo", "bar" }
- }
-);
+ }),
+ xpath: "/",
+ method: "GET",
+ headers: new Dictionary<string, object> {
+ { "X-Custom-Header", "123" }
+});
@@ -366,6 +409,7 @@ Execution result = await functions.CreateExecution(
import io.appwrite.Client
import io.appwrite.services.Functions
+import com.google.gson.Gson
fun main(args: Array<String>) {
val client = Client(context)
@@ -377,8 +421,13 @@ fun main(args: Array<String>) {
val response = functions.createExecution(
functionId = "[FUNCTION_ID]",
- data = mapOf(
+ data = gson.toString(mapOf(
"foo" to "bar"
+ )),
+ xpath = "/",
+ method = "GET",
+ headers = mapOf(
+ "X-Custom-Header" to "123"
)
)
}
@@ -395,6 +444,7 @@ fun main(args: Array<String>) {
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()
@@ -414,9 +464,14 @@ public static void main(String[] args) throws Exception {
System.out.println(result);
}),
- new HashMap() {{
+ gson.toString(new HashMap() {{
put("foo", "bar");
- }}
+ }}),
+ "/",
+ "GET",
+ new HashMap() {{
+ put("X-Custom-Header", "123");
+ }},
);
}
From e22eee160e3d5a9559f23ffebe0c20bc81ff50c3 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 15:10:46 +0000
Subject: [PATCH 79/80] Address Eldad's comments
---
app/views/docs/functions-deploy.phtml | 2 +-
app/views/docs/functions-develop.phtml | 153 +++++++++++++++++++-----
app/views/docs/functions-examples.phtml | 9 +-
3 files changed, 128 insertions(+), 36 deletions(-)
diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml
index 62ee5219f..934166ed4 100644
--- a/app/views/docs/functions-deploy.phtml
+++ b/app/views/docs/functions-deploy.phtml
@@ -69,7 +69,7 @@
CLI
-
+
CLI Setup
Before you can deploy with the Appwrite CLI, make sure you've installed and initialized the CLI.
diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml
index 369b8148d..b2b7bad38 100644
--- a/app/views/docs/functions-develop.phtml
+++ b/app/views/docs/functions-develop.phtml
@@ -3,9 +3,9 @@
Each function is handled following a request and response pattern.
-Function Flow
+Lifecycle
- There is a clear flow for all Appwrite Functions, from beginning to end.
+ There is a clear lifecycle for all Appwrite Functions, from beginning to end.
Here's everything that happens during a function execution.
@@ -460,19 +460,19 @@ public class Main {
req
- Contains request information like method, body, and headers. See full examples here.
+ Contains request information like method, body, and headers. See full examples here.
res
- Contains methods to build a response and return information. See full examples here.
+ Contains 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.
+ 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.
+ Methoc to log errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
@@ -487,20 +487,32 @@ public class Main {
-
Node.js
- export default async function ({ req, res, log, error }) {
- log('This is a log!');
- error('This is an error!');
- return res.send(`This function was called with ${req.method} method!`)
+ // 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
- export default async function ({ req, res, log, error }: any) {
- log('This is a log!');
- error('This is an error!');
- return res.send(`This function was called with ${req.method} method!`)
+ // 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
}
@@ -829,7 +841,7 @@ public class Main {
export default async ({ req, res, log }) => {
switch (req.query.type) {
- case 'text':
+ case 'text':
return res.send("This is a text response", 200);
case 'json':
return res.json({"type": "This is a JSON response"}, 200);
@@ -1097,6 +1109,47 @@ namespace runtime {
+
+ To get the different response types, set one of the following query parameters in the generated domain of your function.
+
+
+
+
+
+ Type
+ Query Param
+ Example
+
+
+
+
+ text
+ /?type=text
+ https://64d4d22db370ae41a32e.appwrite.global/?type=text
+
+
+ json
+ /?type=json
+ https://64d4d22db370ae41a32e.appwrite.global/?type=json
+
+
+ redirect
+ /?type=redirect
+ https://64d4d22db370ae41a32e.appwrite.global/?type=redirect
+
+
+ html
+ /?type=html
+ https://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.
@@ -1348,10 +1401,10 @@ namespace runtime {
- Function Environment Variables
+ Function-level Environment Variables
- Function environment variables will only be accessible in the function they belong to.
- Function environment variables will override global environment variables when they have conflicting names.
+ 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.
- In Appwrite Console, navigate to Functions.
@@ -1360,13 +1413,13 @@ namespace runtime {
- Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
- Global Environment Variables
+ Project-level Variables
- Global environment variables are accessible to all Appwrite Functions in your project.
- Local environment variables will override global environment variables when they have conflicting names.
+ 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.
- - In Appwrite Console, navigate to your project's Settings page.
+ - In the Appwrite Console, navigate to your project's Settings page.
- Navigate to Global variables section.
- Create an environment variable by clicking Create variable, using the Editor, or import new variables through a
.env file.
@@ -1506,79 +1559,119 @@ namespace runtime {
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:
-
- To install your dependencies before your function is built, you should add the relevant install command to the top your functions Build Commands script.
-
-
- Language
- Package Manager
+
+ Language
+ Package Manager
Commands
+
+
+
Node.js
npm
npm install
+
+
+
PHP
Composer
composer install
+
+
+
Python
pip
pip install -r requirements.txt
+
+
+
Ruby
Bundler
bundle install
+
+
+
Deno
deno
deno cache <ENTRYPOINT_FILE>
+
+
+
Dart
pub
pub get
+
+
+
Swift
Swift Package Manager
N/A
+
+
+
.NET
NuGet
N/A
+
+
+
Kotlin
Gradle
N/A
+
+
+
Java
Gradle
N/A
+
+
+
C++
None
N/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. You can read more about authentication in the Server Authentication section of the docs.
+
+ 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
diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml
index d30c0b827..485c4fe3b 100644
--- a/app/views/docs/functions-examples.phtml
+++ b/app/views/docs/functions-examples.phtml
@@ -4,7 +4,7 @@
Take a look at the following.
-Currency Conversion API
+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.
@@ -233,7 +233,7 @@ end
-Voting System Using Appwrite
+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.
@@ -611,10 +611,9 @@ def main(context):
For example, [YOUR_FUNCTION_URL]/?userId=[USER_ID]&topicId=[TOPIC_ID]&vote=yes to cast a vote.
-HTML Contact Form
-
+HTML Contact Form
- Here's a simple form page that can be used to store a user's message in a collection.
+ 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.
From 8d9be11cf97dcd2b79720d06c8083ac98bd802ac Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge"
Date: Sun, 27 Aug 2023 15:12:05 +0000
Subject: [PATCH 80/80] use enabled instead of supported in migrations
---
app/views/docs/migrations.phtml | 40 ++++++++++++++++-----------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml
index e130ae472..7d4308bac 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 @@
- supported
- supported
+ enabled
+ enabled
partial
- supported
+ enabled
manual
- supported
- supported
+ enabled
+ enabled
partial
- supported
+ enabled
manual
- supported
- supported
+ enabled
+ enabled
partial
- supported
+ enabled
manual
- supported
- supported
- supported
- supported
- supported
+ enabled
+ enabled
+ enabled
+ enabled
+ enabled
- supported
- supported
- supported
- supported
- supported
+ enabled
+ enabled
+ enabled
+ enabled
+ enabled