From 01585c2c88c226efb73036ef378427839d4c5013 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 28 Mar 2023 22:11:22 +0000 Subject: [PATCH 001/183] Init SMTP template docs --- app/views/docs/email-and-sms-templates.phtml | 22 ++++++++++++++++++++ app/views/docs/index.phtml | 1 + 2 files changed, 23 insertions(+) create mode 100644 app/views/docs/email-and-sms-templates.phtml diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml new file mode 100644 index 000000000..7a2b26ac7 --- /dev/null +++ b/app/views/docs/email-and-sms-templates.phtml @@ -0,0 +1,22 @@ +

Appwrite uses emails and SMS messages to perform user invite, user verification, login, and reset password. Emails and SMS messages can be customized to fit your app's design and voice.

+ +

Customize Templates

+

You can customize email and SMS templates in the Appwrite console.

+
+

Custom SMTP Server Required

+

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

+
+
    +
  1. In your project, navigate to Auth > Templates.
  2. + [STEPS AFTER FINALIZED DESIGN] +
+

Email Templates

+ +

Email Template Syntax

+

Email Template Components

+ + +

SMS Templates

+ +

SMS Template Syntax

+

SMS Template Components

\ No newline at end of file diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 998d36cfe..0265e8178 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -106,6 +106,7 @@ $cols = [
  • Pagination
  • Webhooks
  • Custom Domains
  • +
  • Email and SMS Templates
  • Response Codes
  • Rate Limits
  • From d61ac645554729f531023c47a7562ddbb62c8a4a Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 5 May 2023 22:37:03 +0000 Subject: [PATCH 002/183] Use relative links --- app/views/docs/email-and-sms-templates.phtml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 7a2b26ac7..35cbce5cd 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,22 +1,22 @@

    Appwrite uses emails and SMS messages to perform user invite, user verification, login, and reset password. Emails and SMS messages can be customized to fit your app's design and voice.

    -

    Customize Templates

    +

    Customize Templates

    You can customize email and SMS templates in the Appwrite console.

    Custom SMTP Server Required

    -

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

    +

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

    1. In your project, navigate to Auth > Templates.
    2. [STEPS AFTER FINALIZED DESIGN]
    -

    Email Templates

    +

    Email Templates

    +

    Add a SMTP provider

    +

    Email Template Syntax

    +

    Email Template Components

    -

    Email Template Syntax

    -

    Email Template Components

    +

    SMS Templates

    -

    SMS Templates

    - -

    SMS Template Syntax

    -

    SMS Template Components

    \ No newline at end of file +

    SMS Template Syntax

    +

    SMS Template Components

    \ No newline at end of file From 0c444f7d0daebcdfdfa61004e41fb0ccf7cbdbbb Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 8 May 2023 22:00:28 +0000 Subject: [PATCH 003/183] Add placeholders for docs --- app/views/docs/email-and-sms-templates.phtml | 78 +++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 35cbce5cd..e776e3c84 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,22 +1,76 @@ -

    Appwrite uses emails and SMS messages to perform user invite, user verification, login, and reset password. Emails and SMS messages can be customized to fit your app's design and voice.

    +

    Appwrite uses emails messages to perform user invite, user verification, login, and reset password. Emails messages can be customized to fit your app's design and voice.

    Customize Templates

    -

    You can customize email and SMS templates in the Appwrite console.

    +

    You can customize email templates in the Appwrite console.

    Custom SMTP Server Required

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

      -
    1. In your project, navigate to Auth > Templates.
    2. - [STEPS AFTER FINALIZED DESIGN] +
    3. In your project, navigate to the Auth service.
    4. +
    5. Under the Auth service, navigate to the Templates tab.
    6. +
    7. Expand the email template you want to edit.
    8. +
    9. Select the Template language [TODO: @damodar is this used for localization? Can you configure a different template for each language?].
    10. +
    11. Update the email template fields and click **Update** to save your changes.

    Email Templates

    -

    Add a SMTP provider

    -

    Email Template Syntax

    -

    Email Template Components

    +

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

    +

    Email Template Components

    +

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

    +

    Permission Types

    +

    In Client and Server SDKs, you will find a Permission class with helper methods for each role described below.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ComponentDescription
    Sender name[TODO: @damodar where is this used?].
    Sender email[TODO: @damodar which part of this can be configured? Does it have to do with the SMTP configuration?].
    Reply to[TODO: @damodar Where is this displayed, if empty is no reply?].
    SubjectThe title of the email.
    MessageThe body of the email. You can find the variables available in the Email Template Syntax section.
    +

    Email Template Syntax

    +

    [TODO: @damodar are these variables accessible only in the Message tempalte or also the other components?]

    - -

    SMS Templates

    - -

    SMS Template Syntax

    -

    SMS Template Components

    \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + +
    ComponentDescription
    {{project}}The project name.
    {{team}}Thee project team's name.
    {{user}}The name of the uer receiving the email.
    \ No newline at end of file From 703d2c36971b877dd078d864520a7bd4b0d1454e Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 18 May 2023 22:23:08 +0000 Subject: [PATCH 004/183] Update email template docs with Damodar's comments --- app/views/docs/email-and-sms-templates.phtml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index e776e3c84..c5a64819e 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -10,7 +10,7 @@
  • In your project, navigate to the Auth service.
  • Under the Auth service, navigate to the Templates tab.
  • Expand the email template you want to edit.
  • -
  • Select the Template language [TODO: @damodar is this used for localization? Can you configure a different template for each language?].
  • +
  • Select the Template language. You can have a different template for each language your app supports.
  • Update the email template fields and click **Update** to save your changes.
  • Email Templates

    @@ -29,15 +29,15 @@ Sender name - [TODO: @damodar where is this used?]. + Readers will see this as display name of the sender. Sender email - [TODO: @damodar which part of this can be configured? Does it have to do with the SMTP configuration?]. + Readers will see this as the displayed email of the sender. This must be a valid email for the SMTP provider your configured. Reply to - [TODO: @damodar Where is this displayed, if empty is no reply?]. + Readers will reply to this email adress instead of the sender address. You can leave this field empty if unused. Subject @@ -50,7 +50,7 @@

    Email Template Syntax

    -

    [TODO: @damodar are these variables accessible only in the Message tempalte or also the other components?]

    +

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

    From 5b880ecc121613a21871b9e854fd041cf29fd7c4 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 24 May 2023 21:33:20 +0000 Subject: [PATCH 005/183] Add SMS into the templates page --- app/views/docs/email-and-sms-templates.phtml | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index c5a64819e..c137a6053 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -73,4 +73,52 @@ +
    The name of the uer receiving the email.
    + +

    SMS Templates

    +

    You can customize the SMS emplates used for phone verification and login.

    +

    SMS Template Components

    + + + + + + + + + + + + + +
    ComponentDescription
    MessageThe body of the SMS message. You can find the variables available in the SMS Template Syntax section.
    + +

    SMS Template Syntax

    +

    Variables can be used in SMS templates to dynamically format unique messages for each reader.

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    ComponentDescription
    {{project}}The project name.
    {{team}}Thee project team's name.
    {{user}}The name of the uer receiving the email.
    {{passcode}}The secret code sent to users for phone verification or authentication.
    \ No newline at end of file From 455b4bf9972413d4b934838422fb2a27c43e230f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 25 May 2023 18:06:30 +0000 Subject: [PATCH 006/183] Fix table heading for variables --- app/views/docs/email-and-sms-templates.phtml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index c137a6053..b07c012a8 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -55,7 +55,7 @@ - + @@ -70,7 +70,11 @@ - + + + + +
    ComponentVariable Description
    {{user}}The name of the uer receiving the email.The name of the user receiving the email.
    {{redirect}}The URL for the user to complete the email template's action.
    @@ -99,7 +103,7 @@ - + From a0ebf266a8ef920bb9e3555c99fe3c2e549803c1 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 1 Jun 2023 19:42:24 +0000 Subject: [PATCH 007/183] prepare index for Function G4 --- app/views/docs/index.phtml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 63f2d6166..63da00806 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -65,7 +65,17 @@ $cols = [
  • Teams
  • Databases
  • Storage
  • -
  • Functions
  • +
  • + Functions + + +
  • Localization
  • Avatars
  • Health
  • From 3ee6a1f20b7f40bc5e63195915a9a96fa0af0e15 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 1 Jun 2023 19:56:41 +0000 Subject: [PATCH 008/183] Fix reference index, change guide index --- app/views/docs/index.phtml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 63da00806..67be0c3ad 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -65,17 +65,7 @@ $cols = [
  • Teams
  • Databases
  • Storage
  • -
  • - Functions - - -
  • +
  • Functions
  • Localization
  • Avatars
  • Health
  • @@ -102,7 +92,17 @@ $cols = [
  •   Security
  • -
  • Functions
  • +
  • + +
  •    Deploy
  • +
  •    Execute
  • +
  •    Syntax
  • +
  •    Runtimes
  • +
  •    Logging and Debugging
  • + +
    From d491591268e57ac6b8df384f237e4ff2d470c251 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 1 Jun 2023 20:00:05 +0000 Subject: [PATCH 009/183] Change debugging and logging to just debugging --- app/views/docs/index.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 67be0c3ad..7d9bb0b45 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -93,14 +93,14 @@ $cols = [
  • - Functions
  • From 2319af04424ed31b837390e13bf4fa409c2013ef Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 5 Jun 2023 20:54:26 +0000 Subject: [PATCH 010/183] Added more to template docs --- app/views/docs/email-and-sms-templates.phtml | 27 ++++++++++++++++---- app/views/docs/main.phtml | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index b07c012a8..db89e7ff9 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,7 +1,16 @@ -

    Appwrite uses emails messages to perform user invite, user verification, login, and reset password. Emails messages can be customized to fit your app's design and voice.

    +

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

    + +

    Each Appwrite project can have its own set of unique templates. Templates also support localization, every template can be written in multiple languages and served depending on the [TODO: @dlohani]

    + +

    +Email Templates +

    +

    +SMS Templates +

    Customize Templates

    -

    You can customize email templates in the Appwrite console.

    +

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

    Custom SMTP Server Required

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

    @@ -17,8 +26,6 @@

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

    Email Template Components

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

    -

    Permission Types

    -

    In Client and Server SDKs, you will find a Permission class with helper methods for each role described below.

    ComponentVariable Description
    @@ -79,6 +86,9 @@
    +

    Email Template Components

    +[TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)] +

    SMS Templates

    You can customize the SMS emplates used for phone verification and login.

    SMS Template Components

    @@ -125,4 +135,11 @@ The secret code sent to users for phone verification or authentication. - \ No newline at end of file + + +

    SMS Template Components

    +[TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)] + +

    Localization

    +[TODO: @dlohani short description of how it's decided which language's template is sent] +[TODO: @dlohani Maybe example of a template in two languages? (maybe also what it would look like rendered)] diff --git a/app/views/docs/main.phtml b/app/views/docs/main.phtml index 8c4db0f2e..373d4ab51 100644 --- a/app/views/docs/main.phtml +++ b/app/views/docs/main.phtml @@ -94,7 +94,7 @@ $getSpecsUrl = function($type, $platform) use ($latestVersion) {

    API References

    -

    The Appwrite API is organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded or JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

    +

    The Appwrite API is organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded or JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

    Specifications for the Appwrite API are available in multiple formats, including Open API 3 for clients or servers and Swagger2 for clients or servers.

    From 4a01a388818458d01e516370e8e473f1d3b08eee Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 6 Jun 2023 11:19:07 -0400 Subject: [PATCH 011/183] Update app/views/docs/email-and-sms-templates.phtml --- app/views/docs/email-and-sms-templates.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index db89e7ff9..55e83a8a5 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -137,7 +137,7 @@ -

    SMS Template Components

    +

    SMS Template Examples

    [TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)]

    Localization

    From 601dd293f7df9e8dbe891dd357322c8051b80f56 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 6 Jun 2023 11:19:14 -0400 Subject: [PATCH 012/183] Update app/views/docs/email-and-sms-templates.phtml --- app/views/docs/email-and-sms-templates.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 55e83a8a5..5ac15bbe5 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -86,7 +86,7 @@ -

    Email Template Components

    +

    Email Template Examples

    [TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)]

    SMS Templates

    From 4537a2b71a802db213009df5b741a45d2f374aed Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 17 Jul 2023 21:26:44 +0000 Subject: [PATCH 013/183] Init overview page --- app/views/docs/functions.phtml | 988 +++------------------------------ 1 file changed, 71 insertions(+), 917 deletions(-) diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml index 43fdedb12..0bdcb3d7e 100644 --- a/app/views/docs/functions.phtml +++ b/app/views/docs/functions.phtml @@ -7,920 +7,74 @@ $runtimes = $this->getParam('runtimes', []); ?> -

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

    - -

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

    - -

    Getting Started

    - -

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

    - -
    -
    appwrite init function
    -
    - -

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

    - -
    -
    appwrite deploy function
    -
    - -

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

    - -

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

    - -

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

    - -

    Writing your own Function

    - -

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

    - -
      -
    • -

      Node.js

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      PHP

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Python

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Ruby

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Deno

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Dart

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Swift

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

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

      -

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      .NET

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Kotlin

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      Java

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

      Installing Dependencies

      -

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

      -
      -
    • -
    • -

      C++

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

      Installing Dependencies

      -

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

      -
      -
    • -
    - - -

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

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

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

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

    Create your Function

    - -

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

    - -

    Deploy Your Function

    - -

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

    - -
      -
    • -

      Unix

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

      CMD

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

      PowerShell

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

    The command above accepts three parameters:

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

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

    - -

    Manual Deployment

    -

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

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

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

    - -
      -
    • -

      Unix

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

      CMD

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

      PowerShell

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

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

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

    Builds

    -

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

    - -

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

    - -

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

    - -

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

    - -
    -

    Build Times

    -

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

    -
    - -

    Execute

    - -

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

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

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

    - -

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

    - -

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

    - -
      -
    • -

      Web

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

      Flutter

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

      Android

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

      Apple

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

      GraphQL

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

    Scheduled Execution

    -

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

    - -

    Here are some cron expressions for common intervals.

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

    Abuse and Limits

    - -

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

    - -

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

    - -

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

    - -

    Ignore Files

    - -

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

    - -

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

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

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

    - -

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

    - -

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

    - -

    Supported Runtimes

    - -

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

    - -

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

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

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

    - -

    Function Variables

    - -

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

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

    version >= 0.8.0

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

    version >= 0.8.0

    -
    Your function's project ID.
    - APPWRITE_FUNCTION_USER_ID -

    version >= 0.8.0

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

    version >= 0.8.0

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

    version < 0.8.0 (deprecated)

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

    version < 0.8.0 (deprecated)

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

    version < 0.8.0 (deprecated)

    -
    Your function environment version.
    - -
    -

    Using an Appwrite SDK in Your Function

    -

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

    -

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

    -
    - -

    Appwrite SDKs in Functions

    - -

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

    - -

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

    - -

    Monitor & Debug

    - -

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

    - -

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

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

    Demos & Examples

    - -

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

    +

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

    + +

    Getting Started

    +

    + 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?] +

    + +

    Explore Features

    +

    + To fully harness the power of Appwrite Functions, explore the following features. +

    + +

    Templates

    +

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

    + +

    Deploy

    +

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

    + +

    Execute

    +

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

    + +

    Syntax

    +

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

    +

    +

    Runtime

    +

    +Appwrite supports many open-source runtimes. Find your prefered language and start writing your functions. +

    +

    +Learn more about using runtimes +

    +

    Debug

    +

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

    \ No newline at end of file From 52bdc62f0470e2fdfdfce95f48d037c7f5ecbe2a Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 18 Jul 2023 15:48:58 +0000 Subject: [PATCH 014/183] Reorder index, add shell for quickstart example --- app/views/docs/functions.phtml | 136 ++++++++++++++++++++++++++++++--- app/views/docs/index.phtml | 2 +- 2 files changed, 127 insertions(+), 11 deletions(-) diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml index 0bdcb3d7e..b8b94d905 100644 --- a/app/views/docs/functions.phtml +++ b/app/views/docs/functions.phtml @@ -16,9 +16,124 @@ $runtimes = $this->getParam('runtimes', []);

    Getting Started

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

    +
      +
    • +

      Node.js

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      PHP

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Python

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Ruby

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Deno

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Dart

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Swift

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      .NET

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      Kotlin

      +
      +
      +
      
      +
      +            
      +
      + +
      +
    • +
    • +

      Java

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    • +

      C++

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +
    + +

    Explore Features

    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

    +

    Syntax

    +

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

    +

    Deploy

    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

    -

    Syntax

    -

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

    -

    Runtime

    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

    From 6b2da17e590d92da5d8225df2dcd9643ef3154f1 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 18 Jul 2023 21:18:47 +0000 Subject: [PATCH 015/183] Added scaffolding --- app/views/docs/functions-debugging.phtml | 4 +++ app/views/docs/functions-deploy.phtml | 37 ++++++++++++++++++++++++ app/views/docs/functions-develop.phtml | 22 ++++++++++++++ app/views/docs/functions-execute.phtml | 35 ++++++++++++++++++++++ app/views/docs/functions-runtimes.phtml | 5 ++++ app/views/docs/functions.phtml | 10 +++++-- app/views/docs/index.phtml | 2 +- 7 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 app/views/docs/functions-debugging.phtml create mode 100644 app/views/docs/functions-deploy.phtml create mode 100644 app/views/docs/functions-develop.phtml create mode 100644 app/views/docs/functions-execute.phtml create mode 100644 app/views/docs/functions-runtimes.phtml diff --git a/app/views/docs/functions-debugging.phtml b/app/views/docs/functions-debugging.phtml new file mode 100644 index 000000000..870f19cdd --- /dev/null +++ b/app/views/docs/functions-debugging.phtml @@ -0,0 +1,4 @@ +

    + Appwrite Functions... do we need this page? +

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

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

    + +

    Version Control Systems

    +

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

    + +[TODO: Describe how to create a GitHub deployment] + +

    Create

    +

    Deploy

    +

    ...

    +

    Profit?!

    + +

    Templates

    + +

    CLI

    +[TODO] + +

    Manual

    +[TODO] + +

    Deployment Life Cycle

    +

    Deployments will go through the following states throughout their life cycle.

    +[TODO: @matej, describe the life cycle of a deployment (like being uploaded, built, etc)] + +[TODO: @matej What else?] \ No newline at end of file diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml new file mode 100644 index 000000000..4555356b5 --- /dev/null +++ b/app/views/docs/functions-develop.phtml @@ -0,0 +1,22 @@ +

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

    + +

    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 @@ +

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

    + +

    SDK

    +

    + +

    + +

    Preview Link

    +

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

    + +

    Events

    +

    + +

    + +

    Webhooks

    +

    + +

    + + +

    Schedule

    +

    + + +

    \ No newline at end of file diff --git a/app/views/docs/functions-runtimes.phtml b/app/views/docs/functions-runtimes.phtml new file mode 100644 index 000000000..5686a2d28 --- /dev/null +++ b/app/views/docs/functions-runtimes.phtml @@ -0,0 +1,5 @@ +

    + Appwrite Functions supports ... + wait. wut we do with runtimes not yet on cloud??? +

    + diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml index b8b94d905..5ad3d8853 100644 --- a/app/views/docs/functions.phtml +++ b/app/views/docs/functions.phtml @@ -157,7 +157,7 @@ In your function, you'll receive a request object, add transformations and logic Almost anything can be executed as code in an Appwrite Function.

    -Learn more about using function syntax +Learn more about using function syntax

    Deploy

    @@ -193,4 +193,10 @@ So it's important to be able to log, debug, and test your Appwrite Functions in

    Learn more about debugging functions -

    \ No newline at end of file +

    + +

    Upgrade

    +

    + 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?] +

    diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 8b772de6c..5f41f6647 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -96,7 +96,7 @@ $cols = [ Functions
      -
    •    Syntax
    • +
    •    Develop
    •    Deploy
    •    Execute
    •    Runtimes
    • From 9ea4f2c75c3859e8cefd7f296f14bc0cfdaf4eb0 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 20 Jul 2023 20:38:36 +0000 Subject: [PATCH 016/183] Add migrations: --- app/views/docs/index.phtml | 6 +++ app/views/docs/migration-firebase.phtml | 3 ++ app/views/docs/migration-nhost.phtml | 0 app/views/docs/migration-supabase.phtml | 0 app/views/docs/migration.phtml | 60 +++++++++++++++++++++++++ 5 files changed, 69 insertions(+) create mode 100644 app/views/docs/migration-firebase.phtml create mode 100644 app/views/docs/migration-nhost.phtml create mode 100644 app/views/docs/migration-supabase.phtml create mode 100644 app/views/docs/migration.phtml diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 3554cba88..11c8f4882 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -93,6 +93,12 @@ $cols = [
  • Functions
  • +
  • + Migration + +
  • diff --git a/app/views/docs/migration-firebase.phtml b/app/views/docs/migration-firebase.phtml new file mode 100644 index 000000000..4f811a0ea --- /dev/null +++ b/app/views/docs/migration-firebase.phtml @@ -0,0 +1,3 @@ +

    + [TODO: Bradley try to fill this in with necessary information + limitations] +

    \ No newline at end of file diff --git a/app/views/docs/migration-nhost.phtml b/app/views/docs/migration-nhost.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/docs/migration-supabase.phtml b/app/views/docs/migration-supabase.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/docs/migration.phtml b/app/views/docs/migration.phtml new file mode 100644 index 000000000..9757c6526 --- /dev/null +++ b/app/views/docs/migration.phtml @@ -0,0 +1,60 @@ +

    + Moving your app from another platform to Appwrite? + You can move your app from Firebase, Supabase, NHost, and even other Appwrite projects to another Appwrite project using Migrations. + Migrations will automatically move accounts, database documents, and storage files from one source to another. +

    + +

    Supported sources

    +

    + You can transfer from these sources to an Appwrite project. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Source
    + [IMAGE] + + Firebase + +

    Migrate from Firebase

    +
    + [IMAGE] + + Supabase + +

    Migrate from Supabase

    +
    + [IMAGE] + + NHost + +

    Migrate from NHost

    +
    + +

    Limitations

    +

    + [TODO] @bradley help me out here. include performance, feature, all things annoying +

    \ No newline at end of file From 6fbc33ae2c2b258ba35cd552a4a37bb18b9e28c6 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 21 Jul 2023 21:56:49 +0000 Subject: [PATCH 017/183] Add node js example --- app/views/docs/functions-debugging.phtml | 4 ---- app/views/docs/functions-deploy.phtml | 24 ++++++++++++++++---- app/views/docs/functions-develop.phtml | 11 +++++++-- app/views/docs/functions-execute.phtml | 29 +++++++++++++----------- app/views/docs/functions.phtml | 10 ++++---- 5 files changed, 50 insertions(+), 28 deletions(-) delete mode 100644 app/views/docs/functions-debugging.phtml diff --git a/app/views/docs/functions-debugging.phtml b/app/views/docs/functions-debugging.phtml deleted file mode 100644 index 870f19cdd..000000000 --- a/app/views/docs/functions-debugging.phtml +++ /dev/null @@ -1,4 +0,0 @@ -

    - Appwrite Functions... do we need this page? -

    - diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index 79d8fba2c..8f57badb0 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -9,20 +9,32 @@ Here's everything you need to know to deploy your first Appwrite Function.

    -

    Version Control Systems

    +

    Git

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

    [TODO: Describe how to create a GitHub deployment]

    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

    Deployments will go through the following states throughout their life cycle.

    -[TODO: @matej, describe the life cycle of a deployment (like being uploaded, built, etc)] +[TODO: @matej, describe the life cycle of a deployment (like being uploaded, built, build steps, etc.)] [TODO: @matej What else?] \ No newline at end of file diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 4555356b5..2997898fb 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -4,8 +4,7 @@ Here's what you need to know to start writing your first Appwrite Function.

    -

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

    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.

    -

    SDK

    +

    Domain

    - -

    - -

    Preview Link

    -

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

    -

    Events

    +DOMAIN IGNORE PERMISSIONS AOSDHFGAKSHDJG + +

    SDK

    +- two examples + -> sync + -> async + -> pass body

    -

    Webhooks

    +

    Events

    Schedule

    -

    - +

    -

    \ No newline at end of file +

    + +[TODO: EXECUTION ARTIFACTS/LOGS/STUFF] + diff --git a/app/views/docs/functions.phtml b/app/views/docs/functions.phtml index 5ad3d8853..86266c49a 100644 --- a/app/views/docs/functions.phtml +++ b/app/views/docs/functions.phtml @@ -24,9 +24,11 @@ $runtimes = $this->getParam('runtimes', []);

    Node.js

    -
    
    -
    -            
    +
    export default async ({ res }) => {
    +   return res.json({
    +    motto: 'Build Fast. Scale Big. All in One Place.'
    +  });
    +};
    @@ -150,7 +152,7 @@ $runtimes = $this->getParam('runtimes', []); Learn more about using function templates

    -

    Syntax

    +

    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. From 3610aadf00ef588ead24a9a00ba24d1789146a20 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 24 Jul 2023 21:35:34 +0000 Subject: [PATCH 018/183] More shell for the functions --- app/views/docs/functions-develop.phtml | 173 ++++++++++++++++++++++++- app/views/docs/functions.phtml | 8 +- 2 files changed, 177 insertions(+), 4 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 2997898fb..736039a0c 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -4,18 +4,189 @@ Here's what you need to know to start writing your first Appwrite Function.

    -[TODO: CTA if you just want examples, click this link] +
    +

    Just want the code?

    +

    If you prefer to learn through examples, explore the recipes section.

    +

    The Context Object

    +

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

    + +

    You'll find these properties in the context object.

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

    Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax.

    +[TODO: Example below for relevant languages.] +
      +
    • +

      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

    +

    + 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 context.log() and context.error() methods. + These logs are only visible to developers with access to the Appwrite Console. +

    -> LIST WHAT WE SHOW AND WHAT WE DONT SHOW

    Accessing Environment Variables

    +

    + If you need to pass constants or secrets to Appwrite Functions, you can use environment variables. +

    + +[TODO: ways to setup environment variables (link to deployment docs?)] + +

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

    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

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

    @@ -159,7 +161,7 @@ In your function, you'll receive a request object, add transformations and logic Almost anything can be executed as code in an Appwrite Function.

    -Learn more about using function syntax +Learn more about developing functions

    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.

    -Learn more about using deploying functions +Learn more about using deploying functions

    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.

    -Learn more about using executing functions +Learn more about using executing functions

    Runtime

    From 3858af8bc65bec51f93ea40f6d84d776a78ed4c1 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 25 Jul 2023 22:22:28 +0000 Subject: [PATCH 019/183] Add some request and response examples --- app/views/docs/functions-develop.phtml | 281 ++++++++++++++++++++++++- app/views/js.js | 32 +++ 2 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 app/views/js.js diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 736039a0c..d547d2864 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -161,13 +161,286 @@

    Request

    -[TODO: full table of what's in a request] -[TODO: full examples of what's in a request] +

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

    + +
      +
    • +

      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] +

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

    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" Date: Wed, 26 Jul 2023 00:22:19 +0000 Subject: [PATCH 020/183] Adds recipes page --- app/views/docs/functions-develop.phtml | 6 ++++-- app/views/docs/functions-recipes.phtml | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 app/views/docs/functions-recipes.phtml diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index d547d2864..8053f3f87 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -448,13 +448,15 @@ This means, to see logs or debug function executions you need to use the context.log() and context.error() methods. These logs are only visible to developers with access to the Appwrite Console.

    --> LIST WHAT WE SHOW AND WHAT WE DONT SHOW +

    Here's an example of using logs and errors.

    +[TODO] +

    You can access these logs through the following steps.

    +[TODO]

    Accessing Environment Variables

    If you need to pass constants or secrets to Appwrite Functions, you can use environment variables.

    - [TODO: ways to setup environment variables (link to deployment docs?)]

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

    +[TODO: @matej] \ No newline at end of file From 16267be21e81e3f2104366c2c2ce765beebdb383 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 26 Jul 2023 00:22:36 +0000 Subject: [PATCH 021/183] Fill in intro of recipes --- app/views/docs/functions-recipes.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml index a8149e25f..df6e9baac 100644 --- a/app/views/docs/functions-recipes.phtml +++ b/app/views/docs/functions-recipes.phtml @@ -3,4 +3,4 @@ Behind the simple workflow hides some useful recipes that can help you accomplish your goals faster. Take a look at the following.

    -[TODO: @matej] \ No newline at end of file +[TODO: @matej @luke -> Let's have some simple recipes here for common actions] \ No newline at end of file From 9819ffbfc38637abf6678b193690d8970d0153aa Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 26 Jul 2023 21:17:26 +0000 Subject: [PATCH 022/183] Filled in more information from development to runtimes and deployment --- app/views/docs/functions-deploy.phtml | 32 ++- app/views/docs/functions-develop.phtml | 268 +++++++++++++++++++++++- app/views/docs/functions-execute.phtml | 54 ++++- app/views/docs/functions-recipes.phtml | 3 +- app/views/docs/functions-runtimes.phtml | 38 ++++ 5 files changed, 369 insertions(+), 26 deletions(-) diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index 8f57badb0..1994682c9 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -37,15 +37,31 @@ - Make repository

    CLI

    -[TODO] +- Setup 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 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 function
    +
    -

    Manual

    -[TODO] +

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

    + +

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

    -[tar --exclude code.tar.gz -czf code.tar.gz .] +
    +
    appwrite deploy function
    +
    -

    Deployment Life Cycle

    -

    Deployments will go through the following states throughout their life cycle.

    -[TODO: @matej, describe the life cycle of a deployment (like being uploaded, built, build steps, etc.)] +

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

    If you prefer to learn through examples, explore the recipes section.

    +

    Function Flow

    +

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

    + +
      +
    1. Invokation, 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.
    2. +
    3. After a function is invoked, Appwrite passes request information to your function's executor.
    4. +
    5. The executor runs the function code you deployed and waits for it to return.
    6. +
    7. Function terminates either when the user returns with a method from context.res, when the user code throws an exception, or times out.
    8. +
    + +

    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. @@ -25,19 +39,19 @@ - context.req + context.req Contains request information like method, body, and headers. See full examples here. - context.res + context.res Contains methods to build a response and return information. See full examples here. - context.log + context.log Logs information to the Appwrite Console, end users will not be able to see these logs. See full examples here. - context.error + context.error Logs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here. @@ -450,7 +464,122 @@

    Here's an example of using logs and errors.

    -[TODO] +
      +
    • +

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

      +
      +
      +
      
      +
      +            
      +
      +
      +
    • +

    You can access these logs through the following steps.

    [TODO]

    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] +

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

    +

    Limitations

    - \ No newline at end of file +

    Libraries dependent on compiled binaries not available on the executors cannot be installed.

    \ No newline at end of file diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml index 174d7d771..85476f0c0 100644 --- a/app/views/docs/functions-execute.phtml +++ b/app/views/docs/functions-execute.phtml @@ -12,27 +12,61 @@ This unlocks interesting ways to integrate other apps and backends to your Appwrite project.

    -DOMAIN IGNORE PERMISSIONS AOSDHFGAKSHDJG

    SDK

    -- two examples - -> sync - -> async - -> pass body +TODO: two examples running the function sync and async form the SDK

    Events

    - + TODO: Describe steps to navigate the UI

    Schedule

    -

    - -

    +

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

    + +

    Here are some cron expressions for common intervals.

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Cron ExpressionSchedule
    */15 * * * *Every 15 minutes
    0 * * * *Every Hour
    0 0 * * *Every day at 00:00
    0 0 * * 1Every monday at 00:00
    -[TODO: EXECUTION ARTIFACTS/LOGS/STUFF] +

    Permissions

    +

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

    +

    + If your function 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. +

    +

    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', []); + +?> + +

    Appwrite Functions supports ... wait. wut we do with runtimes not yet on cloud???

    +

    Supported Runtimes

    + +

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

    + +

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

    + + + + + + + + + + + + $runtime): ?> + + + + + + + + +
    NameImageArchitectures
    Function Env.escape($key); ?> escape($runtime['image'] ?? ''); ?> escape(implode(' / ', $runtime['supports'] ?? [])); ?>
    + +[TODO: Label which ones are cloud only] From db582b56e9c942f3410f2f48b4850d2e09159456 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 27 Jul 2023 01:09:48 +0000 Subject: [PATCH 023/183] Add manual install command --- app/views/docs/functions-deploy.phtml | 49 +++++++++++++++++++++++-- app/views/docs/functions-runtimes.phtml | 4 +- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index 1994682c9..42067dc6d 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -61,7 +61,50 @@
    appwrite deploy function
    -

    Manual

    -[TODO] +

    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.

    -[tar --exclude code.tar.gz -czf code.tar.gz .] \ No newline at end of file +
    +
    .
    +├── package.json
    +└── index.js
    +
    +
    + +

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

    + +
      +
    • +

      Unix

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

      CMD

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

      PowerShell

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

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

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

    - 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 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" Date: Sun, 30 Jul 2023 22:55:58 +0000 Subject: [PATCH 024/183] Add git instructions --- app/views/docs/functions-deploy.phtml | 65 ++++++++++++++++++++------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index 42067dc6d..c5b92746a 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -4,7 +4,7 @@

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

    @@ -15,27 +15,60 @@ This offers simple versioning and collaboration that will easily fit into the rest of your development workflow.

    -[TODO: Describe how to create a GitHub deployment] +

    Create Funcion

    +

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

    +
      +
    1. + Navigate to Functions from the side bar of the Appwrite Console. +
    2. +
    3. + Click Create function. +
    4. +
    5. + When asked to Choose your source, under Connect Git repository, select your provider. +
    6. +
    7. + Search for the Git repository that hold your function and click connect. +
    8. +
    9. + Select a production branch. New commits made to the production branch will be automatically deployed and activated. +
    10. +
    11. + Input the root directory of the function inside the repository. +
    12. +
    13. + If you don't want deploy comments to be made on your PRs, select Silent mode. +
    14. +
    15. + 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. +
    16. +
    17. + If you have build steps, like installing dependencies, input the commands into the Build settings heading's Command field. +
    18. +
    19. + Finally, configure the execute permissions of the function. For security, only provide execute permissions to the necessary roles. +
    20. +
    -

    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 +
      +
    1. + Checkout your prodction branch in Git. +
    2. +
    3. + Create a new commit. +
    4. +
    5. + Push your new commit. +
    6. +
    7. + A new deployment will be automatically created. Deployments will be automatically activated when new commits are added to the production branch. +
    8. +

    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

    From 1092b844621658a60b45506e86b6af9a985e7040 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 31 Jul 2023 14:04:21 +0100 Subject: [PATCH 025/183] Start work on Firebase docs --- app/views/docs/migration-firebase.phtml | 58 ++++++++++++++++++++++++- app/views/docs/migration.phtml | 2 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/views/docs/migration-firebase.phtml b/app/views/docs/migration-firebase.phtml index 4f811a0ea..835c6553e 100644 --- a/app/views/docs/migration-firebase.phtml +++ b/app/views/docs/migration-firebase.phtml @@ -1,3 +1,59 @@ +

    Things to keep in mind

    - [TODO: Bradley try to fill this in with necessary information + limitations] + - Appwrite will waive usage fees during the migration process, however Firebase may still charge you for usage on their platform. + + - At the moment only top level document migrations are supported. Nested documents will not be transferred at this moment. + + - Appwrite migrations only supports Firestore. Realtime Database is not supported at this time. + + - OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete. +

    + +

    Supported Resources

    + + + + + + + + + + + + + + + + + + + + + +
    UsersDatabasesDocumentsFilesFunctions
    Firebase
    + +

    Migrating to Appwrite from Firebase

    +

    + To begin migrating to Appwrite make sure to read the migration overview and + things to keep in mind sections above. + + To begin you can either migrate while creating a new project or go into your project settings and click on the "Migrations" tab. + + Next click on the "Create Migration" button and select "Firebase" as your source. + +

    Migrating to Appwrite Cloud

    + To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically + discover your Firebase projects then you can simply just select the project you want to migrate from. + +

    Migrating to Appwrite Self-Hosted

    + If you are self-hosting Appwrite you will need to create a service account in your Firebase project and download the JSON file. + + To create a service account navigate to your Firebase console then click on the gear icon and select "Project Settings". + Next click on the "Service Accounts" tab and click on the "Generate New Private Key" button to download the JSON file. + + + + Once you have the JSON file downloaded you can click on "Manual Authentication" while going through the migration process and\ + upload the JSON file.

    \ No newline at end of file diff --git a/app/views/docs/migration.phtml b/app/views/docs/migration.phtml index 9757c6526..542744618 100644 --- a/app/views/docs/migration.phtml +++ b/app/views/docs/migration.phtml @@ -56,5 +56,5 @@

    Limitations

    - [TODO] @bradley help me out here. include performance, feature, all things annoying + - Migrations cannot transfer all data perfectly, so certain fields, such as $createdAt and $updatedAt, may not be transferred. More information can be found on the migration page for each source.

    \ No newline at end of file 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 026/183] 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', []);
    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.'
    +    });
     };
    @@ -36,9 +36,11 @@ $runtimes = $this->getParam('runtimes', []);

    PHP

    -
    
    -
    -            
    +
    return function ($context) {
    +    return $context->res->json([
    +        'motto' => 'Build Fast. Scale Big. All in One Place.'
    +    ]);
    +}
    @@ -46,9 +48,10 @@ $runtimes = $this->getParam('runtimes', []);

    Python

    -
    
    -
    -            
    +
    def main(context):
    +    return context.res.json({
    +        "motto": "Build Fast. Scale Big. All in One Place.",
    +})
    @@ -56,9 +59,13 @@ $runtimes = $this->getParam('runtimes', []);

    Ruby

    -
    
    -
    -            
    +
    def main(context)
    +    return context.res.json(
    +        {
    +            "motto": "Build Fast. Scale Big. All in One Place."
    +        }
    +    )
    +end
    @@ -66,9 +73,11 @@ $runtimes = $this->getParam('runtimes', []);

    Deno

    -
    
    -
    -            
    +
    export default ({ req, res, log, error }: any) => {
    +  return res.json({
    +    motto: "Build Fast. Scale Big. All in One Place."
    +  });
    +};
    @@ -76,9 +85,13 @@ $runtimes = $this->getParam('runtimes', []);

    Dart

    -
    
    +            
    import 'dart:async';
     
    -            
    +Future main(final context) async { + return context.res.json({ + 'motto': 'Build Fast. Scale Big. All in One Place.', + }); +}
    @@ -86,9 +99,13 @@ $runtimes = $this->getParam('runtimes', []);

    Swift

    -
    
    +            
    import Foundation
     
    -            
    + func main(context: RuntimeContext) async throws -> RuntimeOutput { + return try context.res.json([ + "motto": "Build Fast. Scale Big. All in One Place." + ]) +}
    @@ -96,9 +113,16 @@ $runtimes = $this->getParam('runtimes', []);

    .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." }
    +        });
    +    }
    +}
    @@ -106,9 +130,21 @@ $runtimes = $this->getParam('runtimes', []);

    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" + )) + } +}
    @@ -117,9 +153,19 @@ $runtimes = $this->getParam('runtimes', []);

    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); + } +}
    @@ -127,9 +173,21 @@ $runtimes = $this->getParam('runtimes', []);

    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); + } + }; +}
    From 7e10cc90feee9dc24849aab3e87f493f7b89d755 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 31 Jul 2023 19:44:12 +0000 Subject: [PATCH 027/183] Did some formatting --- app/views/docs/migration-firebase.phtml | 79 +++++++++++++++++-------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/app/views/docs/migration-firebase.phtml b/app/views/docs/migration-firebase.phtml index 835c6553e..300fbfd43 100644 --- a/app/views/docs/migration-firebase.phtml +++ b/app/views/docs/migration-firebase.phtml @@ -1,15 +1,20 @@ -

    Things to keep in mind

    - - Appwrite will waive usage fees during the migration process, however Firebase may still charge you for usage on their platform. - - - At the moment only top level document migrations are supported. Nested documents will not be transferred at this moment. + Moving your project from Firebase to Appwrite? + Appwrite Migrations can help you streamline the process. + + Here's what you need to know to get started. +

    - - Appwrite migrations only supports Firestore. Realtime Database is not supported at this time. +

    Things to keep in mind

    - - OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete. -

    +
      +
    1. Appwrite will not charge usage during migrations, but Firebase may still incur service charges.
    2. +
    3. Appwrite migrations only supports Firestore as a database source. Realtime Database is currently not supported.
    4. +
    5. At the moment only top level document migration is supported. Nested documents will not be transferred automatically.
    6. +
    7. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
    8. +
    -

    Supported Resources

    +

    Supported resource types

    @@ -35,25 +40,49 @@

    Migrating to Appwrite from Firebase

    - To begin migrating to Appwrite make sure to read the migration overview and - things to keep in mind sections above. - - To begin you can either migrate while creating a new project or go into your project settings and click on the "Migrations" tab. - - Next click on the "Create Migration" button and select "Firebase" as your source. + To begin migrating to Appwrite make sure to read the migration overview + and things to keep in mind sections above. +

    + +
      +
    1. + Create a new project and click on the Migrations tab. +
    2. +
    3. + Click on the Create Migration button and select Firebase as your source. +
    4. +
    5. + Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. +
    6. +
    -

    Migrating to Appwrite Cloud

    - To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically - discover your Firebase projects then you can simply just select the project you want to migrate from. -

    Migrating to Appwrite Self-Hosted

    - If you are self-hosting Appwrite you will need to create a service account in your Firebase project and download the JSON file. - To create a service account navigate to your Firebase console then click on the gear icon and select "Project Settings". - Next click on the "Service Accounts" tab and click on the "Generate New Private Key" button to download the JSON file. +

    Appwrite Cloud

    +

    + To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically + discover your Firebase projects. Simply select the source project and follow the migration wizard. +

    - +

    Migrating to Appwrite Self-Hosted

    +

    + If you are self-hosting Appwrite you will need to create a service account in your Firebase project and download the JSON file. +

    - Once you have the JSON file downloaded you can click on "Manual Authentication" while going through the migration process and\ - upload the JSON file. -

    \ No newline at end of file +
      +
    1. + Navigate to your Firebase console. +
    2. +
    3. + Click the gear icon to access your Project Settings. +
    4. +
    5. + Click Service Accounts, then Generate New Private Key. Don't share this key with anyone! +
    6. +
    7. + Once you've downloaded your private key, head back to Appwrite and click Manual Authentication. +
    8. +
    9. + Upload the JSON private key and follow the wizard. +
    10. +
    From b5ec4432dd0d1215ddb7a27b1f869982f1383645 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:19:32 +0100 Subject: [PATCH 028/183] feat: js currency convert recipe --- app/views/docs/functions-recipes.phtml | 110 ++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/app/views/docs/functions-recipes.phtml b/app/views/docs/functions-recipes.phtml index a6e6f7e09..230b58619 100644 --- a/app/views/docs/functions-recipes.phtml +++ b/app/views/docs/functions-recipes.phtml @@ -1,7 +1,113 @@

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

    [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 + +

    Section 1: My First Function

    + +

    Creating the function

    + +
      +
    1. Create a new file, `index.js`.
    2. +
    3. Add the following code to `index.js`. This code will return 1.13 when the function is called, because 1€ equals approximately 1.13$. + +
      +
      module.exports = async function ({ res }) {
      +  return res.end('1.13');
      +};
      +
      + +
    4. Initialize a Git repository and add `index.js` to it with the following Bash commands: + +
      +
      git init
      +git add index.js
      +git commit -m "Initial commit"
      +
      +
      + +
    5. Then, create a function in the Appwrite console and add your Git repository as the remote source.
    6. +
    7. Finally, execute the function and visit the URL (like `ghrfu9ewji.functions.appwrite.app`) to see the response.
    8. +
    + +

    Section 2: Let's Use Payload

    + +

    Updating the function

    + +
      +
    1. Update `index.js` to use `req.query.amount` to calculate the conversion. The following code takes the amount in Euros from the URL and converts it to Dollars using a static conversion rate. + +
      +
      module.exports = async function ({ req, res }) {
      +  const amountInEuros = Number(req.query.amount);
      +  const amountInDollars = amountInEuros * 1.13;
      +  return res.end(amountInDollars.toString());
      +};
      +
      + +
    2. Commit your changes and push them to your Git repository.
    3. +
    + +

    Testing the function

    + +
      +
    1. Once the function is updated, you can test it by visiting the URL and providing different amounts to convert in the query string. For example, `ghrfu9ewji.functions.appwrite.app?amount=5` should return `5.65`.
    2. +
    + +

    Section 3: Installing Dependencies

    + +

    Preparing for dependencies

    + +
      +
    1. Run `npm init --yes` to create a `package.json` file. This file is used to manage your Node.js project's dependencies.
    2. +
    3. Install the `undici` library with `npm install undici`. This library includes a `fetch` function that you can use to make HTTP requests.
    4. +
    + +

    Updating the function

    + +
      +
    1. Update `index.js` to use `fetch` from `undici` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. + +
      +
      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());
      +};
      +
      + +
    2. Commit your changes and push them to your Git repository.
    3. +
    + +

    Testing the function

    + +
      +
    1. 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.
    2. +
    + +

    Section 4: More Routes

    + +

    Updating the function

    + +
      +
    1. Edit `index.js` to support multiple paths like `/eur`, `/czk`, `/ft`, `/rub`. Each path will convert from that currency to dollars. Note that you will need to update the fetch URL for each new path.
    2. +
    3. Commit your changes and push them to your Git repository.
    4. +
    + +

    Testing the function

    + +
      +
    1. 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/czk?amount=100` should convert Czech Koruna to Dollars.
    2. +
    + +

    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] \ No newline at end of file From dbe2e9f8ba3f2a7f2319f1fdaeaac0382a97c561 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 1 Aug 2023 14:53:04 +0000 Subject: [PATCH 029/183] Fix Damodar's comments --- app/views/docs/email-and-sms-templates.phtml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 5ac15bbe5..7511ce244 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,6 +1,10 @@

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

    -

    Each Appwrite project can have its own set of unique templates. Templates also support localization, every template can be written in multiple languages and served depending on the [TODO: @dlohani]

    +

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

    Email Templates @@ -141,5 +145,5 @@ [TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)]

    Localization

    -[TODO: @dlohani short description of how it's decided which language's template is sent] +

    You can configure localization by settling locale with client.setLocale in the SDKs or the X-Appwrite-Locale HTTP header.

    [TODO: @dlohani Maybe example of a template in two languages? (maybe also what it would look like rendered)] From 57411541ebe90f1642a21ec4f3e49617cfea96f0 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 1 Aug 2023 18:54:59 +0000 Subject: [PATCH 030/183] added todo comments for develop page --- app/views/docs/functions-develop.phtml | 53 +++++++++++++++++++++----- app/views/docs/index.phtml | 2 +- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 28ee83399..803ce3f36 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -59,7 +59,7 @@

    Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax.

    -[TODO: Example below for relevant languages.] +[TODO: @luke for languages that have unpacking, let's add unpacking examples!]
    • 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.] +
      • 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 @@

          Here's an example of using logs and errors.

          +[TODO: @luke Let's make sure we show an example for evert runtime with good string manip methods.]
          • Node.js

            @@ -581,21 +586,54 @@

          You can access these logs through the following steps.

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

          Accessing Environment Variables

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

          + +

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

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

          Global Variables

          +

          + Global variables are accessible to all Appwrite Functions. + Local variables will override global variables when they have conflicting names.

          -[TODO: ways to setup environment variables (link to deployment docs?)] +
            +
          1. In Appwrite Console, navigate to your project's Settings page.
          2. +
          3. Navigate to Global variables section.
          4. +
          5. Create an environment variable by clicking Create variable, using the Editor, or import new variables through a .env file.
          6. +

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

          +[TODO: @luke show how you access environment varibles for every language (sorry for the pain!)] +

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

          Explore examples and recipes -

          - - -

          Limitations

          -

          Libraries dependent on compiled binaries not available on the executors cannot be installed.

          \ No newline at end of file +

          \ No newline at end of file diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 5f41f6647..44007ad43 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -100,7 +100,7 @@ $cols = [
        •    Deploy
        •    Execute
        •    Runtimes
        • -
        •    Debugging
        • +
        •    Recipes
      From 29fc3c15d9a80f6cfcda58f546d5f0a8ab543d32 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 1 Aug 2023 19:09:49 +0000 Subject: [PATCH 031/183] Fix up deployment docs --- app/views/docs/functions-deploy.phtml | 14 +++++++++++--- app/views/docs/index.phtml | 10 +++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index c5b92746a..fb9791ca2 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -66,11 +66,19 @@
    • Debugging Builds

      -- Check logs and errors -- Redeploy button for non-code issues [TODO: @matej write an example] +

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

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

      CLI

      -- Setup cli +
      +

      CLI Setup

      +

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

      +

      To deploy with the Appwrite CLI, your function's folder structure must be configured in a specific way. The folder path is then added to a config file called 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

    From 31c7c44813afa7fd43a4e8628a0a1985ea061a49 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 1 Aug 2023 19:24:05 +0000 Subject: [PATCH 032/183] Add comments and todo tags for all pages in Functions --- app/views/docs/functions-execute.phtml | 16 ++++++++++++++-- app/views/docs/functions-recipes.phtml | 20 +++++++++++++++++++- app/views/docs/functions-runtimes.phtml | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml index 85476f0c0..387ca1dc3 100644 --- a/app/views/docs/functions-execute.phtml +++ b/app/views/docs/functions-execute.phtml @@ -14,15 +14,26 @@

    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

    - TODO: Describe steps to navigate the UI + Changes in Appwrite emit events. + You can configure Functions to be executed in response to these events.

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

    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', []); -[TODO: Label which ones are cloud only] +[TODO: @matej Label which ones are cloud only, idk how to do cleanly] From a76e1ea5536ce4908fd5e2e8f2d7319a376c0e15 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 2 Aug 2023 19:09:58 +0000 Subject: [PATCH 033/183] Added instructions for setup to include adding platforms --- app/views/docs/migration-firebase.phtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/docs/migration-firebase.phtml b/app/views/docs/migration-firebase.phtml index 300fbfd43..2d4951cc2 100644 --- a/app/views/docs/migration-firebase.phtml +++ b/app/views/docs/migration-firebase.phtml @@ -52,12 +52,14 @@ Click on the Create Migration button and select Firebase as your source.
  • - Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. + Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. + See the Cloud and Self-hosting sections for details. +
  • +
  • + Finally, add the platforms for your Web, Flutter, Android, and iOS apps.
  • - -

    Appwrite Cloud

    To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically From d9c2d5d833ec38c0145fe7d48e791b212beeca08 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 2 Aug 2023 21:45:58 +0000 Subject: [PATCH 034/183] Add clarification that you need to run deploy command next to appwrite.json --- app/views/docs/command-line-deployment.phtml | 14 ++++++++++---- app/views/docs/functions-deploy.phtml | 9 ++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/views/docs/command-line-deployment.phtml b/app/views/docs/command-line-deployment.phtml index 79487ed3f..a0903c6a6 100644 --- a/app/views/docs/command-line-deployment.phtml +++ b/app/views/docs/command-line-deployment.phtml @@ -27,7 +27,7 @@ The Apprite CLI allows you to create and deploy databases, collections, buckets,

    Deploying Appwrite Functions

    -

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

    +

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

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

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

    +

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

    + +

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

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

    Deploying Databases and Collections

    -

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

    +

    The Appwrite CLI also helps you 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 appwrite.json file.

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

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

    +

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

    appwrite deploy team
    -

    Deploying Storage Buckets

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

    +

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

    +
    appwrite deploy bucket
    diff --git a/app/views/docs/functions-deploy.phtml b/app/views/docs/functions-deploy.phtml index fb9791ca2..bebd906f0 100644 --- a/app/views/docs/functions-deploy.phtml +++ b/app/views/docs/functions-deploy.phtml @@ -80,9 +80,12 @@

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

    + +

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

    appwrite init function
    From b4fb7387e93fe53a59f37da3322eac3e5c03a60b Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 3 Aug 2023 00:50:36 +0100 Subject: [PATCH 035/183] Add docs for cloud to local and visa-versa --- app/views/docs/cloud-to-local.phtml | 33 ++++++++++++++++++++++++++++ app/views/docs/local-to-cloud.phtml | 34 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 app/views/docs/cloud-to-local.phtml create mode 100644 app/views/docs/local-to-cloud.phtml diff --git a/app/views/docs/cloud-to-local.phtml b/app/views/docs/cloud-to-local.phtml new file mode 100644 index 000000000..160c35c07 --- /dev/null +++ b/app/views/docs/cloud-to-local.phtml @@ -0,0 +1,33 @@ +

    + Want to leave the cloud and move your stuff to a Self Hosted instance? We're sorry to see you go, but we've got your back. + Migrations makes it easy as easy as a couple clicks to move all of your cloud data to a Self Hosted instance. +

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    3. Your Appwrite Instace must be accessible from the internet for the migration to work.
    4. +
    + +

    Migrating to Self Hosted from Cloud

    + +

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

    + +

    + Navigate to your Appwrite Cloud and click on the Migrations tab. + + From there you can click on the Export to Self Hosted button, you will then be asked to input the URL of your Self Hosted instance + aswell as an optional feedback question asking why Self Hosted is a better fit for you. Once done you can click on the Continue button and you will be + redirected to your Self Hosted instance to continue the migration process. + + Once your at Self Hosted instance you will be prompted to select the organization aswell as the option to either create a new project + or select an existing project to migrate to. + + After you have selected the project you want to migrate to you will be asked what data you want to migrate. You can select + to migrate users, databases, documents, files and functions. Once you have selected what data you want to migrate you can + click on the Start Migration button to begin the migration process. +

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

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

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    + +

    Migrating to Cloud from Self Hosted

    +

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

    + +

    + Navigate to your Self Hosted instance and click on the Migrations tab. + + From there you can click on the Deploy to Cloud button, you will then be redirected to Appwrite Cloud. + + Once your at Appwrite Cloud you will be prompted to select the organization aswell as the option to either create a new project + or select an existing project to migrate to. + + After you have selected the project you want to migrate to you will be asked what data you want to migrate. You can select + to migrate users, databases, documents, files and functions. Once you have selected what data you want to migrate you can + click on the Start Migration button to begin the migration process. +

    + +
    +

    Keep in mind

    +

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

    +
    \ No newline at end of file From 573755c693697d5bc26cdd76cb4cc245e7b32628 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 3 Aug 2023 21:58:08 +0000 Subject: [PATCH 036/183] Fix cloud -> local --- app/views/docs/cloud-to-local.phtml | 33 ------------------- app/views/docs/migration-cloud-to-local.phtml | 33 +++++++++++++++++++ ...d.phtml => migration-local-to-cloud.phtml} | 0 3 files changed, 33 insertions(+), 33 deletions(-) delete mode 100644 app/views/docs/cloud-to-local.phtml create mode 100644 app/views/docs/migration-cloud-to-local.phtml rename app/views/docs/{local-to-cloud.phtml => migration-local-to-cloud.phtml} (100%) diff --git a/app/views/docs/cloud-to-local.phtml b/app/views/docs/cloud-to-local.phtml deleted file mode 100644 index 160c35c07..000000000 --- a/app/views/docs/cloud-to-local.phtml +++ /dev/null @@ -1,33 +0,0 @@ -

    - Want to leave the cloud and move your stuff to a Self Hosted instance? We're sorry to see you go, but we've got your back. - Migrations makes it easy as easy as a couple clicks to move all of your cloud data to a Self Hosted instance. -

    - -

    Things to keep in mind

    - -
      -
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. -
    3. Your Appwrite Instace must be accessible from the internet for the migration to work.
    4. -
    - -

    Migrating to Self Hosted from Cloud

    - -

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

    - -

    - Navigate to your Appwrite Cloud and click on the Migrations tab. - - From there you can click on the Export to Self Hosted button, you will then be asked to input the URL of your Self Hosted instance - aswell as an optional feedback question asking why Self Hosted is a better fit for you. Once done you can click on the Continue button and you will be - redirected to your Self Hosted instance to continue the migration process. - - Once your at Self Hosted instance you will be prompted to select the organization aswell as the option to either create a new project - or select an existing project to migrate to. - - After you have selected the project you want to migrate to you will be asked what data you want to migrate. You can select - to migrate users, databases, documents, files and functions. Once you have selected what data you want to migrate you can - click on the Start Migration button to begin the migration process. -

    diff --git a/app/views/docs/migration-cloud-to-local.phtml b/app/views/docs/migration-cloud-to-local.phtml new file mode 100644 index 000000000..5927d792c --- /dev/null +++ b/app/views/docs/migration-cloud-to-local.phtml @@ -0,0 +1,33 @@ +

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

    + +

    Things to keep in mind

    + +
      +
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    3. Your Appwrite Instace must be accessible from the internet for the migration to work.
    4. +
    + +

    Migrating to Self-hosted from Cloud

    + +

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

    + +

    Steps on Your Cloud Project

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

    Steps on Your Self-hosted Project

    +
      +
    1. Once redirected to your self-hosted project, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    \ No newline at end of file diff --git a/app/views/docs/local-to-cloud.phtml b/app/views/docs/migration-local-to-cloud.phtml similarity index 100% rename from app/views/docs/local-to-cloud.phtml rename to app/views/docs/migration-local-to-cloud.phtml From b84453104cbacea6743e38fee8e0068d328a645d Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 4 Aug 2023 14:59:52 +0000 Subject: [PATCH 037/183] Complete appwrite->appwrite guides --- app/views/docs/migration-cloud-to-local.phtml | 9 +++--- app/views/docs/migration-local-to-cloud.phtml | 32 +++++++++++-------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/app/views/docs/migration-cloud-to-local.phtml b/app/views/docs/migration-cloud-to-local.phtml index 5927d792c..3f601a2ec 100644 --- a/app/views/docs/migration-cloud-to-local.phtml +++ b/app/views/docs/migration-cloud-to-local.phtml @@ -1,26 +1,27 @@

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

    Things to keep in mind

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

    Migrating to Self-hosted from Cloud

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

    Steps on Your Cloud Project

    1. Navigate to your Appwrite Cloud Console and click on the Migrations tab.
    2. -
    3. Click Export to Self Hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
    4. +
    5. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
    6. Optionally, tell us about why you're moving to self-hosted.
    7. After clicking Continue, you'll be directed back to your self-hosted project to complete the process.
    diff --git a/app/views/docs/migration-local-to-cloud.phtml b/app/views/docs/migration-local-to-cloud.phtml index 3648b25ee..e30783d4b 100644 --- a/app/views/docs/migration-local-to-cloud.phtml +++ b/app/views/docs/migration-local-to-cloud.phtml @@ -1,34 +1,38 @@

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

    Things to keep in mind

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

    Migrating to Cloud from Self Hosted

    +

    Migrating to Self-hosted from Cloud

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

    -

    - Navigate to your Self Hosted instance and click on the Migrations tab. - - From there you can click on the Deploy to Cloud button, you will then be redirected to Appwrite Cloud. +

    Steps on Your Self-hosted Project

    - Once your at Appwrite Cloud you will be prompted to select the organization aswell as the option to either create a new project - or select an existing project to migrate to. +
      +
    1. Navigate to your self-hosted project's console and click on the Migrations tab.
    2. +
    3. Click Deploy to cloud, you will be redirected to Appwrite Cloud.
    4. +
    5. You will complete the migration on Appwrite Cloud.
    6. +
    - After you have selected the project you want to migrate to you will be asked what data you want to migrate. You can select - to migrate users, databases, documents, files and functions. Once you have selected what data you want to migrate you can - click on the Start Migration button to begin the migration process. -

    +

    Steps on Your Cloud Project

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

    Keep in mind

    -

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

    +

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

    \ No newline at end of file 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 038/183] 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 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.

    [TODO: @matej @luke -> Let's have some simple recipes here for common actions] -

    Section 1: My First Function

    +

    Getting Started

    -

    Creating the function

    - -
      -
    1. Create a new file, `index.js`.
    2. -
    3. Add the following code to `index.js`. This code will return 1.13 when the function is called, because 1€ equals approximately 1.13$. +

      + In this recipe, we'll build a simple function for currency conversion. +

      -
      -
      module.exports = async function ({ res }) {
      -  return res.end('1.13');
      +
        +
      • +

        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');
         };
        -
        - -
      • Initialize a Git repository and add `index.js` to it with the following Bash commands: - -
        -
        git init
        -git add index.js
        -git commit -m "Initial commit"
        -
        -
        - -
      • Then, create a function in the Appwrite console and add your Git repository as the remote source.
      • -
      • Finally, execute the function and visit the URL (like `ghrfu9ewji.functions.appwrite.app`) to see the response.
      • -
    - -

    Section 2: Let's Use Payload

    - -

    Updating the function

    - -
      -
    1. Update `index.js` to use `req.query.amount` to calculate the conversion. The following code takes the amount in Euros from the URL and converts it to Dollars using a static conversion rate. - -
      -
      module.exports = async function ({ req, res }) {
      +      
      +
    + +
  • +

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

    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.

    + +
      +
    • +

      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.end(amountInDollars.toString());
      +  return res.send(amountInDollars.toString());
       };
      -
      - -
    • Commit your changes and push them to your Git repository.
    • - - -

      Testing the function

      - -
        -
      1. Once the function is updated, you can test it by visiting the URL and providing different amounts to convert in the query string. For example, `ghrfu9ewji.functions.appwrite.app?amount=5` should return `5.65`.
      2. -
      - -

      Section 3: Installing Dependencies

      - -

      Preparing for dependencies

      +
    + + +
  • +

    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);
    +};
    +
    +
    +
  • + -
      -
    1. Run `npm init --yes` to create a `package.json` file. This file is used to manage your Node.js project's dependencies.
    2. -
    3. Install the `undici` library with `npm install undici`. This library includes a `fetch` function that you can use to make HTTP requests.
    4. -
    +

    Commit your changes and push them to your Git repository.

    -

    Updating the function

    -
      -
    1. Update `index.js` to use `fetch` from `undici` to get the current conversion rate. This API call will return the current conversion rate between Euros and Dollars. +

      Testing the function

      -
      -
      const { fetch } = require('undici');
      +

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

      -module.exports = async function ({ req, res }) { +

      Adding Dependencies

      + +
        +
      • +

        Node.js

        +
        +

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

        +
        +
        npm init -y
        +
        +

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

        +
        +
        npm install undici
        +
        +

        Finally, we need to add `npm install` to your function's build commands in the Appwrite console.

        +
        +
      • +
      + +

      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://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());
         };
        -
        - -
      • Commit your changes and push them to your Git repository.
      • -
    - -

    Testing the function

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

    Section 4: More Routes

    - -

    Updating the function

    - -
      -
    1. Edit `index.js` to support multiple paths like `/eur`, `/czk`, `/ft`, `/rub`. Each path will convert from that currency to dollars. Note that you will need to update the fetch URL for each new path.
    2. -
    3. Commit your changes and push them to your Git repository.
    4. -
    - -

    Testing the function

    - -
      -
    1. 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/czk?amount=100` should convert Czech Koruna to Dollars.
    2. -
    + + + + + +

    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.

    + +

    Adding More Routes

    + +

    Let's add support multiple paths like `/eur` and `/inr`. Each path will convert from that currency to dollars.

    + +
      +
    • +

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

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

    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.

    @@ -141,7 +181,89 @@ return function ($context) {
    npm install undici
    -

    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.

    + + +
  • +

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

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

    +
    +
    composer require guzzlehttp/guzzle
    +
    +

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

    +
    +
  • +
  • +

    Python

    +
    +

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

    +
    +
    touch requirements.txt
    +
    +

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

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

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

    +
    +
  • +
  • +

    + Dart +

    +
    +

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

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

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

    +
    +
    
    +          pub install http
    +      
    +

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

    +
    +
  • +
  • +

    + Ruby +

    +
    +

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

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

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

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

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

  • @@ -166,6 +288,79 @@ export default async function ({ req, res }) { +
  • +

    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
    +
    +
    +
  • Deploy your changes

    @@ -205,6 +400,92 @@ export default async function ({ req, res }) { +
  • +

    Python

    +
    +

    +

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

    Dart

    +
    +

    +

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

    Ruby

    +
    +

    +

    +
    require 'httparty'
    +
    +def main(context)
    +  if context.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
    +
    +
    +
  • +

    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.

    From 1e34f712dd496814a2b234880ba9acee4a497869 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:13:45 +0100 Subject: [PATCH 040/183] feat: destructuring examples --- app/views/docs/functions-develop.phtml | 110 +++---------------------- 1 file changed, 11 insertions(+), 99 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 803ce3f36..68411f460 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -58,46 +58,17 @@ -

    Some lamguages support unpacking. You'll see us use unpacking in examples, which has the following syntax.

    -[TODO: @luke for languages that have unpacking, let's add unpacking examples!] +

    Some languages support destructuring. You'll see us use destructing in examples, which has the following syntax.

    • 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!`)
      +}
    • @@ -105,70 +76,11 @@

      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!`)
      +}
    • From 30e2d2922437fd1ca13d15b829f3b4d064775c9a Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:44:06 +0100 Subject: [PATCH 041/183] feat: env vars --- app/views/docs/functions-develop.phtml | 96 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 68411f460..998b51f6a 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -93,7 +93,7 @@ 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.] +[TODO: @luke Let's make sure we show an example for event runtime with good string manip methods.]
      • @@ -101,7 +101,7 @@
        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 042/183] 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 c4e6f150924a9991886ebe03faf0c7689a1f9bf8 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 14 Aug 2023 18:07:32 +0000 Subject: [PATCH 064/183] Add tags for engineers to add examples --- app/views/docs/authentication-anonymous.phtml | 8 ++++++- .../docs/authentication-email-pass.phtml | 5 ++-- app/views/docs/authentication-magic.phtml | 2 +- .../docs/authentication-management.phtml | 4 ++-- app/views/docs/authentication-oauth.phtml | 23 ++++++++++--------- app/views/docs/authentication-security.phtml | 3 ++- app/views/docs/authentication-sms.phtml | 2 +- app/views/docs/getting-started-for-web.phtml | 2 +- 8 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 93d6dbc64..f0c9b236f 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -108,8 +108,14 @@ mutation {
      1. Email and password +
      2. +
      3. Phone - Magic URL +
      4. +
      5. + Magic URL +
      6. +
      7. OAuth2
      \ No newline at end of file diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index c9cee86f7..8e8b5dd39 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -160,7 +160,7 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

      -[TODO: Who ever: examples to parse query params from page and complete verification] +[TODO: @bradley examples to parse query params from page and complete verification]

      Log In

      @@ -457,4 +457,5 @@ let token = try await account.updateRecovery(

    Security

    -[TODO: Talk about the password security features] \ No newline at end of file +[TODO: @steven Talk about the password security features like password dictionary, passowrd history, and prevent personal information.] +[Be brief, link to security page for details] \ No newline at end of file diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 1f89e0346..d863b7611 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -106,7 +106,7 @@ let user = try await account.createMagicURLSession( After receiving your secret from an email, you can create a session.

    -[TODO: Engineers, please update the examples below with how to get the secret from the magic URL] +[TODO: @bradley, please update the examples below with how to get the secret from the magic URL]
    • diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 69db8cb05..8f636fcfc 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -4,9 +4,9 @@ Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

      -[TODO @STEVEN: TEAMS examples] +[TODO @steven: TEAMS docs] -[TODO @STEVEN: Labels] +[TODO @steven: Labels docs]

      User Preferences

      diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 5fcbb32ee..18f8b69d1 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -14,11 +14,13 @@ Before using OAuth2 login, you need to enable and configure a OAuth2 login provider.

      -[TODO] -1. Navigate to your Appwrite project -2. Navigate to **Auth** > **Settings** -3. Find and open the OAuth provider -4. In the **Zoom OAuth2 Settings** modal, use the toggle to enable the provider +
        +
      1. Navigate to your Appwrite project
      2. +
      3. Navigate to Auth > Settings
      4. +
      5. Find and open the OAuth provider.
      6. +
      7. In the OAuth2 settings modal, use the toggle to enable the provider
      8. +
      +

      Initialize OAuth2 Login

      @@ -103,10 +105,9 @@ try await account.createOAuth2Session(provider: "amazon")

      OAuth 2 Profile

      - + [TODO: @steven fill the docs to access profile information]

      -

      Refresh Tokens

      OAuth2 sessions expire to protect from security risks. @@ -129,8 +130,8 @@ client .setProject('[PROJECT_ID]') // Your Project ID ; -// Go to Zoom OAuth login page -account.createOAuth2Session('zoom', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]'); +// Go to Amazon OAuth login page +account.createOAuth2Session('amazon', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]');

    • @@ -148,7 +149,7 @@ void main() async { // OAuth Login, for simplest implementation you can leave both success and // failure link empty so that Appwrite handles everything. - await account.createOAuth2Session(provider: 'zoom'); + await account.createOAuth2Session(provider: 'amazon'); } @@ -165,7 +166,7 @@ val client = Client(context) val account = Account(client) -account.createOAuth2Session(provider = "zoom") +account.createOAuth2Session(provider = "amazon")
    • diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 28a1a475b..8e98a7b90 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -92,7 +92,8 @@

      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.

      Personal Information

      + +[TODO: @steven Talk about new personal information thing.] \ No newline at end of file diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index b02f581b9..49c7c6483 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -16,7 +16,7 @@ A new account will be created for this phone number if it has never been used before.

      -[TODO: to engineer: update these examples to show where the userID comes from (continuity from first request to next)] +[TODO: @bradley update these examples to show where the userID comes from (continuity from first request to next)]
      • diff --git a/app/views/docs/getting-started-for-web.phtml b/app/views/docs/getting-started-for-web.phtml index d7ec5bc2a..51d3428df 100644 --- a/app/views/docs/getting-started-for-web.phtml +++ b/app/views/docs/getting-started-for-web.phtml @@ -27,7 +27,7 @@ $demos = $platform['demos'] ?? [];

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

        - +

        Get Appwrite Web SDK

        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 065/183] 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

        + + + + + + + + + + + + + +
        VariableDescription
        + +

        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 066/183] 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. +

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

      - -
        -
      1. - The parameter passed into functions has changed. - req and res has been replaced by context, which contains new logger methods. - Learn about context. -
      2. -
      3. - To improve privacy and logging reliability, we provide new context.log() and context.error() functions. - You can no longer use native logging methods. - Learn about logging. -
      4. -
      5. - The old way of req.variables has been deprecated. - You can now access variables passed into each function as environment variables. - Learn about environment variables. -
      6. -
      7. - The req object has been updated to use terminology consistent with typical HTTP concepts. - You'll now find familiar concepts like headers, body, HTTP methods, and others. - Learn about request. -
      8. -
      9. - The response object has been updated. - You can now specify headers, as well as use new methods like return redirects or empty responses. - Learn about response. -
      10. -
      11. - Now, you must return a response such as return context.res.send(""). - This prevents confusing errors when functions are terminated prematurely before a response is sent. - Learn about response. -
      12. -
      13. - Some variables about how a function was triggered are now found in the context.req object as headers. -
      14. -
      - 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 067/183] 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 068/183] 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 069/183] 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 46ffc50db33703f4a9191e4ae226fca2a5aa27b5 Mon Sep 17 00:00:00 2001
      From: Bradley Schofield 
      Date: Tue, 15 Aug 2023 10:23:07 +0100
      Subject: [PATCH 070/183] Add NHost and Supabase Docs
      
      ---
       app/views/docs/migration-nhost.phtml    | 88 ++++++++++++++++++++++++
       app/views/docs/migration-supabase.phtml | 91 +++++++++++++++++++++++++
       2 files changed, 179 insertions(+)
      
      diff --git a/app/views/docs/migration-nhost.phtml b/app/views/docs/migration-nhost.phtml
      index e69de29bb..154555757 100644
      --- a/app/views/docs/migration-nhost.phtml
      +++ b/app/views/docs/migration-nhost.phtml
      @@ -0,0 +1,88 @@
      +

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

      + +

      Things to keep in mind

      + +
        +
      1. Appwrite will not charge usage during migrations, but NHost may still incur service charges.
      2. +
      3. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
      4. +
      5. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
      6. +
      + +

      Supported resource types

      + + + + + + + + + + + + + + + + + + + + + +
      UsersDatabasesDocumentsFilesFunctions
      NHost
      + +

      Migrating to Appwrite from NHost

      +

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

      + +
        +
      1. + Create a new project and click on the Migrations tab. +
      2. +
      3. + Click on the Create Migration button and select NHost as your source. +
      4. +
      5. + Enter the credentials following the instructions below and click Next. +
      6. +
      7. + Select the resources you want to migrate and finally click Start migration to begin the migration process. +
      8. +
      + +

      Migrating to Appwrite from NHost

      +

      +

        +
      1. + Enter all the following credentials from your NHost project. +
          +
        • + Region - The region your NHost project is hosted in. This can be found in your NHost project environment variables as NHOST_REGION. +
        • +
        • + Subdomain - The subdomain of your NHost project. This can be found in your NHost project environment variables as NHOST_SUBDOMAIN. +
        • +
        • + Database - The name of your NHost database. This can be found in your NHost project Database settings. +
        • +
        • + Username - The username of your NHost database. This can be found in your NHost project Database settings. +
        • +
        • + Password - The password of your NHost database. You set this when you created your NHost project, if you don't remember it you can reset it from your NHost project Database settings. +
        • +
        • + Admin Secret - The admin secret of your NHost project. This can be found in your NHost project environment variables as NHOST_ADMIN_SECRET. We use this to transfer your NHost Files to Appwrite. +
        • +
        +
      2. +
      +

      \ No newline at end of file diff --git a/app/views/docs/migration-supabase.phtml b/app/views/docs/migration-supabase.phtml index e69de29bb..76f0188c6 100644 --- a/app/views/docs/migration-supabase.phtml +++ b/app/views/docs/migration-supabase.phtml @@ -0,0 +1,91 @@ +

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

      + +

      Things to keep in mind

      + +
        +
      1. Appwrite will not charge usage during migrations, but Supabase may still incur service charges.
      2. +
      3. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
      4. +
      5. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
      6. +
      + +

      Supported resource types

      + + + + + + + + + + + + + + + + + + + + + +
      UsersDatabasesDocumentsFilesFunctions
      Supabase
      + +

      Migrating to Appwrite from Supabase

      +

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

      + +
        +
      1. + Create a new project and click on the Migrations tab. +
      2. +
      3. + Click on the Create Migration button and select Supabase as your source. +
      4. +
      5. + Enter the credentials following the instructions below and click Next. +
      6. +
      7. + Select the resources you want to migrate and finally click Start migration to begin the migration process. +
      8. +
      + +

      Migrating to Appwrite from Supabase

      +

      +

        +
      1. + Enter all the following credentials from your Supabase project. +
          +
        • + Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. +
        • +
        • + Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. +
        • +
        • + Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. +
        • +
        • + Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. +
        • +
        • + Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot it you can reset it within your Database Settings +
        • +
        • + Endpoint - This is the endpoint of your Supabase instance under Project Settings -> API. This is used to migrate your files. +
        • +
        • + API Key - This is the key of your Supabase instance under Project Settings -> API. This is used to migrate your files. Make sure to use the hidden service_role key. +
        • +
        +
      2. +
      +

      \ No newline at end of file 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 071/183] 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 7d7c029dbfc9c1e32743271a70677aeaca73d050 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 14:34:23 +0000 Subject: [PATCH 072/183] update index to have all pages --- app/views/docs/index.phtml | 14 +++++++++++++- app/views/docs/migration.phtml | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 11c8f4882..dac01f024 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -96,7 +96,19 @@ $cols = [
    • Migration + + + +
    diff --git a/app/views/docs/migration.phtml b/app/views/docs/migration.phtml index 542744618..336689026 100644 --- a/app/views/docs/migration.phtml +++ b/app/views/docs/migration.phtml @@ -56,5 +56,6 @@

    Limitations

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

    \ No newline at end of file From fc5ba4004d64e87dcd6f7abb9ac0593942890692 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 15:11:06 +0000 Subject: [PATCH 073/183] Fix ordered list tags and headings --- app/views/docs/migration-nhost.phtml | 54 +++++++++++----------- app/views/docs/migration-supabase.phtml | 61 ++++++++++++------------- 2 files changed, 56 insertions(+), 59 deletions(-) diff --git a/app/views/docs/migration-nhost.phtml b/app/views/docs/migration-nhost.phtml index 154555757..a556de4a0 100644 --- a/app/views/docs/migration-nhost.phtml +++ b/app/views/docs/migration-nhost.phtml @@ -58,31 +58,29 @@ -

    Migrating to Appwrite from NHost

    -

    -

      -
    1. - Enter all the following credentials from your NHost project. -
        -
      • - Region - The region your NHost project is hosted in. This can be found in your NHost project environment variables as NHOST_REGION. -
      • -
      • - Subdomain - The subdomain of your NHost project. This can be found in your NHost project environment variables as NHOST_SUBDOMAIN. -
      • -
      • - Database - The name of your NHost database. This can be found in your NHost project Database settings. -
      • -
      • - Username - The username of your NHost database. This can be found in your NHost project Database settings. -
      • -
      • - Password - The password of your NHost database. You set this when you created your NHost project, if you don't remember it you can reset it from your NHost project Database settings. -
      • -
      • - Admin Secret - The admin secret of your NHost project. This can be found in your NHost project environment variables as NHOST_ADMIN_SECRET. We use this to transfer your NHost Files to Appwrite. -
      • -
      -
    2. -
    -

    \ No newline at end of file +

    NHost Credentials

    +
      +
    1. + Enter all the following credentials from your NHost project. +
        +
      • + Region - The region your NHost project is hosted in. This can be found in your NHost project environment variables as NHOST_REGION. +
      • +
      • + Subdomain - The subdomain of your NHost project. This can be found in your NHost project environment variables as NHOST_SUBDOMAIN. +
      • +
      • + Database - The name of your NHost database. This can be found in your NHost project Database settings. +
      • +
      • + Username - The username of your NHost database. This can be found in your NHost project Database settings. +
      • +
      • + Password - The password of your NHost database. You set this when you created your NHost project, if you don't remember it you can reset it from your NHost project Database settings. +
      • +
      • + Admin Secret - The admin secret of your NHost project. This can be found in your NHost project environment variables as NHOST_ADMIN_SECRET. We use this to transfer your NHost Files to Appwrite. +
      • +
      +
    2. +
    \ No newline at end of file diff --git a/app/views/docs/migration-supabase.phtml b/app/views/docs/migration-supabase.phtml index 76f0188c6..871ca85a9 100644 --- a/app/views/docs/migration-supabase.phtml +++ b/app/views/docs/migration-supabase.phtml @@ -58,34 +58,33 @@ -

    Migrating to Appwrite from Supabase

    -

    -

      -
    1. - Enter all the following credentials from your Supabase project. -
        -
      • - Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. -
      • -
      • - Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. -
      • -
      • - Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. -
      • -
      • - Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. -
      • -
      • - Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot it you can reset it within your Database Settings -
      • -
      • - Endpoint - This is the endpoint of your Supabase instance under Project Settings -> API. This is used to migrate your files. -
      • -
      • - API Key - This is the key of your Supabase instance under Project Settings -> API. This is used to migrate your files. Make sure to use the hidden service_role key. -
      • -
      -
    2. -
    -

    \ No newline at end of file +

    Credentials

    + +
      +
    1. + Enter all the following credentials from your Supabase project. +
        +
      • + Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. +
      • +
      • + Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. +
      • +
      • + Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. +
      • +
      • + Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. +
      • +
      • + Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot it you can reset it within your Database Settings +
      • +
      • + Endpoint - This is the endpoint of your Supabase instance under Project Settings -> API. This is used to migrate your files. +
      • +
      • + API Key - This is the key of your Supabase instance under Project Settings -> API. This is used to migrate your files. Make sure to use the hidden service_role key. +
      • +
      +
    2. +
    From 4b5185846b0041c4fe6aac6d745cafc8e408f290 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 16:03:00 +0000 Subject: [PATCH 074/183] Fix migrations index --- app/views/docs/index.phtml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index dac01f024..c4889dee5 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -97,19 +97,10 @@ $cols = [ Migration - - - - From 3b7d63e33e7a96f9a2aa37268836192af6030742 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 17:24:39 +0000 Subject: [PATCH 075/183] Fix language in migration guides for firebase, supabase, and nhost --- app/views/docs/index.phtml | 12 +-- app/views/docs/migration-supabase.phtml | 90 ------------------- ....phtml => migrations-cloud-to-local.phtml} | 4 +- ...rebase.phtml => migrations-firebase.phtml} | 8 +- ....phtml => migrations-local-to-cloud.phtml} | 2 +- ...ion-nhost.phtml => migrations-nhost.phtml} | 48 +++++----- app/views/docs/migrations-supabase.phtml | 88 ++++++++++++++++++ .../{migration.phtml => migrations.phtml} | 32 +++++-- 8 files changed, 151 insertions(+), 133 deletions(-) delete mode 100644 app/views/docs/migration-supabase.phtml rename app/views/docs/{migration-cloud-to-local.phtml => migrations-cloud-to-local.phtml} (92%) rename app/views/docs/{migration-firebase.phtml => migrations-firebase.phtml} (87%) rename app/views/docs/{migration-local-to-cloud.phtml => migrations-local-to-cloud.phtml} (97%) rename app/views/docs/{migration-nhost.phtml => migrations-nhost.phtml} (56%) create mode 100644 app/views/docs/migrations-supabase.phtml rename app/views/docs/{migration.phtml => migrations.phtml} (52%) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index c4889dee5..125f562c6 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -94,13 +94,13 @@ $cols = [
  • Functions
  • - Migration + Migrations diff --git a/app/views/docs/migration-supabase.phtml b/app/views/docs/migration-supabase.phtml deleted file mode 100644 index 871ca85a9..000000000 --- a/app/views/docs/migration-supabase.phtml +++ /dev/null @@ -1,90 +0,0 @@ -

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

    - -

    Things to keep in mind

    - -
      -
    1. Appwrite will not charge usage during migrations, but Supabase may still incur service charges.
    2. -
    3. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
    4. -
    5. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
    6. -
    - -

    Supported resource types

    - - - - - - - - - - - - - - - - - - - - - -
    UsersDatabasesDocumentsFilesFunctions
    Supabase
    - -

    Migrating to Appwrite from Supabase

    -

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

    - -
      -
    1. - Create a new project and click on the Migrations tab. -
    2. -
    3. - Click on the Create Migration button and select Supabase as your source. -
    4. -
    5. - Enter the credentials following the instructions below and click Next. -
    6. -
    7. - Select the resources you want to migrate and finally click Start migration to begin the migration process. -
    8. -
    - -

    Credentials

    - -
      -
    1. - Enter all the following credentials from your Supabase project. -
        -
      • - Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. -
      • -
      • - Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. -
      • -
      • - Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. -
      • -
      • - Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. -
      • -
      • - Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot it you can reset it within your Database Settings -
      • -
      • - Endpoint - This is the endpoint of your Supabase instance under Project Settings -> API. This is used to migrate your files. -
      • -
      • - API Key - This is the key of your Supabase instance under Project Settings -> API. This is used to migrate your files. Make sure to use the hidden service_role key. -
      • -
      -
    2. -
    diff --git a/app/views/docs/migration-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml similarity index 92% rename from app/views/docs/migration-cloud-to-local.phtml rename to app/views/docs/migrations-cloud-to-local.phtml index 3f601a2ec..801d93c0e 100644 --- a/app/views/docs/migration-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -11,10 +11,10 @@
  • Migrations are non-destructive. No data will be deleted or lost in the source project.
  • -

    Migrating to Self-hosted from Cloud

    +

    Migrating to Self-hosted from Cloud

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

    diff --git a/app/views/docs/migration-firebase.phtml b/app/views/docs/migrations-firebase.phtml similarity index 87% rename from app/views/docs/migration-firebase.phtml rename to app/views/docs/migrations-firebase.phtml index 2d4951cc2..f8c236ea3 100644 --- a/app/views/docs/migration-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -8,10 +8,10 @@

    Things to keep in mind

      -
    1. Appwrite will not charge usage during migrations, but Firebase may still incur service charges.
    2. -
    3. Appwrite migrations only supports Firestore as a database source. Realtime Database is currently not supported.
    4. +
    5. Appwrite will not incur usage charges during migrations, but Firebase may still incur service charges.
    6. +
    7. Appwrite Migrations only supports Firestore as a database source. Realtime Database is currently not supported.
    8. At the moment only top level document migration is supported. Nested documents will not be transferred automatically.
    9. -
    10. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
    11. +
    12. OAuth users will not be transferred. Users will need to re-authenticate with your OAuth provider after the migration is complete.

    Supported resource types

    @@ -40,7 +40,7 @@

    Migrating to Appwrite from Firebase

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

    diff --git a/app/views/docs/migration-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml similarity index 97% rename from app/views/docs/migration-local-to-cloud.phtml rename to app/views/docs/migrations-local-to-cloud.phtml index e30783d4b..3e19aef74 100644 --- a/app/views/docs/migration-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -13,7 +13,7 @@

    Migrating to Self-hosted from Cloud

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

    diff --git a/app/views/docs/migration-nhost.phtml b/app/views/docs/migrations-nhost.phtml similarity index 56% rename from app/views/docs/migration-nhost.phtml rename to app/views/docs/migrations-nhost.phtml index a556de4a0..0d625eb67 100644 --- a/app/views/docs/migration-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -8,7 +8,7 @@

    Things to keep in mind

      -
    1. Appwrite will not charge usage during migrations, but NHost may still incur service charges.
    2. +
    3. Appwrite will not incur usage charges during migrations, but NHost may still incur service charges.
    4. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
    5. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
    @@ -39,7 +39,7 @@

    Migrating to Appwrite from NHost

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

    @@ -59,28 +59,26 @@

    NHost Credentials

    +

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

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

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

    + +

    Things to keep in mind

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

    Supported resource types

    + + + + + + + + + + + + + + + + + + + + + +
    UsersDatabasesDocumentsFilesFunctions
    Supabase
    + +

    Migrating to Appwrite from Supabase

    +

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

    + +
      +
    1. + Create a new project and click on the Migrations tab. +
    2. +
    3. + Click on the Create Migration button and select Supabase as your source. +
    4. +
    5. + Enter the credentials following the instructions below and click Next. +
    6. +
    7. + Select the resources you want to migrate and finally click Start migration to begin the migration process. +
    8. +
    + +

    Credentials

    + +

    Enter all the following credentials from your Supabase project.

    + +
      + +
    1. + Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. +
    2. +
    3. + Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host. +
    4. +
    5. + Port - The port of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Port. By default this is 5432. +
    6. +
    7. + Username - The username of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Username. +
    8. +
    9. + Password - The password of your Supabase Database, this was set when you created your Supabase project. If you forgot your password, you can reset it within Database Settings. +
    10. +
    11. + Endpoint - This is the endpoint of your Supabase instance under Project Settings > API. This is used to migrate your files. +
    12. +
    13. + API Key - This is the key of your Supabase instance under Project Settings > API. This is used to migrate your files. Make sure to use the hidden service_role key. +
    14. +
    diff --git a/app/views/docs/migration.phtml b/app/views/docs/migrations.phtml similarity index 52% rename from app/views/docs/migration.phtml rename to app/views/docs/migrations.phtml index 336689026..d15752efa 100644 --- a/app/views/docs/migration.phtml +++ b/app/views/docs/migrations.phtml @@ -1,6 +1,6 @@

    - Moving your app from another platform to Appwrite? - You can move your app from Firebase, Supabase, NHost, and even other Appwrite projects to another Appwrite project using Migrations. + Ready to migrate your project to Appwrite? + You can move your app from Firebase, Supabase, NHost, and even move between self-hosted and Cloud projects using Migrations. Migrations will automatically move accounts, database documents, and storage files from one source to another.

    @@ -26,7 +26,7 @@ Firebase -

    Migrate from Firebase

    +

    Migrate from Firebase

    @@ -37,7 +37,7 @@ Supabase -

    Migrate from Supabase

    +

    Migrate from Supabase

    @@ -48,7 +48,29 @@ NHost -

    Migrate from NHost

    +

    Migrate from NHost

    + + + + + [IMAGE] + + + Cloud to Self-host + + +

    Migrate from Appwrite Cloud to Self-hosted

    + + + + + [IMAGE] + + + Self-host to Cloud + + +

    Migrate from Self-hosted to Appwrite Cloud

    From 1819b3288c0aff003288fe4d2800b3af035f3a5d Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 17:31:23 +0000 Subject: [PATCH 076/183] Fixed code tags in local to cloud page --- app/views/docs/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index 3e19aef74..5cfee4cb8 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -6,7 +6,7 @@

    Things to keep in mind

      -
    1. Data transferred by migrations will reset `$createdAt` and `$updatedAt` timestamps to the date of the migration.
    2. +
    3. Data transferred by migrations will reset $createdAt and $updatedAt timestamps to the date of the migration.
    4. Your self-hosted Appwrite project must be accessible from the internet for the migration to work.
    5. Migrations are non-destructive. No data will be deleted or lost in the source project.
    From 30bc686cae377cd6597f2cba8125e03bf9ae75ad Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 17:38:51 +0000 Subject: [PATCH 077/183] Fix titles in index --- app/views/docs/index.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 125f562c6..1d45bff57 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -99,8 +99,8 @@ $cols = [
  •    Firebase
  •    Supabase
  •    NHost
  • -
  •    Cloud to Local
  • -
  •    Local to Cloud
  • +
  •    Cloud to Self-hosted
  • +
  •    Self-hosted to Cloud
  • From 1b974feaec94c8022add7e7b7ca3b3b7fccc7fa5 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 15 Aug 2023 17:42:20 +0000 Subject: [PATCH 078/183] Fix missing ul tag in index --- app/views/docs/index.phtml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 1d45bff57..ecab000aa 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -101,6 +101,8 @@ $cols = [
  •    NHost
  •    Cloud to Self-hosted
  •    Self-hosted to Cloud
  • +
  •   Security
  • + 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 079/183] 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 080/183] 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. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableDescription
    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 { - + + + + + + + + + + + + + + + + + + + + + + The runtime version of the running function.
    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
    -

    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 ff3c2b495d35ca89fc2677c9af189421c50897f4 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 17:29:28 +0000 Subject: [PATCH 081/183] Fix web example format, add quickstart to auth --- app/views/docs/authentication-anonymous.phtml | 8 +- .../docs/authentication-email-pass.phtml | 36 +----- app/views/docs/authentication-magic.phtml | 16 +-- .../docs/authentication-management.phtml | 16 +-- app/views/docs/authentication-server.phtml | 8 +- app/views/docs/authentication-sms.phtml | 18 +-- app/views/docs/authentication.phtml | 105 +++++++++++++++++- 7 files changed, 118 insertions(+), 89 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index f0c9b236f..8c6f53929 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -26,13 +26,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createAnonymousSession(); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createAnonymousSession();

  • diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 8e8b5dd39..9ad52be88 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -22,17 +22,11 @@ const client = new Client() const account = new Account(client); -const promise = account.create( +const user = await account.create( ID.unique(), 'email@example.com', 'password' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
  • @@ -181,16 +175,10 @@ const client = new Client() const account = new Account(client); -const promise = account.createEmailSession( +const user = await account.createEmailSession( 'email@example.com', 'password' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
  • @@ -278,13 +266,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createPasswordRecovery('email@example.com', 'https://example.com'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createPasswordRecovery('email@example.com', 'https://example.com');
  • @@ -371,13 +353,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password');
  • diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index d863b7611..f06095ab5 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -23,13 +23,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createMagicURLSession('email@example.com', 'email@example.com'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createMagicURLSession('email@example.com', 'email@example.com');
  • @@ -120,13 +114,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updateMagicURLSession('email@example.com', '[SECRET]'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updateMagicURLSession('email@example.com', '[SECRET]');
  • diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 8f636fcfc..f0c89799e 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -24,13 +24,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updatePrefs({darkTheme: true, language: 'en'}); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updatePrefs({darkTheme: true, language: 'en'});
  • @@ -123,13 +117,7 @@ const client = new Client() const account = new Account(client); -const promise = account.getPrefs(); - -promise.then(function (prefs) { - console.log(prefs); -}, function (error) { - console.log(error); -}); +const user = await account.getPrefs();
  • diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 186b5eb5b..0313c8a11 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -30,13 +30,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createJWT(); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createJWT();
  • diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 49c7c6483..2660ccc4f 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -30,17 +30,11 @@ const client = new Client() const account = new Account(client); -const promise = account.createPhoneSession( +const user = await account.createPhoneSession( ID.unique(), '+14255550123' ); -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); -
  • @@ -128,16 +122,10 @@ const client = new Client() const account = new Account(client); -const promise = account.updatePhoneSession( +const user = await account.updatePhoneSession( '[USER_ID]', '[SECRET]' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -});
    +);
  • diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 7f8755d59..62fcdce3e 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -1,8 +1,109 @@

    Appwrite Authentication delivers more than just user sign up and log in. - Authentication makes it easy to build secure and robust authentication with support for many differnt authentication methods. + Authentication makes it easy to build secure and robust authentication with support for many different authentication methods. +

    + +

    You can manage user accounts with user preferences, user labeling, or organizing users into teams. - Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manager users. + Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manage users. +

    + +

    Getting Started

    +

    + Adding Appwrite Authentication to your apps can be as easy as these lines of code. +

    + +
      +
    • +

      Web

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

      Flutter

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

      Android

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

      Apple

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

      GraphQL

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

    + Use email and password authentication as a starting point and explore the many powerful features of Appwrite authentication.

    Account vs Users API

    From 21431cc4c3d045fa560f2a07e70d3e6b92e29a13 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:30:43 +0000 Subject: [PATCH 082/183] Fix auth index, add users api docs --- .../docs/authentication-management.phtml | 21 ++++++++++++++++++- app/views/docs/authentication.phtml | 6 ++++++ app/views/docs/index.phtml | 6 ++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index f0c89799e..269233007 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -9,7 +9,7 @@ [TODO @steven: Labels docs] -

    User Preferences

    +

    User Preferences

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

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

      @@ -171,3 +171,22 @@ let prefs = try await account.getPrefs()
    + +

    Users API

    +

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

    + +

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

    + +

    + + Learn more about the Users API + +

    \ No newline at end of file diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 62fcdce3e..c2691e24b 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -161,6 +161,12 @@ mutation {

    +

    + + Manage users + +

    +

    Server integrations diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 3554cba88..4643d1aca 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -88,6 +88,12 @@ $cols = [

  • Authentication From 672a6df5bce31bcbba0040384f8103eb0bd0ecc0 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:34:06 +0000 Subject: [PATCH 083/183] Fix auth index display names --- app/views/docs/index.phtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 4643d1aca..48a97c0ff 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -88,13 +88,13 @@ $cols = [
  • Authentication
  • From 8050091707bd0cc36a250c1264e7f1164b29e23b Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:41:57 +0000 Subject: [PATCH 084/183] Maybe it should be user management vs just management --- app/views/docs/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 48a97c0ff..e4f21b661 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -93,7 +93,7 @@ $cols = [
  •   Magic URL
  •   OAuth 2
  •   Anonymous
  • -
  •   Management
  • +
  •   User Management
  •   Server Integrations
  •   Security
  • From e2f493ec3fde149be307a97249b10fd007a6af54 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:59:12 +0000 Subject: [PATCH 085/183] grammar check by GPT --- app/views/docs/authentication-anonymous.phtml | 4 ++-- app/views/docs/authentication-email-pass.phtml | 2 +- app/views/docs/authentication-management.phtml | 2 +- app/views/docs/authentication-security.phtml | 6 +++--- app/views/docs/authentication-server.phtml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 8c6f53929..9848c8097 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -92,7 +92,7 @@ mutation {

    Anonymous users cannot sign back in. If they close their browser, or go to another computer, they won't be able to log in again. - Remeber to prompt the user to create an account to no lose their data. + Remeber to prompt the user to create an account to not lose their data.

    @@ -104,7 +104,7 @@ mutation { Email and password

  • - Phone + Phone (SMS)
  • Magic URL diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 9ad52be88..4cbb7d731 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -433,5 +433,5 @@ let token = try await account.updateRecovery(

    Security

    -[TODO: @steven Talk about the password security features like password dictionary, passowrd history, and prevent personal information.] +[TODO: @steven Talk about the password security features like password dictionary, password history, and prevent personal information.] [Be brief, link to security page for details] \ No newline at end of file diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 269233007..d140e01fd 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -1,5 +1,5 @@

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

    diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 8e98a7b90..153581615 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -10,7 +10,7 @@

    Best Practice

    -

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

    +

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

    @@ -74,7 +74,7 @@

    Session Limits

    -

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

    +

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

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

    @@ -85,7 +85,7 @@

    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 prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password every time it's changed.

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

    diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 0313c8a11..7e54f1d2e 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -12,7 +12,7 @@

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

    JWT Authentication

    -

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

    +

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

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

    @@ -441,7 +441,7 @@ var documentList = await databases.ListDocuments(
  • -

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

    +

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

    {
       "total": 1,
    
    From f1a41d254d810ea2cc192971377ed0b3edc86279 Mon Sep 17 00:00:00 2001
    From: "Vincent (Wen Yu) Ge" 
    Date: Thu, 17 Aug 2023 20:33:20 +0000
    Subject: [PATCH 086/183] Add info about personal information in auth docs
    
    ---
     app/views/docs/authentication-security.phtml | 7 +++++--
     1 file changed, 5 insertions(+), 2 deletions(-)
    
    diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml
    index 153581615..99fd79a21 100644
    --- a/app/views/docs/authentication-security.phtml
    +++ b/app/views/docs/authentication-security.phtml
    @@ -95,5 +95,8 @@
     

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

    Personal Information

    - -[TODO: @steven Talk about new personal information thing.] \ No newline at end of file +

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

    +

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

    From 61be417bb523fd7babbac1042a766f531174173f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 20:34:35 +0000 Subject: [PATCH 087/183] Add more information about password security in Appwrite --- app/views/docs/authentication-email-pass.phtml | 12 ++++++++++-- app/views/docs/authentication-oauth.phtml | 2 +- app/views/docs/authentication-security.phtml | 7 +++++-- app/views/docs/authentication.phtml | 4 ++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 4cbb7d731..119dd9fa0 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -433,5 +433,13 @@ let token = try await account.updateRecovery(

    Security

    -[TODO: @steven Talk about the password security features like password dictionary, password history, and prevent personal information.] -[Be brief, link to security page for details] \ No newline at end of file +

    + Appwrite does more than use secure implementation of email and password authentication on the server-side to ensure security. + You can enable features like password dictionary, password history, and disallow personal information to encourage users to pick better passwords. + By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place. +

    +

    + + Learn more about security features + +

    \ No newline at end of file diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 18f8b69d1..35a6a9305 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -105,7 +105,7 @@ try await account.createOAuth2Session(provider: "amazon")

    OAuth 2 Profile

    - [TODO: @steven fill the docs to access profile information] + [TODO: @steven fill the docs to access oauth account profile information]

    Refresh Tokens

    diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 99fd79a21..776c320d8 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -78,10 +78,13 @@

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

    -

    Security

    +

    Permissions

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

    Password History

    diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index c2691e24b..917c20852 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -162,7 +162,7 @@ mutation {

    - + Manage users

    @@ -174,7 +174,7 @@ mutation {

    - + Security

    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 088/183] 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 089/183] 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 12ebf382ac9054e78bb1f2214f08623f8a862f90 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 13:40:40 +0000 Subject: [PATCH 090/183] Remove Health API temporarily from nav --- app/views/docs/index.phtml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 3554cba88..6d51b1dc3 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -68,7 +68,6 @@ $cols = [
    • Functions
    • Localization
    • Avatars
    • -
    • Health
    From e58af232b8febdaac87b57a52d864294149ba093 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 18 Aug 2023 15:40:40 +0100 Subject: [PATCH 091/183] Improve Examples --- .../docs/authentication-email-pass.phtml | 27 ++++++++++- app/views/docs/authentication-magic.phtml | 8 ++-- app/views/docs/authentication-sms.phtml | 45 ++++++++++--------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 119dd9fa0..1f8b44012 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -154,7 +154,32 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

    -[TODO: @bradley examples to parse query params from page and complete verification] +
      +
    • +

      Web

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

    Log In

    diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index f06095ab5..29fc0fda9 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -100,8 +100,6 @@ let user = try await account.createMagicURLSession( After receiving your secret from an email, you can create a session.

    -[TODO: @bradley, please update the examples below with how to get the secret from the magic URL] -
    • Web

      @@ -114,7 +112,11 @@ const client = new Client() const account = new Account(client); -const user = await account.updateMagicURLSession('email@example.com', '[SECRET]'); +const urlParams = new URLSearchParams(window.location.search); +const secret = urlParams.get('secret'); +const userId = urlParams.get('userId'); + +const user = await account.updateMagicURLSession(userId, secret);
  • diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 2660ccc4f..54aea908e 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -16,8 +16,6 @@ A new account will be created for this phone number if it has never been used before.

    -[TODO: @bradley update these examples to show where the userID comes from (continuity from first request to next)] -
    • Web

      @@ -30,12 +28,12 @@ const client = new Client() const account = new Account(client); -const user = await account.createPhoneSession( +const sessionToken = await account.createPhoneSession( ID.unique(), '+14255550123' ); - +var userId = sessionToken.userId // Store this somewhere to use later when logging in
  • @@ -49,10 +47,12 @@ final client = Client() final account = Account(client); -final session = await account.createPhoneSession( +final sessionToken = await account.createPhoneSession( userId: ID.unique(), phone: '+14255550123' -); +); + +final userId = sessionToken.userId // Store this somewhere to use later when logging in
  • Android

    @@ -67,10 +67,12 @@ val client = Client() val account = Account(client) -val session = account.createPhoneSession( +val sessionToken = account.createPhoneSession( userId = ID.unique(), phone = "+14255550123" -) +) + +val userId = sessionToken.userId // Store this somewhere to use later when logging in
  • Apple

    @@ -83,10 +85,12 @@ let client = Client() let account = Account(client) -let session = try await account.createPhoneSession( +let sessionToken = try await account.createPhoneSession( userId: ID.unique(), phone: "+14255550123" -) +) + +let userId = sessionToken.userId // Store this somewhere to use later when logging in
  • GraphQL

    @@ -122,10 +126,11 @@ const client = new Client() const account = new Account(client); -const user = await account.updatePhoneSession( - '[USER_ID]', - '[SECRET]' -); +const session = await account.updatePhoneSession( + userId, // From when you called createPhoneSession + '[SECRET]' // The 6-digit code from the SMS message +); +
  • @@ -140,8 +145,8 @@ final client = Client() final account = Account(client); final session = await account.updatePhoneSession( - userId: '[USER_ID]', - secret: '[SECRET]' + userId: userId, // From when you called createPhoneSession + secret: '[SECRET]' // The 6-digit code from the SMS message );
  • @@ -158,8 +163,8 @@ val client = Client() val account = Account(client) val session = account.updatePhoneSession( - userId = "[USER_ID]", - secret = "[SECRET]" + userId = userId, // From when you called createPhoneSession + secret = "[SECRET]" // The 6-digit code from the SMS message )
  • @@ -174,8 +179,8 @@ let client = Client() let account = Account(client) let session = try await account.updatePhoneSession( - userId: "[USER_ID]", - secret: "[SECRET]" + userId: userId, // From when you called createPhoneSession + secret: "[SECRET]" // The 6-digit code from the SMS message )
  • 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 092/183] 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 9921120e973274909378003eeb465be62088de6d Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 16:44:03 +0000 Subject: [PATCH 093/183] user management docs --- .../docs/authentication-management.phtml | 209 +++++++++++++++++- 1 file changed, 204 insertions(+), 5 deletions(-) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index d140e01fd..83d284fc5 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -4,10 +4,6 @@ Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

    -[TODO @steven: TEAMS docs] - -[TODO @steven: Labels docs] -

    User Preferences

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

    @@ -189,4 +185,207 @@ let prefs = try await account.getPrefs() Learn more about the Users API -

    \ No newline at end of file +

    + +

    Labels

    +

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

    + +
      +
    • +

      Node.js

      +
      +
      const sdk = require('node-appwrite');
      +
      +const client = new sdk.Client();
      +
      +const users = new sdk.Users(client);
      +
      +let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
      +
      +
    • +
    • +

      PHP

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

      Python

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

      Ruby

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

      Deno

      +
      +
      import * as sdk from "https://deno.land/x/appwrite/mod.ts";
      +
      +// Init SDK
      +let client = new sdk.Client();
      +
      +let users = new sdk.Users(client);
      +
      +client
      +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      +    .setProject('5df5acd0d48c2') // Your project ID
      +    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
      +;
      +
      +
      +let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
      +
      +
    • +
    • +

      Dart

      +
      +
      import 'package:dart_appwrite/dart_appwrite.dart';
      +
      +void main() { // Init SDK
      +  Client client = Client();
      +  Users users = Users(client);
      +
      +  client
      +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
      +    .setProject('5df5acd0d48c2') // Your project ID
      +    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
      +  ;
      +
      +  Future result = users.updateLabels(
      +    userId: '[USER_ID]',
      +    labels: [ Role.label('subscriber') ],
      +  );
      +
      +  result
      +    .then((response) {
      +      print(response);
      +    }).catchError((error) {
      +      print(error.response);
      +  });
      +}
      +
      +
    • +
    • +

      Kotlin

      +
      +
      import io.appwrite.Client
      +import io.appwrite.services.Users
      +import io.appwrite.Role
      +
      +suspend fun main() {
      +    val client = Client(context)
      +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
      +      .setProject("5df5acd0d48c2") // Your project ID
      +      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
      +
      +    val users = Users(client)
      +    val response = users.updateLabels(
      +        userId = "[USER_ID]",
      +        labels = [ Role.label('subscriber') ]
      +    )
      +    val json = response.body?.string()
      +}
      +
      +
    • +
    • +

      Swift

      +
      +
      import Appwrite
      +
      +func main() async throws {
      +    let client = Client()
      +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
      +      .setProject("5df5acd0d48c2") // Your project ID
      +      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
      +    let users = Users(client)
      +    let response = try await users.updateLabels(
      +        userId: "[USER_ID]",
      +        labels: [ Role.label('subscriber') ]
      +    )
      +
      +    print(String(describing: response)
      +}
      +
      +
    • +
    • +

      .NET

      +
      +
      +
      +
    • +
    + +

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

    + + +

    +

  • Learn more about permissions
  • +

    + +

    Teams

    +

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

    + +

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

    From 36a5b6b548062f44f24638d04fb269ff04017d06 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 18:32:45 +0000 Subject: [PATCH 094/183] OAuth docs additions with steven's comments --- app/views/docs/authentication-oauth.phtml | 120 +++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 35a6a9305..c75c2f9e8 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -105,7 +105,125 @@ try await account.createOAuth2Session(provider: "amazon")

    OAuth 2 Profile

    - [TODO: @steven fill the docs to access oauth account profile information] +After authenticating a user through their OAuth2 provider, you can fetch their profile information such as their avatar image or name. +To do this you can use the access token from the OAuth2 provider and make API calls to the provider. +

    + +

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

    + +
      +
    • +

      Web

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

      Flutter

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

      Android

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

      Apple

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

    + An OAuth2 session will have the following attributes. +

    + + + + + + + + + + + + + + + + + + + + + + +
    propertyDescription
    providerThe OAuth2 Provider.
    providerUid User ID from the OAuth2 Provider.
    provderAccessTokenAccess token from the OAuth2 provider. Use this to make requests to the OAuth2 provider to fetch personal information.
    + +

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

    Refresh Tokens

    From a5b28d62648897542700a4abcec362d854c9f17f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 20:17:28 +0000 Subject: [PATCH 095/183] ChatGPT grammar check --- app/views/docs/authentication-anonymous.phtml | 31 ++-- .../docs/authentication-email-pass.phtml | 4 +- app/views/docs/authentication-magic.phtml | 20 ++- .../docs/authentication-management.phtml | 12 +- app/views/docs/authentication-oauth.phtml | 42 ++--- app/views/docs/authentication-server.phtml | 146 +++++++++--------- app/views/docs/authentication-sms.phtml | 6 +- app/views/docs/authentication.phtml | 4 +- 8 files changed, 137 insertions(+), 128 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 9848c8097..e9a73943a 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -5,7 +5,7 @@

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

    Create Anonymous Session

    @@ -92,24 +92,23 @@ mutation {

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

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

    -
      -
    1. - Email and password -
    2. -
    3. - Phone (SMS) -
    4. -
    5. - Magic URL -
    6. -
    7. - OAuth2 -
    8. -
    \ No newline at end of file + +

    +Email and password +

    +

    +Phone (SMS) +

    +

    +Magic URL +

    +

    +OAuth2 +

    diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 1f8b44012..31a4b5580 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -363,7 +363,7 @@ let token = try await account.createRecovery(

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

      @@ -459,7 +459,7 @@ let token = try await account.updateRecovery(

      Security

      - Appwrite does more than use secure implementation of email and password authentication on the server-side to ensure security. + Appwrite's security first mindset goes beyond a securely implementated of authentication API. You can enable features like password dictionary, password history, and disallow personal information to encourage users to pick better passwords. By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place.

      diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 29fc0fda9..d5aeb16f4 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -1,14 +1,15 @@

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

      Send Email

      Initialize the log in process with the Create Magic URL Session route. - We recommend you use the user's email as their user ID instead of a random ID. - This way, you will only need an email, and not an ID to log in the user. + If the email has never been used, a new user ID is generated, then the user will receive an email. + If the email is already attached to an account, the user ID is ignored and the user will receive a link in their email.

        @@ -23,7 +24,10 @@ const client = new Client() const account = new Account(client); -const user = await account.createMagicURLSession('email@example.com', 'email@example.com'); +const user = await account.createMagicURLSession( + ID.unique(), + 'email@example.com' + );
      • @@ -33,12 +37,12 @@ const user = await account.createMagicURLSession('email@example.com', 'email@exa final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); final user = await account.createMagicURLSession( - userId: 'email@example.com', + userId: ID.unique(), email: 'email@example.com', );
      • @@ -55,7 +59,7 @@ val client = Client(context) val account = Account(client) val user = account.createMagicURLSession( - userId = 'email@example.com', + userId = ID.unique(), email = "email@example.com" ) @@ -71,7 +75,7 @@ let client = Client() let account = Account(client) let user = try await account.createMagicURLSession( - userId: 'email@example.com', + userId: ID.unique(), email: "email@example.com" ) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 83d284fc5..4e3514b27 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -6,8 +6,14 @@

        User Preferences

        -

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

        -

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

        +

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

        +

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

        • Web

          @@ -376,7 +382,7 @@ func main() async throws {

          -

        • Learn more about permissions
        • + Learn more about permissions

          Teams

          diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index c75c2f9e8..dc99af316 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -6,26 +6,26 @@

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

          -

          Configure OAuth2 Login

          +

          Configure OAuth 2 Login

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

          1. Navigate to your Appwrite project
          2. Navigate to Auth > Settings
          3. Find and open the OAuth provider.
          4. -
          5. In the OAuth2 settings modal, use the toggle to enable the provider
          6. +
          7. In the OAuth 2 settings modal, use the toggle to enable the provider
          -

          Initialize OAuth2 Login

          +

          Initialize OAuth 2 Login

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

            @@ -105,12 +105,12 @@ try await account.createOAuth2Session(provider: "amazon")

            OAuth 2 Profile

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

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

              @@ -128,7 +128,7 @@ const session = account.getSession('current'); // Provider information console.log(session.provider); console.log(session.providerUid); -console.log(session.provderAccessToken); +console.log(session.providerAccessToken);
            • @@ -149,7 +149,7 @@ final session = await getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);
            • Android

              @@ -170,7 +170,7 @@ val response = account.getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);
            • Apple

              @@ -190,12 +190,12 @@ let session = try await account.getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);

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

            @@ -212,24 +212,24 @@ print(session.provderAccessToken); - + - - + +
            providerUid User ID from the OAuth2 Provider. User ID from the OAuth 2 Provider.
            provderAccessTokenAccess token from the OAuth2 provider. Use this to make requests to the OAuth2 provider to fetch personal information.providerAccessTokenAccess token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal information.

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

            Refresh Tokens

            - OAuth2 sessions expire to protect from security risks. - This means, OAuth2 sessions should be refreshed to keep the user authenticated. + OAuth 2 sessions expire to protect from security risks. + OAuth 2 sessions should be periodically refreshed to keep the user authenticated. You can do this by calling the Update OAuth Session endpoint when ever your user visits your app.

            diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 7e54f1d2e..de1c90211 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -7,7 +7,7 @@

            Proof of Identity

            -

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

            +

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

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

            @@ -26,7 +26,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -40,7 +40,7 @@ const user = await account.createJWT(); final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -56,7 +56,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -69,7 +69,7 @@ val jwt = account.createJWT() let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -99,8 +99,8 @@ const client = new Client(); client .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -113,8 +113,8 @@ $client = new Client(); $client ->setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('[PROJECT_ID]') // Your project ID - ->setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + ->setProject('[PROJECT_ID]') // Your project ID + ->setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -125,9 +125,9 @@ $client client = Client() (client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token )
          • @@ -141,9 +141,9 @@ include Appwrite client = Client.new client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token
          • @@ -154,9 +154,9 @@ client let client = new Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -167,9 +167,9 @@ client final client = Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -180,9 +180,9 @@ client val client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
          • @@ -193,9 +193,9 @@ client let client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
          • @@ -206,9 +206,9 @@ client var client = new Client(); client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("[PROJECT_ID]") // Your project ID - .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token
          @@ -343,9 +343,9 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35 let client = new Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token let databases = new sdk.Databases(client); @@ -361,9 +361,9 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a final client = Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token Databases databases = Databases(client); @@ -382,9 +382,9 @@ Future result = databases.listDocuments( val client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token val databases = Databases(client) @@ -403,9 +403,9 @@ val response = databases.listDocuments( let client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token let databases = Databases(client) @@ -426,9 +426,9 @@ using Appwrite.Models; var client = new Client(); client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("[PROJECT_ID]") // Your project ID - .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token var databases = new Databases(client); @@ -461,7 +461,7 @@ var documentList = await databases.ListDocuments( } -

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

          +

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

          • Node.js

            @@ -471,9 +471,9 @@ var documentList = await databases.ListDocuments( const client = new Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key const databases = new sdk.Databases(client); @@ -490,9 +490,9 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592 $client = new Client(); $client - ->setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('[PROJECT_ID]') // Your project ID - ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ->setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('[PROJECT_ID]') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key $databases = new Databases($client); @@ -508,9 +508,9 @@ $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1 client = Client() (client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key ) databases = Databases(client) @@ -529,9 +529,9 @@ include Appwrite client = Client client.new - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key databases = Databases.new(client) @@ -547,9 +547,9 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35 let client = new Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key let databases = new sdk.Databases(client); @@ -565,9 +565,9 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a final client = Client(); client - .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]') // Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key Databases databases = Databases(client); @@ -586,9 +586,9 @@ Future result = databases.listDocuments( val client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key val databases = Databases(client) @@ -607,9 +607,9 @@ val response = databases.listDocuments( let client = Client() client - .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID - .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key let databases = Databases(client) @@ -630,9 +630,9 @@ using Appwrite.Models; var client = new Client(); client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("[PROJECT_ID]") // Your project ID - .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key var databases = new Databases(client); diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 54aea908e..8e03e7880 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -33,7 +33,7 @@ const sessionToken = await account.createPhoneSession( '+14255550123' ); -var userId = sessionToken.userId // Store this somewhere to use later when logging in +var userId = sessionToken.userId; // Store this somewhere to use later when logging in
          • @@ -52,7 +52,7 @@ final sessionToken = await account.createPhoneSession( phone: '+14255550123' ); -final userId = sessionToken.userId // Store this somewhere to use later when logging in +final userId = sessionToken.userId; // Store this somewhere to use later when logging in
          • Android

            @@ -110,7 +110,7 @@ let userId = sessionToken.userId // Store this somewhere to use later when loggi

            Log In

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

            diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 917c20852..bade8dfc9 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -125,7 +125,7 @@ mutation { Use the Users API when acting as an administrator in use cases like building admin consoles or server integrations. The Users API uses API keys to authenticate, which means Appwrite only knows which API key is accessing data. API keys don't respect permissions, which means they can access all data, and should never be shared with end users in client applications. - The Users API also has batch operations, letting your query and manage users from an admin's perspective. + The Users API also has batch operations, letting you query and manage users from an admin's perspective.

            Explore

            @@ -177,4 +177,4 @@ mutation { Security -

            +

            \ No newline at end of file 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 096/183] 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 @@

              -
            1. 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.
            2. -
            3. After a function is invoked, Appwrite passes request information to your function's executor.
            4. -
            5. The executor runs the function code you deployed and waits for it to return.
            6. -
            7. Function terminates either when the user returns with a method from res, when the user code throws an exception, or times out.
            8. +
            9. The function is invoked.
            10. +
            11. Appwrite passes in request information like headers and environment variables through the context.req object.
            12. +
            13. The runtime executes the code you defined, you can log through the context.log or context.error methods.
            14. +
            15. 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.

            1. In Appwrite Console, navigate to Functions.
            2. @@ -1075,10 +1357,10 @@ namespace runtime {
            3. 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.

            1. In Appwrite Console, navigate to your project's Settings page.
            2. @@ -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 47dd97178925e79f9f2c2a6a37d589fa3f40cf84 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 21 Aug 2023 21:19:22 +0000 Subject: [PATCH 097/183] Where applicable, prefer promises because it's copyable. --- app/views/docs/authentication-anonymous.phtml | 8 +- .../docs/authentication-email-pass.phtml | 215 ++++++++++++++++-- app/views/docs/authentication-magic.phtml | 12 +- app/views/docs/authentication-oauth.phtml | 76 ++++--- app/views/docs/authentication.phtml | 2 +- 5 files changed, 254 insertions(+), 59 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index e9a73943a..4992ebe29 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -26,7 +26,13 @@ const client = new Client() const account = new Account(client); -const user = await account.createAnonymousSession();
          +const promise = account.createAnonymousSession(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 31a4b5580..d5f77c4ed 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -22,11 +22,13 @@ const client = new Client() const account = new Account(client); -const user = await account.create( - ID.unique(), - 'email@example.com', - 'password' -); +const promise = account.create('[USER_ID]', 'email@example.com', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -120,30 +122,114 @@ mutation {
        • Web

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

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

          -
          +
          import androidx.appcompat.app.AppCompatActivity
          +import android.os.Bundle
          +import kotlinx.coroutines.GlobalScope
          +import kotlinx.coroutines.launch
          +import io.appwrite.Client
          +import io.appwrite.services.Account
          +
          +class MainActivity : AppCompatActivity() {
          +    override fun onCreate(savedInstanceState: Bundle?) {
          +        super.onCreate(savedInstanceState)
          +        setContentView(R.layout.activity_main)
          +
          +        val client = Client(applicationContext)
          +            .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
          +            .setProject("5df5acd0d48c2") // Your project ID
          +
          +        val account = Account(client)
          +
          +        GlobalScope.launch {
          +            val response = account.createVerification(
          +                url = "https://example.com"
          +            )
          +            val json = response.body?.string()        
          +        }
          +    }
          +}
        • Apple

          -
          +
          import Appwrite
          +
          +func main() async throws {
          +    let client = Client()
          +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
          +      .setProject("5df5acd0d48c2") // Your project ID
          +    let account = Account(client)
          +    let token = try await account.createVerification(
          +        url: "https://example.com"
          +    )
          +
          +    print(String(describing: token)
          +}
        • GraphQL

          -
          +
          mutation {
          +    accountCreateVerification(
          +        url: "https://example.com"
          +    ) {
          +        _id
          +        _createdAt
          +        userId
          +        secret
          +        expire
          +    }
          +}
        @@ -154,6 +240,10 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

        +

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

        +
        • Web

          @@ -178,6 +268,84 @@ promise.then(function (response) { console.log(error); }); +
        • +
        • +

          Flutter

          +
          +
          import 'package:appwrite/appwrite.dart';
          +
          +void main() { // Init SDK
          +  Client client = Client();
          +  Account account = Account(client);
          +
          +  client
          +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
          +    .setProject('5df5acd0d48c2') // Your project ID
          +  ;
          +  Future result = account.updateVerification(
          +    userId: '[USER_ID]',
          +    secret: '[SECRET]',
          +  );
          +
          +  result
          +    .then((response) {
          +      print(response);
          +    }).catchError((error) {
          +      print(error.response);
          +  });
          +}
          +
        • +
        • +

          Android

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

          Apple

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

          GraphQL

          +
          +
          mutation {
          +    accountUpdateVerification(
          +        userId: "[USER_ID]",
          +        secret: "[SECRET]"
          +    ) {
          +        _id
          +        _createdAt
          +        userId
          +        secret
          +        expire
          +    }
          +}
          +
        @@ -200,10 +368,13 @@ const client = new Client() const account = new Account(client); -const user = await account.createEmailSession( - 'email@example.com', - 'password' -); +const promise = account.createEmailSession('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
      • @@ -289,9 +460,13 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint .setProject('[PROJECT_ID]'); // Your project ID -const account = new Account(client); +const promise = account.createRecovery('email@example.com', 'https://example.com'); -const user = await account.createPasswordRecovery('email@example.com', 'https://example.com'); +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
      • @@ -376,9 +551,13 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint .setProject('[PROJECT_ID]'); // Your project ID -const account = new Account(client); +const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); -const user = await account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
      • diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index d5aeb16f4..e50694877 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -24,10 +24,14 @@ const client = new Client() const account = new Account(client); -const user = await account.createMagicURLSession( - ID.unique(), - 'email@example.com' - ); + +const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
      • diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index dc99af316..e136c6af7 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -123,7 +123,7 @@ const client = new Client(); const account = new Account(client); -const session = account.getSession('current'); +const session = await account.getSession('current'); // Provider information console.log(session.provider); @@ -237,38 +237,38 @@ print(session.providerAccessToken);
      • Web

        -
        import { Client, Account } from "appwrite";
        -
        -const client = new Client();
        -
        -const account = new Account(client);
        -
        -client
        -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        -    .setProject('[PROJECT_ID]')                  // Your Project ID
        -;
        +        
        const promise = account.updateSession('[SESSION_ID]');
         
        -// Go to Amazon OAuth login page
        -account.createOAuth2Session('amazon', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]');
        +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 = new Client();
        -    final account = new Account(client);
        -    
        -    client
        -        .setEndpoint('https://cloud.appwrite.io/v1') // YOUR API Endpoint
        -        .setProject('[PROJECT_ID]')                  // YOUR PROJECT ID
        -    ;
        -    
        -    // OAuth Login, for simplest implementation you can leave both success and
        -    // failure link empty so that Appwrite handles everything.
        -    await account.createOAuth2Session(provider: 'amazon');
        -        
        +
        +void main() { // Init SDK
        +  Client client = Client();
        +  Account account = Account(client);
        +
        +  client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2') // Your project ID
        +  ;
        +  Future result = account.updateSession(
        +    sessionId: '[SESSION_ID]',
        +  );
        +
        +  result
        +    .then((response) {
        +      print(response);
        +    }).catchError((error) {
        +      print(error.response);
        +  });
         }
      • @@ -280,23 +280,29 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your Project ID + .setProject("5df5acd0d48c2") // Your project ID val account = Account(client) -account.createOAuth2Session(provider = "amazon") +val response = account.updateSession( + sessionId = "[SESSION_ID]" +)
      • Apple

        -
        func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
        -    guard let url = URLContexts.first?.url,
        -        url.absoluteString.contains("appwrite-callback") else {
        -        return
        -    }
        -    WebAuthComponent.handleIncomingCookie(from: url)
        -}
        +
        import Appwrite
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("5df5acd0d48c2") // Your project ID
        +
        +let account = Account(client)
        +
        +let session = try await account.updateSession(
        +    sessionId: "[SESSION_ID]"
        +)
      • diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index bade8dfc9..05e44aa9c 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -145,7 +145,7 @@ mutation {

        - Log in with magic URL + Log in with Magic URL

        From fd8e391036e205072c17c7dce011b67eb5653815 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 22 Aug 2023 22:25:10 +0000 Subject: [PATCH 098/183] Don't use images and emojis for Appwrite migration docs --- app/views/docs/index.phtml | 1 - app/views/docs/migrations-firebase.phtml | 10 +++++----- app/views/docs/migrations-nhost.phtml | 10 +++++----- app/views/docs/migrations-supabase.phtml | 10 +++++----- app/views/docs/migrations.phtml | 16 ---------------- 5 files changed, 15 insertions(+), 32 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index ecab000aa..ec9819fbf 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -101,7 +101,6 @@ $cols = [
      •    NHost
      •    Cloud to Self-hosted
      •    Self-hosted to Cloud
      • -
      •   Security
    diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index f8c236ea3..0aacc6bc0 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -29,11 +29,11 @@ Firebase - ✅ - ✅ - ✅ - ✅ - + supported + supported + supported + supported + not supported diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml index 0d625eb67..e6c84a22b 100644 --- a/app/views/docs/migrations-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -28,11 +28,11 @@ NHost - ✅ - ✅ - ✅ - ✅ - + supported + supported + supported + supported + not supported diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index 58036bc5e..02b0bb132 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -28,11 +28,11 @@ Supabase - ✅ - ✅ - ✅ - ✅ - + supported + supported + supported + supported + not supported diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index d15752efa..53dc3eae5 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -12,16 +12,12 @@ - - @@ -30,9 +26,6 @@ - @@ -41,9 +34,6 @@ - @@ -52,9 +42,6 @@ - @@ -63,9 +50,6 @@ - From e6f2aace423816b64e0f0bafa050a9dd82ef8f6f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 22 Aug 2023 22:49:21 +0000 Subject: [PATCH 099/183] Reformat support table to be in overview --- app/views/docs/migrations-firebase.phtml | 24 --------- app/views/docs/migrations-nhost.phtml | 24 --------- app/views/docs/migrations-supabase.phtml | 24 --------- app/views/docs/migrations.phtml | 65 +++++++++++++++--------- 4 files changed, 42 insertions(+), 95 deletions(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index 0aacc6bc0..a8fdc3fed 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -14,30 +14,6 @@
  • OAuth users will not be transferred. Users will need to re-authenticate with your OAuth provider after the migration is complete.
  • -

    Supported resource types

    -
    Source
    - [IMAGE] - Firebase
    - [IMAGE] - Supabase
    - [IMAGE] - NHost
    - [IMAGE] - Cloud to Self-host
    - [IMAGE] - Self-host to Cloud
    - - - - - - - - - - - - - - - - - - - - -
    UsersDatabasesDocumentsFilesFunctions
    Firebasesupportedsupportedsupportedsupportednot supported
    -

    Migrating to Appwrite from Firebase

    To begin migrating to Appwrite make sure to read the migration overview diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml index e6c84a22b..ca9aed1d5 100644 --- a/app/views/docs/migrations-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -13,30 +13,6 @@

  • OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
  • -

    Supported resource types

    - - - - - - - - - - - - - - - - - - - - - -
    UsersDatabasesDocumentsFilesFunctions
    NHostsupportedsupportedsupportedsupportednot supported
    -

    Migrating to Appwrite from NHost

    To begin migrating to Appwrite make sure to read the migration overview diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index 02b0bb132..754445ad0 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -13,30 +13,6 @@

  • OAuth users will not be transferred. Users will need to re-authenticate with your OAuth provider after the migration is complete.
  • -

    Supported resource types

    - - - - - - - - - - - - - - - - - - - - - -
    UsersDatabasesDocumentsFilesFunctions
    Supabasesupportedsupportedsupportedsupportednot supported
    -

    Migrating to Appwrite from Supabase

    To begin migrating to Appwrite make sure to read the migration overview diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index 53dc3eae5..a42226e95 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -1,5 +1,5 @@

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

    @@ -12,50 +12,64 @@ - - + + + + + + - + + + + + - + + + + + - + + + + + - + + + + + - + + + + +
    SourceSourceUsersDatabasesDocumentsFilesFunctions
    - Firebase - -

    Migrate from Firebase

    +

    Firebase

    supportedsupportedpartialsupported
    - Supabase - -

    Migrate from Supabase

    +

    Supabase

    supportedsupportedpartialsupported
    - NHost - -

    Migrate from NHost

    +

    NHost

    supportedsupportedpartialsupported
    - Cloud to Self-host - -

    Migrate from Appwrite Cloud to Self-hosted

    +

    Cloud to Self-hosted

    supportedsupportedsupportedsupportedsupported
    - Self-host to Cloud - -

    Migrate from Self-hosted to Appwrite Cloud

    +

    Self-hosted to Cloud

    supportedsupportedsupportedsupportedsupported
    @@ -64,4 +78,9 @@

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

    + +

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

    \ No newline at end of file From 7de3dd7d998566362a46afa9c1a8a81255ac48a6 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 22 Aug 2023 22:50:11 +0000 Subject: [PATCH 100/183] Instead of not support, call it manual --- app/views/docs/migrations.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index a42226e95..e5469750d 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -29,7 +29,7 @@ supported partial supported - + manual @@ -39,7 +39,7 @@ supported partial supported - + manual @@ -49,7 +49,7 @@ supported partial supported - + manual From 1d465e5fec72f39f457748d8e963f6d6d4134226 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 22 Aug 2023 22:54:02 +0000 Subject: [PATCH 101/183] Change partial to yellow --- app/views/docs/migrations.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index e5469750d..d51e3709f 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -27,7 +27,7 @@ supported supported - partial + partial supported manual @@ -37,7 +37,7 @@ supported supported - partial + partial supported manual @@ -47,7 +47,7 @@ supported supported - partial + partial supported manual From 7d01bd477acbb8dfdca04fade1d8acb779af81cc Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:34:39 +0000 Subject: [PATCH 102/183] Personal Information -> Data --- app/views/docs/authentication-email-pass.phtml | 2 +- app/views/docs/authentication-oauth.phtml | 2 +- app/views/docs/authentication-security.phtml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index d5f77c4ed..8fde1db9a 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -639,7 +639,7 @@ let token = try await account.updateRecovery(

    Security

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

    diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index e136c6af7..2d87b8f7b 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -216,7 +216,7 @@ print(session.providerAccessToken); providerAccessToken - Access token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal information. + Access token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal data. diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 776c320d8..9bae92804 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -97,9 +97,9 @@

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

    -

    Personal Information

    +

    Personal Data

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

    -

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

    +

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

    From cda41f592d8cfbc5b83243a93335cdefe536af61 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:52:59 +0000 Subject: [PATCH 103/183] address OAuth2 issues like redirect --- app/views/docs/authentication-oauth.phtml | 58 ++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 2d87b8f7b..c1ab9671c 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -41,7 +41,7 @@ const client = new Client() const account = new Account(client); // Go to OAuth provider login page -account.createOAuth2Session('amazon'); +account.createOAuth2Session('amazon', [LINK_ON_SUCCESS], [LINK_ON_FAILURE]);
  • @@ -61,6 +61,26 @@ await account.createOAuth2Session(provider: 'amazon');
  • Android

    +

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

    + +
    +
    escape('
    +  ...
    +  
    +    ...
    +    
    +    
    +      
    +        
    +        
    +        
    +        
    +      
    +    
    +  
    +'); ?>
    +
    +
    import io.appwrite.Client
     import io.appwrite.services.Account
    @@ -77,6 +97,38 @@ account.createOAuth2Session(provider = "amazon")
  • Apple

    +

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

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

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

    + +
    +
    escape('
    +func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
    +    guard let url = URLContexts.first?.url,
    +        url.absoluteString.contains("appwrite-callback") else {
    +        return
    +    }
    +    WebAuthComponent.handleIncomingCookie(from: url)
    +}
    +');?>
    +
    import Appwrite
     
    @@ -103,6 +155,10 @@ try await account.createOAuth2Session(provider: "amazon")
    Once complete, you'll be redirected to the redirect URL configured in your OAuth 2 provider.

    +

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

    +

    OAuth 2 Profile

    After authenticating a user through their OAuth 2 provider, you can fetch their profile information such as their avatar image or name. From a4eac315c321292cceabb71a5a15a117e85b7fe7 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:57:40 +0000 Subject: [PATCH 104/183] improve getting started guide because we should --- app/views/docs/authentication-oauth.phtml | 6 +++--- app/views/docs/getting-started-for-android.phtml | 2 +- app/views/docs/getting-started-for-apple.phtml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index c1ab9671c..0a3ec4854 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -61,7 +61,7 @@ await account.createOAuth2Session(provider: 'amazon');

  • Android

    -

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

    +

    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('
    @@ -97,7 +97,7 @@ account.createOAuth2Session(provider = "amazon")
  • Apple

    -

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

    +

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

    escape('CFBundleURLTypes
    @@ -116,7 +116,7 @@ account.createOAuth2Session(provider = "amazon")
    ');?>
    -

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

    +

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

    escape('
    diff --git a/app/views/docs/getting-started-for-android.phtml b/app/views/docs/getting-started-for-android.phtml
    index 74d35cbf0..c410e4caa 100644
    --- a/app/views/docs/getting-started-for-android.phtml
    +++ b/app/views/docs/getting-started-for-android.phtml
    @@ -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..2e71911d9 100644
    --- a/app/views/docs/getting-started-for-apple.phtml
    +++ b/app/views/docs/getting-started-for-apple.phtml
    @@ -64,7 +64,7 @@ $appleVersion = $versions['apple'] ?? '';
     
     

    OAuth Callback

    -

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

    +

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

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

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

    +

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

    escape('
    
    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 105/183] 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 106/183] 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.

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

    Response

    +

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

    +
    • Node.js

      -
      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 107/183] 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. +

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

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

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

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

    \ 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 108/183] 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 99c3600dba5c0a864c67f9f10d8327b9f0b29c12 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 19:19:20 +0000 Subject: [PATCH 109/183] Add locale examples --- app/views/docs/email-and-sms-templates.phtml | 165 +++++++++++++++++-- 1 file changed, 148 insertions(+), 17 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 7511ce244..d0b0fc21d 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -91,7 +91,56 @@

    Email Template Examples

    -[TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)] +

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

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

    SMS Templates

    You can customize the SMS emplates used for phone verification and login.

    @@ -123,27 +172,109 @@ - {{project}} - The project name. - - - {{team}} - Thee project team's name. - - - {{user}} - The name of the uer receiving the email. - - - {{passcode}} + {{token}} The secret code sent to users for phone verification or authentication.

    SMS Template Examples

    -[TODO: @dlohani once we're ready, let's do examples for each type of template (maybe also what it would look like rendered)] +

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

    +
    +
    Your account verification code is {{token}}
    +
    +

    Localization

    -

    You can configure localization by settling locale with client.setLocale in the SDKs or the X-Appwrite-Locale HTTP header.

    -[TODO: @dlohani Maybe example of a template in two languages? (maybe also what it would look like rendered)] +

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

    + +

    + You can send messages in different localizations by settling locale with client.setLocale() in the SDKs or the X-Appwrite-Locale HTTP header. +

    + +

    For example, you can send a phone verification in French.

    +
      +
    • +

      Web

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

      Flutter

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

      Android

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

      Apple

      +
      +
      import Appwrite
      +
      +let client = Client()
      +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
      +    .setProject("5df5acd0d48c2")                 // Your project ID
      +    .setLocale('fr')                             // Your locale
      +
      +let account = Account(client)
      +
      +let token = try await account.createPhoneVerification()
      +
      +
    • +
    \ No newline at end of file From 82fe4846541d966b370d1234cfb931138d95684f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 19:28:06 +0000 Subject: [PATCH 110/183] chat GPT helps me spell! --- app/views/docs/email-and-sms-templates.phtml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index d0b0fc21d..1d4ec7c15 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -27,7 +27,7 @@
  • Update the email template fields and click **Update** to save your changes.
  • Email Templates

    -

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

    +

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

    Email Template Components

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

    @@ -44,11 +44,11 @@ - + - + @@ -77,7 +77,7 @@ - + @@ -104,7 +104,7 @@ <body style="direction: ltr"> -<div style="max-width:650px; word-wrap: break-wrod; overflow-wrap: break-word; +<div style="max-width:650px; word-wrap: break-word; overflow-wrap: break-word; word-break: break-all; margin:0 auto;"> <table style="margin-top: 32px"> <tr> @@ -143,7 +143,7 @@

    SMS Templates

    -

    You can customize the SMS emplates used for phone verification and login.

    +

    You can customize the SMS templates used for phone verification and login.

    SMS Template Components

    Sender emailReaders will see this as the displayed email of the sender. This must be a valid email for the SMTP provider your configured.Readers will see this as the displayed email of the sender. This must be a valid email for the SMTP provider you've configured.
    Reply toReaders will reply to this email adress instead of the sender address. You can leave this field empty if unused.Readers will reply to this email address instead of the sender address. You can leave this field empty if unused.
    Subject
    {{team}}Thee project team's name.The project team's name.
    {{user}}
    @@ -184,15 +184,15 @@
    Your account verification code is {{token}}
    +

    Localization

    -

    Localization

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

    - You can send messages in different localizations by settling locale with client.setLocale() in the SDKs or the X-Appwrite-Locale HTTP header. + You can send messages in different localizations by setting the locale with client.setLocale() in the SDKs or the X-Appwrite-Locale HTTP header.

    For example, you can send a phone verification in French.

    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 111/183] 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 { - + 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 112/183] 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 @@

      -
    1. The function is invoked.
    2. -
    3. Appwrite passes in request information like headers and environment variables through the context.req object.
    4. -
    5. The runtime executes the code you defined, you can log through the context.log or context.error methods.
    6. -
    7. Function terminates when you return results using context.res.
    8. +
    9. The function is invoked.
    10. +
    11. Appwrite passes in request information like headers and environment variables through the context.req object.
    12. +
    13. The runtime executes the code you defined, you can log through the context.log or context.error methods.
    14. +
    15. 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.

    Deno denodeno cachedeno cache [ENTRYPOINT_FILE]
    Dart
    - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +
    PropertyDescription
    PropertyDescription
    reqContains request information like method, body, and headers. See full examples here.
    resContains methods to build a response and return information. See full examples here.
    logLogs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
    errorLogs errors to the Appwrite Console, end users will not be able to see these errors. See full examples here.
    reqContains request information like method, body, and headers. See full examples here.
    resContains methods to build a response and return information. See full examples here.
    logLogs information to the Appwrite Console, end users will not be able to see these logs. See full examples here.
    errorLogs 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. -

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

    Response

    -

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

    - -
      -
    • -

      Node.js

      -
      -
      export default async ({ req, res, log }) => {
      +    

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

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

      Response

      +

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

      + +
        +
      • +

        Node.js

        +
        +
        export default async ({ req, res, log }) => {
         
             switch (req.query.type) {
                 case 'text':
        @@ -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.

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

    You can access these logs through the following steps.

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

    Accessing Environment Variables

    +

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

    + +

    Default Environment Variables

    +

    + Appwrite runtimes passes in some environment variables by default. + These are always 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. +

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

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

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

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

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

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

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

    Response

    +

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

    + +
      +
    • +

      Node.js

      +
      +
      export default async ({ req, res, log }) => {
      +    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;
       
      -
      -    
      -        
      -            
      -            
      -        
      -    
      -    
      -        
      -            
      -            
      -        
      -        
      -            
      -            
      -        
      -        
      -            
      -            
      -        
      +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. +

      + +
      VariableDescription
      APPWRITE_FUNCTION_ID - The ID of the running function. -
      APPWRITE_FUNCTION_NAME - The Name of the running function. -
      APPWRITE_FUNCTION_DEPLOYMENT - The deployment ID of the running function. -
      + + + + + + + - - + + + - - + + + - - + + + - -
      LanguagePackage ManagerCommands
      APPWRITE_FUNCTION_PROJECT_ID - The project ID of the running function. - Node.jsnpmnpm install
      APPWRITE_FUNCTION_RUNTIME_NAME - The runtime of the running function. - PHPComposercomposer install
      APPWRITE_FUNCTION_RUNTIME_VERSION - The runtime version of the running function. - Pythonpippip 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. -

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

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

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

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

      - - - - - + + + - - - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - -
      VariableDescriptionRubyBundlerbundle install
      x-appwrite-trigger - Describes how the function execution was invoked. - Possible values are http, schedule or event. - Denodenodeno cache [ENTRYPOINT_FILE]
      x-appwrite-event - If the function execution was triggered by an event, describes the triggering event. - Dartpubpub 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. - SwiftSwift Package ManagerN/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. - .NETNuGetN/A
      x-appwrite-country-code - Displays the country code of the configured locale. - KotlinGradleN/A
      x-appwrite-continent-code - Displays the continent code of the configured locale. - JavaGradleN/A
      x-appwrite-continent-eu - Describes if the configured local is within the EU. - C++NoneN/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. -

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        LanguagePackage ManagerCommands
        Node.jsnpmnpm install
        PHPComposercomposer install
        Pythonpippip install -r requirements.txt
        RubyBundlerbundle install
        Denodenodeno cache [ENTRYPOINT_FILE]
        Dartpubpub get
        SwiftSwift Package ManagerN/A
        .NETNuGetN/A
        KotlinGradleN/A
        JavaGradleN/A
        C++NoneN/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. -

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

      Upgrade

      +

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

      + +

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

      + +
        +
      1. + The parameter passed into functions has changed. + req and res has been replaced by context, which contains new logger methods. + Learn about context. +
      2. +
      3. + To improve privacy and logging reliability, we provide new context.log() and context.error() functions. + You can no longer use native logging methods. + Learn about logging. +
      4. +
      5. + The old way of req.variables has been deprecated. + You can now access variables passed into each function as environment variables. + Learn about environment variables. +
      6. +
      7. + The req object has been updated to use terminology consistent with typical HTTP concepts. + You'll now find familiar concepts like headers, body, HTTP methods, and others. + Learn about request. +
      8. +
      9. + The response object has been updated. + You can now specify headers, as well as use new methods like return redirects or empty responses. + Learn about response. +
      10. +
      11. + Now, you must return a response such as return context.res.send(""). + This prevents confusing errors when functions are terminated prematurely before a response is sent. + Learn about response. +
      12. +
      13. + Some variables about how a function was triggered are now found in the context.req object as headers. +
      14. +
      \ No newline at end of file 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 113/183] 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 2b868da2bf7e49cce4583c5082ec8f1287fb9fb7 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 24 Aug 2023 11:01:08 +0100 Subject: [PATCH 114/183] Add alot more details around service account key creation --- app/views/docs/migrations-firebase.phtml | 158 +++++++++++++++++++---- 1 file changed, 130 insertions(+), 28 deletions(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index f8c236ea3..67cbd68e9 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -1,7 +1,7 @@

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

      @@ -16,34 +16,34 @@

      Supported resource types

      - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
      UsersDatabasesDocumentsFilesFunctions
      Firebase
      UsersDatabasesDocumentsFilesFunctions
      Firebase

      Migrating to Appwrite from Firebase

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

      - +
      1. Create a new project and click on the Migrations tab. @@ -52,7 +52,7 @@ Click on the Create Migration button and select Firebase as your source.
      2. - Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. + Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. See the Cloud and Self-hosting sections for details.
      3. @@ -79,12 +79,114 @@ Click the gear icon to access your Project Settings.
      4. - Click Service Accounts, then Generate New Private Key. Don't share this key with anyone! + Click on Service Accounts, then click on the Manage service account permissions link redirecting you to the Google Cloud Console.
      5. - Once you've downloaded your private key, head back to Appwrite and click Manual Authentication. + Click on Create Service Account, give it any name, id and description you want, then click Continue.
      6. - Upload the JSON private key and follow the wizard. + Next you'll be prompted to grant the service account roles, grant the following roles:
      7. -
      + + + + + + + + + + + + + + + + + +
      RoleReason
      Firebase ViewerRead access to your entire Firebase project including Database and Storage
      Identity Toolkit ViewerRead access to your users including their hash config
      +
    • If you prefer to create a custom role, you can use the following permissions:
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      PermissionReason
      datastore.databases.getRead access to your Firestore database
      datastore.databases.listRead access to your Firestore database
      datastore.entities.getRead access to your Firestore database's documents
      datastore.entities.listRead access to your Firestore database's documents
      datastore.indexes.getRead access to your Firestore database's indexes
      datastore.indexes.listRead access to your Firestore database's indexes
      firebaseauth.configs.getRead access to your Firebase project's authentication configs
      firebaseauth.configs.getHashConfigRead access to your Firebase project's authentication configs including hash salt
      firebaseauth.configs.getSecretRead access to your Firebase project's authentication configs including secret
      firebaseauth.users.getRead access to your Firebase project's users
      identitytoolkit.tenants.getRead access to your Firebase project's users
      identitytoolkit.tenants.listRead access to your Firebase project's users
      storage.buckets.getRead access to your Firebase project's storage buckets
      storage.buckets.listRead access to your Firebase project's storage buckets
      storage.objects.getRead access to your Firebase project's storage objects
      storage.objects.listRead access to your Firebase project's storage objects
      +
    • + Click Done to create the service account. After that you'll be redirected back to the service accounts page. Select the service account you just created and click Keys. +
    • +
    • + Click Add Key and select Create new key. Select JSON as the key type and click Create. This will download a JSON file to your computer. +
    • +
    • + Upload the JSON file to Appwrite and follow the migration wizard. +
    • + \ No newline at end of file From f7fe08ed2e4eb7f0edeb74dea6aeea063d475166 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 11:51:36 -0400 Subject: [PATCH 115/183] Update app/views/docs/migrations-firebase.phtml --- app/views/docs/migrations-firebase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index 893659197..cf575693e 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -58,7 +58,7 @@ Click on Service Accounts, then click on the Manage service account permissions link redirecting you to the Google Cloud Console.
    • - Click on Create Service Account, give it any name, id and description you want, then click Continue. + Click on Create Service Account, give it a name, id and description you want, then click Continue.
    • Next you'll be prompted to grant the service account roles, grant the following roles: From 255224e3bfaaa36b219f548955bc0ea72030222f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 11:51:41 -0400 Subject: [PATCH 116/183] Update app/views/docs/migrations-firebase.phtml --- app/views/docs/migrations-firebase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index cf575693e..c7a40ab3a 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -61,7 +61,7 @@ Click on Create Service Account, give it a name, id and description you want, then click Continue.
    • - Next you'll be prompted to grant the service account roles, grant the following roles: + Next you'll be prompted to grant the service account roles. You need to grant the following roles.
    • From d33d2230e3c66c3b98428cdd81db0b73304363c2 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 11:51:46 -0400 Subject: [PATCH 117/183] Update app/views/docs/migrations-firebase.phtml --- app/views/docs/migrations-firebase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index c7a40ab3a..e131a7826 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -73,7 +73,7 @@ - + From 6f67e62e39902e51efc8924839c801f8ca77e287 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 11:51:51 -0400 Subject: [PATCH 118/183] Update app/views/docs/migrations-firebase.phtml --- app/views/docs/migrations-firebase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index e131a7826..cb27cd23b 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -77,7 +77,7 @@ - +
      Firebase ViewerRead access to your entire Firebase project including Database and Storage
      Read access to your entire Firebase project including Database and Storage.
      Identity Toolkit Viewer
      Identity Toolkit ViewerRead access to your users including their hash config
      Read access to your users including their hash config.
      From 124826a67e84e87a08917c78a3ddfeeb78bdfe29 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 16:08:08 +0000 Subject: [PATCH 119/183] fix some style and grammar --- .../docs/migrations-cloud-to-local.phtml | 2 +- app/views/docs/migrations-firebase.phtml | 47 ++++++++++--------- .../docs/migrations-local-to-cloud.phtml | 2 +- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index 801d93c0e..743efb54b 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -1,5 +1,5 @@

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

      diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index cb27cd23b..c5d234175 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -36,13 +36,15 @@ -

      Appwrite Cloud

      +

      Migrate to Cloud

      To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically discover your Firebase projects. Simply select the source project and follow the migration wizard.

      -

      Migrating to Appwrite Self-Hosted

      +

      After completing the migration wizard, migration will begin. Return to step 4 of the migration steps.

      + +

      Migrating to Self-Hosted

      If you are self-hosting Appwrite you will need to create a service account in your Firebase project and download the JSON file.

      @@ -63,7 +65,7 @@
    • Next you'll be prompted to grant the service account roles. You need to grant the following roles.
    • - +
      @@ -81,8 +83,8 @@
      Role
      -
    • If you prefer to create a custom role, you can use the following permissions:
    • - +
    • If you prefer to create a custom role, you can use the following permissions.
    • +
      @@ -92,67 +94,67 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
      Permission
      datastore.databases.getRead access to your Firestore databaseRead access to your Firestore database.
      datastore.databases.listRead access to your Firestore databaseRead access to your Firestore database.
      datastore.entities.getRead access to your Firestore database's documentsRead access to your Firestore database's documents.
      datastore.entities.listRead access to your Firestore database's documentsRead access to your Firestore database's documents.
      datastore.indexes.getRead access to your Firestore database's indexesRead access to your Firestore database's indexes.
      datastore.indexes.listRead access to your Firestore database's indexesRead access to your Firestore database's indexes.
      firebaseauth.configs.getRead access to your Firebase project's authentication configsRead access to your Firebase project's authentication configs.
      firebaseauth.configs.getHashConfigRead access to your Firebase project's authentication configs including hash saltRead access to your Firebase project's authentication configs including hash salt.
      firebaseauth.configs.getSecretRead access to your Firebase project's authentication configs including secretRead access to your Firebase project's authentication configs including secret.
      firebaseauth.users.getRead access to your Firebase project's usersRead access to your Firebase project's users.
      identitytoolkit.tenants.getRead access to your Firebase project's usersRead access to your Firebase project's users.
      identitytoolkit.tenants.listRead access to your Firebase project's usersRead access to your Firebase project's users.
      storage.buckets.getRead access to your Firebase project's storage bucketsRead access to your Firebase project's storage buckets.
      storage.buckets.listRead access to your Firebase project's storage bucketsRead access to your Firebase project's storage buckets.
      storage.objects.getRead access to your Firebase project's storage objectsRead access to your Firebase project's storage objects.
      storage.objects.listRead access to your Firebase project's storage objectsRead access to your Firebase project's storage objects.
      @@ -165,4 +167,7 @@
    • Upload the JSON file to Appwrite and follow the migration wizard.
    • +
    • + After completing the migration wizard, migration will begin. Return to step 4 of the migration steps. +
    • \ No newline at end of file diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index 5cfee4cb8..96cd51ec3 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -1,5 +1,5 @@

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

      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 120/183] 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

      1. - Checkout your prodction branch in Git. + Checkout your production branch in Git.
      2. Create a new commit. From eaa9683820bde906933c40c4500dcb77f15ffd8f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 24 Aug 2023 12:12:27 -0400 Subject: [PATCH 121/183] Update app/views/docs/migrations-supabase.phtml Co-authored-by: Bradley Schofield --- app/views/docs/migrations-supabase.phtml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index 754445ad0..e5b789ebd 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -40,9 +40,6 @@
          -
        1. - Region - The region your Supabase project is hosted in. This can be found in your Supabase project environment variables as Supabase_REGION. -
        2. Host - The host of your Supabase Database, this can be found in your Supabase project settings under Database Settings and Host.
        3. 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 122/183] 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 123/183] 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.

          1. 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.
          2. - 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.
          3. 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.

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

          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.

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

        Redeploy Builds

        +

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

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

        + 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 124/183] 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 125/183] 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:

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

        Create a Votes collection with the following attributes:

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

        Code

        • Node.js

          -

          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 126/183] 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:

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

        Code

        + +
          +
        • +

          Node.js

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

          Python

          +
          +

          +

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

          PHP

          +
          +

          +

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

          Ruby

          +
          +

          +

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

          Dart

          +
          +

          +

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

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

        [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 f6dff91336e60e90ef216ab7d343fbd66e9f2a5f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:30:55 -0400 Subject: [PATCH 127/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index 743efb54b..8fb11b0cb 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -20,7 +20,7 @@

        Steps on Your Cloud Project

          -
        1. Navigate to your Appwrite Cloud Console and click on the Migrations tab.
        2. +
        3. Navigate to your Appwrite Cloud Console and click on the Migrations tab in Project Settings.
        4. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
        5. Optionally, tell us about why you're moving to self-hosted.
        6. After clicking Continue, you'll be directed back to your self-hosted project to complete the process.
        7. From 54300083b3e7b8fb12cf4b7a5870ca985dab3640 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:31:04 -0400 Subject: [PATCH 128/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index 8fb11b0cb..184e43bd1 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -23,7 +23,7 @@
        8. Navigate to your Appwrite Cloud Console and click on the Migrations tab in Project Settings.
        9. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
        10. Optionally, tell us about why you're moving to self-hosted.
        11. -
        12. After clicking Continue, you'll be directed back to your self-hosted project to complete the process.
        13. +
        14. After clicking Continue, you'll be redirected to your self-hosted project to complete the process.

        Steps on Your Self-hosted Project

        From 635ee8dbeadc61da5cf37b9802b5bbe406988757 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:31:19 -0400 Subject: [PATCH 129/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index 184e43bd1..c66644803 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -18,7 +18,7 @@ and things to keep in mind sections above.

        -

        Steps on Your Cloud Project

        +

        Steps in Cloud Console

        1. Navigate to your Appwrite Cloud Console and click on the Migrations tab in Project Settings.
        2. Click Export to Self-hosted, you will be prompted to input the URL of your self-hosted Appwrite project.
        3. From 47dd217e4365b9b6ce5a3046054cb7c89a81b24a Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:31:32 -0400 Subject: [PATCH 130/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index c66644803..abfb8e673 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -26,7 +26,7 @@
        4. After clicking Continue, you'll be redirected to your self-hosted project to complete the process.
        -

        Steps on Your Self-hosted Project

        +

        Steps in Self-hosted Console

        1. Once redirected to your self-hosted project, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
        2. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
        3. From 3cdd52d888b82dcb4bbb8b4ae6c1e4fbe73ba454 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:31:58 -0400 Subject: [PATCH 131/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index abfb8e673..c242905ad 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -28,7 +28,7 @@

          Steps in Self-hosted Console

            -
          1. Once redirected to your self-hosted project, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
          2. +
          3. Once redirected to your self-hosted server, you'll be prompted to select a project. If you have multiple organizations, you will also be asked to pick one. You can migrate to an existing project or create a new one.
          4. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
          5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
          \ No newline at end of file From 98f2b36efd36f33d2fabdecfdb7435efd6165707 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:32:13 -0400 Subject: [PATCH 132/183] Update app/views/docs/migrations-cloud-to-local.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/migrations-cloud-to-local.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-cloud-to-local.phtml b/app/views/docs/migrations-cloud-to-local.phtml index c242905ad..6c012e1ef 100644 --- a/app/views/docs/migrations-cloud-to-local.phtml +++ b/app/views/docs/migrations-cloud-to-local.phtml @@ -30,5 +30,5 @@
          1. Once redirected to your self-hosted server, you'll be prompted to select a project. If you have multiple organizations, you will also be asked to pick one. You can migrate to an existing project or create a new one.
          2. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
          3. -
          4. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
          5. +
          6. Click Start migration to begin the migration process. You do not need to keep the Appwrite Console open through the process.
          \ No newline at end of file From 09607691e7824b53393e776569ed81fed8c73624 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:32:48 -0400 Subject: [PATCH 133/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index 96cd51ec3..e69a47ff0 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -11,7 +11,7 @@
        4. Migrations are non-destructive. No data will be deleted or lost in the source project.
        -

        Migrating to Self-hosted from Cloud

        +

        Migrating to Cloud from Self-hosted

        To begin migrating to self-hosted, make sure to read the migration overview and things to keep in mind sections above. From b8d7cafd11c538ab25b7e4977dbb8c81317cd9cf Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:33:03 -0400 Subject: [PATCH 134/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index e69a47ff0..3b51000a9 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -17,7 +17,7 @@ and things to keep in mind sections above.

        -

        Steps on Your Self-hosted Project

        +

        Steps in Self-hosted Console

        1. Navigate to your self-hosted project's console and click on the Migrations tab.
        2. From d21952e2340b8a78596ab3b4764143ad28cb60ab Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:33:12 -0400 Subject: [PATCH 135/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index 3b51000a9..4f6e8ac78 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -25,7 +25,7 @@
        3. You will complete the migration on Appwrite Cloud.
        -

        Steps on Your Cloud Project

        +

        Steps in Cloud Console

        1. Once redirected to Appwrite Cloud, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
        2. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
        3. From d18687646ba34a710c55ec7d7fa4daa361d31e34 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:33:19 -0400 Subject: [PATCH 136/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index 4f6e8ac78..f1db09fb4 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -20,7 +20,7 @@

          Steps in Self-hosted Console

            -
          1. Navigate to your self-hosted project's console and click on the Migrations tab.
          2. +
          3. Navigate to your self-hosted project's console and click on the Migrations tab in Project Settings.
          4. Click Deploy to cloud, you will be redirected to Appwrite Cloud.
          5. You will complete the migration on Appwrite Cloud.
          From 3b6ca9aee33137e745fa35d70688ff68b2f8beb8 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:33:41 -0400 Subject: [PATCH 137/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index f1db09fb4..bf2efd78c 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -21,7 +21,7 @@
          1. Navigate to your self-hosted project's console and click on the Migrations tab in Project Settings.
          2. -
          3. Click Deploy to cloud, you will be redirected to Appwrite Cloud.
          4. +
          5. Click Deploy to cloud, and you will be redirected to Appwrite Cloud.
          6. You will complete the migration on Appwrite Cloud.
          From 70d285eb1b328420a869c22eeb39e51663bd5962 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:34:53 -0400 Subject: [PATCH 138/183] Update app/views/docs/migrations-local-to-cloud.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/migrations-local-to-cloud.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-local-to-cloud.phtml b/app/views/docs/migrations-local-to-cloud.phtml index bf2efd78c..9040dafa1 100644 --- a/app/views/docs/migrations-local-to-cloud.phtml +++ b/app/views/docs/migrations-local-to-cloud.phtml @@ -27,7 +27,7 @@

          Steps in Cloud Console

            -
          1. Once redirected to Appwrite Cloud, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
          2. +
          3. Once redirected to Appwrite Cloud, you'll be prompted to select a project. If you have multiple organizations, you will also be asked to pick one. You can migrate to an existing project or create a new one.
          4. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
          5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
          From 70518866774a5be3262c8faa455d433b5ff80233 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:36:04 -0400 Subject: [PATCH 139/183] Update app/views/docs/migrations.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/migrations.phtml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index d51e3709f..8f1b98d8e 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -1,6 +1,7 @@

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

          From 645eb610e20c31003a5e4739d70c5bdb37e49e2a Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:36:14 -0400 Subject: [PATCH 140/183] Update app/views/docs/migrations.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/migrations.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index 8f1b98d8e..6e3e09661 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -82,6 +82,6 @@

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

          \ No newline at end of file From 6ddde09aaa2b391f2d2aa7b253ac3cef0dc10332 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:36:40 -0400 Subject: [PATCH 141/183] Update app/views/docs/migrations-nhost.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/migrations-nhost.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml index ca9aed1d5..0c48071da 100644 --- a/app/views/docs/migrations-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -21,7 +21,7 @@
          1. - Create a new project and click on the Migrations tab. + Create a new project and click on the Migrations tab in Project Settings.
          2. Click on the Create Migration button and select NHost as your source. From 7e06a3068ca577f62e7c4748544214a8a88d5050 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:36:49 -0400 Subject: [PATCH 142/183] Update app/views/docs/migrations-supabase.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/migrations-supabase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index e5b789ebd..09ecd1fd3 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -21,7 +21,7 @@
            1. - Create a new project and click on the Migrations tab. + Create a new project and click on the Migrations tab in Project Settings.
            2. Click on the Create Migration button and select Supabase as your source. From bf58e0f0ced58b2ca6ae12d3ecdca9176d83e152 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 10:37:02 -0400 Subject: [PATCH 143/183] Update app/views/docs/migrations-firebase.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/migrations-firebase.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index c5d234175..999147a8d 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -22,7 +22,7 @@
              1. - Create a new project and click on the Migrations tab. + Create a new project and click on the Migrations tab in Project Settings.
              2. Click on the Create Migration button and select Firebase as your source. From 2e5216e28024ff25e85af015ba1a6a25d7966724 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 16:37:03 +0000 Subject: [PATCH 144/183] Resolve conflicts with upstream --- app/views/docs/index.phtml | 4 +- .../migrations-cloud-to-self-hosted.phtml | 34 +++++++++++++++++ app/views/docs/migrations-firebase.phtml | 5 ++- app/views/docs/migrations-nhost.phtml | 3 +- .../migrations-self-hosted-to-cloud.phtml | 38 +++++++++++++++++++ app/views/docs/migrations-supabase.phtml | 3 +- app/views/docs/migrations.phtml | 9 +++-- 7 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 app/views/docs/migrations-cloud-to-self-hosted.phtml create mode 100644 app/views/docs/migrations-self-hosted-to-cloud.phtml diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index ec9819fbf..b57eb9a43 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -99,8 +99,8 @@ $cols = [
              3.    Firebase
              4.    Supabase
              5.    NHost
              6. -
              7.    Cloud to Self-hosted
              8. -
              9.    Self-hosted to Cloud
              10. +
              11.    Cloud to Self-hosted
              12. +
              13.    Self-hosted to Cloud
    diff --git a/app/views/docs/migrations-cloud-to-self-hosted.phtml b/app/views/docs/migrations-cloud-to-self-hosted.phtml new file mode 100644 index 000000000..801d93c0e --- /dev/null +++ b/app/views/docs/migrations-cloud-to-self-hosted.phtml @@ -0,0 +1,34 @@ +

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

    + +

    Things to keep in mind

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

    Migrating to Self-hosted from Cloud

    + +

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

    + +

    Steps on Your Cloud Project

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

    Steps on Your Self-hosted Project

    +
      +
    1. Once redirected to your self-hosted project, you'll be prompted to select an organization and a project. You can migrate to an existing project or create a new one.
    2. +
    3. Select the data you wish to migrate. You can choose among accounts, databases, documents, files, and functions.
    4. +
    5. Click Start migration to start the migration process. You do not need to keep the Appwrite Console open through the process.
    6. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index 999147a8d..f16efc879 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -10,8 +10,9 @@
    1. Appwrite will not incur usage charges during migrations, but Firebase may still incur service charges.
    2. Appwrite Migrations only supports Firestore as a database source. Realtime Database is currently not supported.
    3. -
    4. At the moment only top level document migration is supported. Nested documents will not be transferred automatically.
    5. -
    6. OAuth users will not be transferred. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    7. +
    8. At the moment only top level document migration is supported. Nested documents will not be migrated automatically.
    9. +
    10. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    11. +
    12. Functions are not automatically migrated because of syntax and runtime differences.

    Migrating to Appwrite from Firebase

    diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml index 0c48071da..20a8edef2 100644 --- a/app/views/docs/migrations-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -10,7 +10,8 @@
    1. Appwrite will not incur usage charges during migrations, but NHost may still incur service charges.
    2. Appwrite's Database doesn't support all the features of the postgreSQL database so more advanced postgres centric things things like advanced indexes, postgres functions and scheduling will not be migrated.
    3. -
    4. OAuth users will not be transferred. You will need to re-authenticate with your OAuth provider after the migration is complete.
    5. +
    6. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    7. +
    8. Functions are not automatically migrated because of syntax and runtime differences.

    Migrating to Appwrite from NHost

    diff --git a/app/views/docs/migrations-self-hosted-to-cloud.phtml b/app/views/docs/migrations-self-hosted-to-cloud.phtml new file mode 100644 index 000000000..5cfee4cb8 --- /dev/null +++ b/app/views/docs/migrations-self-hosted-to-cloud.phtml @@ -0,0 +1,38 @@ +

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

    + +

    Things to keep in mind

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

    Migrating to Self-hosted from Cloud

    +

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

    + +

    Steps on Your Self-hosted Project

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

    Steps on Your Cloud Project

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

    Keep in mind

    +

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

    +
    \ No newline at end of file diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index 09ecd1fd3..dedbcbcb7 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -10,7 +10,8 @@
    1. Appwrite will not incur usage charges during migrations, but Supabase may still incur service charges.
    2. Appwrite's Databases services supports a different set of features as PostgreSQL. Some features like advanced indexes, Postgres functions and scheduling will not be migrated.
    3. -
    4. OAuth users will not be transferred. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    5. +
    6. OAuth users will not be migrated because the sessions are managed by the third-party OAuth provider. Users will need to re-authenticate with your OAuth provider after the migration is complete.
    7. +
    8. Functions are not automatically migrated because of syntax and runtime differences.

    Migrating to Appwrite from Supabase

    diff --git a/app/views/docs/migrations.phtml b/app/views/docs/migrations.phtml index 6e3e09661..e130ae472 100644 --- a/app/views/docs/migrations.phtml +++ b/app/views/docs/migrations.phtml @@ -7,7 +7,10 @@

    Supported sources

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

    @@ -54,7 +57,7 @@ @@ -64,7 +67,7 @@ From eb9d20aa77914b85e99288bcc4888a30110e9a06 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 16:51:04 +0000 Subject: [PATCH 145/183] Address matej's comments --- app/views/docs/migrations-firebase.phtml | 26 +++--------------------- app/views/docs/migrations-nhost.phtml | 3 +++ app/views/docs/migrations-supabase.phtml | 3 +++ 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/app/views/docs/migrations-firebase.phtml b/app/views/docs/migrations-firebase.phtml index f16efc879..2c351d599 100644 --- a/app/views/docs/migrations-firebase.phtml +++ b/app/views/docs/migrations-firebase.phtml @@ -28,29 +28,6 @@
  • Click on the Create Migration button and select Firebase as your source.
  • -
  • - Depending on where your Appwrite project is hosted, you'll need to use different methods to authorize with Firebase. - See the Cloud and Self-hosting sections for details. -
  • -
  • - Finally, add the platforms for your Web, Flutter, Android, and iOS apps. -
  • - - -

    Migrate to Cloud

    -

    - To simplify the migration process we have created an OAuth application that will allow you to sign in with Google and automatically - discover your Firebase projects. Simply select the source project and follow the migration wizard. -

    - -

    After completing the migration wizard, migration will begin. Return to step 4 of the migration steps.

    - -

    Migrating to Self-Hosted

    -

    - If you are self-hosting Appwrite you will need to create a service account in your Firebase project and download the JSON file. -

    - -
    1. Navigate to your Firebase console.
    2. @@ -171,4 +148,7 @@
    3. After completing the migration wizard, migration will begin. Return to step 4 of the migration steps.
    4. +
    5. + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
    \ No newline at end of file diff --git a/app/views/docs/migrations-nhost.phtml b/app/views/docs/migrations-nhost.phtml index 20a8edef2..7558fe9b5 100644 --- a/app/views/docs/migrations-nhost.phtml +++ b/app/views/docs/migrations-nhost.phtml @@ -33,6 +33,9 @@
  • Select the resources you want to migrate and finally click Start migration to begin the migration process.
  • +
  • + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
  • NHost Credentials

    diff --git a/app/views/docs/migrations-supabase.phtml b/app/views/docs/migrations-supabase.phtml index dedbcbcb7..8ff4a7bca 100644 --- a/app/views/docs/migrations-supabase.phtml +++ b/app/views/docs/migrations-supabase.phtml @@ -33,6 +33,9 @@
  • Select the resources you want to migrate and finally click Start migration to begin the migration process.
  • +
  • + Finally, add the platforms for your Web, Flutter, Android, and iOS apps. +
  • Credentials

    From b5dd0689288869e94b36dd1afd00be3af8fb21f9 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 14:08:56 -0400 Subject: [PATCH 146/183] Update app/views/docs/email-and-sms-templates.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/email-and-sms-templates.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 1d4ec7c15..63730e086 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -2,7 +2,7 @@

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

    From e6b6fee0da3a75ab50a768b456761a821940e870 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 14:09:06 -0400 Subject: [PATCH 147/183] Update app/views/docs/email-and-sms-templates.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/email-and-sms-templates.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index 63730e086..bb6b6b4d6 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,4 +1,4 @@ -

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

    +

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

    Each Appwrite project can have its own set of unique templates. From 9249017aa0c8d6eafe3dbb8c24b8606eda8adee4 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 14:11:47 -0400 Subject: [PATCH 148/183] 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/email-and-sms-templates.phtml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index bb6b6b4d6..c7a723c36 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -17,7 +17,7 @@

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

    Custom SMTP Server Required

    -

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

    +

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

    1. In your project, navigate to the Auth service.
    2. @@ -40,15 +40,15 @@
    - + - + - + @@ -56,12 +56,12 @@ - +
    -

    Cloud to Self-hosted

    +

    Cloud to Self-hosted

    supported supported
    -

    Self-hosted to Cloud

    +

    Self-hosted to Cloud

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

    Email Template Syntax

    -

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

    +

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

    @@ -81,7 +81,7 @@ - + @@ -192,7 +192,7 @@

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

    For example, you can send a phone verification in French.

    From 5353edfb0505d9e2f8f913f1207e55a2bf84e18d Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 18:39:31 +0000 Subject: [PATCH 149/183] Console capitalized --- app/views/docs/email-and-sms-templates.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index c7a723c36..aed0abe2d 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -14,7 +14,7 @@

    Customize Templates

    -

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

    +

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

    Custom SMTP Server Required

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

    From 7844c58d5f6382dc29eb97f608404fbc32bb3f2b Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 18:47:07 +0000 Subject: [PATCH 150/183] remove reference of phone/sms template --- app/views/docs/email-and-sms-templates.phtml | 61 ++------------------ 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index aed0abe2d..f1327335d 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -1,4 +1,4 @@ -

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

    +

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

    Each Appwrite project can have its own set of unique templates. @@ -6,13 +6,6 @@ depending on the configured locale.

    -

    -Email Templates -

    -

    -SMS Templates -

    -

    Customize Templates

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

    @@ -142,48 +135,6 @@ </html>
    -

    SMS Templates

    -

    You can customize the SMS templates used for phone verification and login.

    -

    SMS Template Components

    -
    {{user}}The name of the user receiving the email.The name of the user receiving the email. This variable is not available in the Magic URL template, as there might not be a user yet.
    {{redirect}}
    - - - - - - - - - - - - -
    ComponentDescription
    MessageThe body of the SMS message. You can find the variables available in the SMS Template Syntax section.
    - -

    SMS Template Syntax

    -

    Variables can be used in SMS templates to dynamically format unique messages for each reader.

    - - - - - - - - - - - - - - -
    VariableDescription
    {{token}}The secret code sent to users for phone verification or authentication.
    - -

    SMS Template Examples

    -

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

    -
    -
    Your account verification code is {{token}}
    -
    -

    Localization

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

    -

    For example, you can send a phone verification in French.

    +

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

    • Web

      @@ -212,7 +163,7 @@ client .setLocale('fr') // Your locale ; -const promise = account.createPhoneVerification(); +const promise = account.createVerification('https://example.com'); promise.then(function (response) { console.log(response); // Success @@ -235,7 +186,7 @@ void main() { // Init SDK .setProject('5df5acd0d48c2') // Your project ID .setLocale('fr') // Your locale ; - Future result = account.createPhoneVerification(); + Future result = account.createVerification('https://example.com'); result .then((response) { @@ -259,7 +210,7 @@ val client = Client(context) val account = Account(client) -val response = account.createPhoneVerification()
      +val response = account.createVerification('https://example.com')
    • @@ -274,7 +225,7 @@ let client = Client() let account = Account(client) -let token = try await account.createPhoneVerification() +let token = try await account.createVerification('https://example.com')
    \ No newline at end of file From 24ebe2fd296bf26bf5b1130127a4b2aa1926a687 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 25 Aug 2023 19:03:44 +0000 Subject: [PATCH 151/183] Fix index --- app/views/docs/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 5db26d3dc..8f0bd9a08 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -107,7 +107,7 @@ $cols = [
  • Pagination
  • Webhooks
  • Custom Domains
  • -
  • Email and SMS Templates
  • +
  • Email Templates
  • Response Codes
  • Rate Limits
  • 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 152/183] 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'] ?? [])); ?> - + Function Env. + + + 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 153/183] 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 { - + @@ -1372,64 +1372,7 @@ namespace runtime { You can access the environment variables through the systems library of each language.

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

    Response

    +

    If you need to send a response to the invoker of the function, such as a user, client app, or an integration, use the response object. The response information will not be logged to the Appwrite Console. @@ -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 154/183] 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 155/183] 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.

      1. @@ -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 @@
      2. Navigate to the Domains tab.
      3. Click on Create domain.
      4. Input your domain in the Domain input field and click Next.
      5. -
      6. Copy the CNAME record provided to you, and add it to your domain registar.
      7. +
      8. Copy the CNAME record provided to you, and add it to your domain registrar.
      9. 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.

        1. In Appwrite Console, navigate to Functions.
        2. -
        3. Click to open a function you wish to add variables to.
        4. +
        5. Click to open a function you wish to configure.
        6. Under the Settings tab, navigate to Events.
        7. Add one or multiple events as triggers for the function.
        8. 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 156/183] 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 @@

        1. The function is invoked.
        2. -
        3. Appwrite passes in request information like headers and environment variables through the context.req object.
        4. -
        5. The runtime executes the code you defined, you can log through the context.log or context.error methods.
        6. -
        7. Function terminates when you return results using context.res.
        8. +
        9. Appwrite passes in request information like headers, body or path through the context.req object.
        10. +
        11. The runtime executes the code you defined, you can log through the context.log() or context.error() methods.
        12. +
        13. 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.

        1. In Appwrite Console, navigate to Functions.
        2. @@ -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.

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

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

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

          4. @@ -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 157/183] 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.

            1. Navigate to the function you want to deploy.
            2. 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.

              1. Whitelist a group of developers by IP using the _APP_CONSOLE_WHITELIST_IPS environment variable.
              2. diff --git a/app/views/docs/self-hosting.phtml b/app/views/docs/self-hosting.phtml index 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 158/183] 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 159/183] 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.

              3. - 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.
              4. - 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.
              5. - 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.
              6. - 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.
              7. 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.
              8. Finally, configure the execute permissions of the function. For security, only provide execute permissions to the necessary roles. @@ -54,7 +55,7 @@

                Deploy

                1. - Checkout your production branch in Git. + Using Git, checkout the branch you configured as production branch when creating the Appwrite Function.
                2. Create a new commit. @@ -63,18 +64,18 @@ Push your new commit.
                3. - 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 @@

              9. Select the Manual tab.
              10. Input the entry point of your function under Entrypoint. For the example above, it would be index.js.
              11. Upload code.tar.gz.
              12. -
              13. Select Activate deployment after build to use your new function.
              14. +
              15. Select Activate deployment after build to use your new deployment.
              16. 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 160/183] 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.

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

              @@ -208,10 +207,10 @@

            3. In Appwrite Console, navigate to Functions.
            4. Click to open a function you wish to inspect.
            5. Under the Deployments tab, you'll find the status of the current active deployment.
            6. -
            7. You can redeploy by clicking the Redeploy button.
            8. +
            9. You can redeploy by clicking the triple-dots beside an execution, and hitting the Redeploy button.
            10. 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;
              + - @@ -53,7 +53,15 @@ $sorted_runtimes['Dart']["cloud"] = true; Function Env. + - 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 161/183] 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) { - - + + + - + @@ -53,17 +54,21 @@ foreach ($runtimes as $key => $item) { Function Env. + $version): ?> + escape($version['version']); ?>
              +
              + - + - + - + - + @@ -487,20 +487,32 @@ public class Main {
            11. 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
               }
            12. 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
               }
            13. @@ -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. +

              + +
              Nameversion Image ArchitecturesPlatforms
              - 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 - -
              NameversionNameVersion ImageArchitecturesArchitectures
              - escape($key); ?> + escape($key); ?> - - Self-hosted - - Cloud - - + $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 162/183] 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 163/183] 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 {
              reqContains request information like method, body, and headers. See full examples here.Contains request information like method, body, and headers. See full examples here.
              resContains 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.
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              TypeQuery ParamExample
              text/?type=texthttps://64d4d22db370ae41a32e.appwrite.global/?type=text
              json/?type=jsonhttps://64d4d22db370ae41a32e.appwrite.global/?type=json
              redirect/?type=redirecthttps://64d4d22db370ae41a32e.appwrite.global/?type=redirect
              html/?type=htmlhttps://64d4d22db370ae41a32e.appwrite.global/?type=html
              empty/https://64d4d22db370ae41a32e.appwrite.global/
              +

              Logging

              To protect user privacy, the request and response objects are not logged to the Appwrite Console by default. @@ -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.

              1. In Appwrite Console, navigate to Functions.
              2. @@ -1360,13 +1413,13 @@ namespace runtime {
              3. 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.

                -
              1. In Appwrite Console, navigate to your project's Settings page.
              2. +
              3. In the Appwrite Console, navigate to your project's Settings page.
              4. Navigate to Global variables section.
              5. 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. -

              - - - + + + + + + + + + + + + + +
              LanguagePackage ManagerLanguagePackage Manager Commands
              + Node icon + Node.js npm npm install
              + PHP icon + PHP Composer composer install
              + Python icon + Python pip pip install -r requirements.txt
              + Ruby icon + Ruby Bundler bundle install
              + Deno icon + Deno deno deno cache <ENTRYPOINT_FILE>
              + Dart icon + Dart pub pub get
              + Swift icon + Swift Swift Package Manager N/A
              + Swift icon + .NET NuGet N/A
              + Swift icon + Kotlin Gradle N/A
              + Swift icon + Java Gradle N/A
              + C++ icon + 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 164/183] 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 @@

              Firebase

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

              Supabase

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

              NHost

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

              Cloud to Self-hosted

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

              Self-hosted to Cloud

              - supported - supported - supported - supported - supported + enabled + enabled + enabled + enabled + enabled From 3eaa24612b83692fb221185647b42c596a9e83e9 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Sun, 27 Aug 2023 11:17:01 -0400 Subject: [PATCH 165/183] 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/authentication-magic.phtml | 2 +- app/views/docs/authentication-oauth.phtml | 2 +- app/views/docs/authentication-security.phtml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index e50694877..7ef26927f 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -1,6 +1,6 @@

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

              diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 0a3ec4854..e8dee928b 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -284,7 +284,7 @@ print(session.providerAccessToken);

              Refresh Tokens

              - OAuth 2 sessions expire to protect from security risks. + OAuth 2 access tokens expire to protect from security risks. OAuth 2 sessions should be periodically refreshed to keep the user authenticated. You can do this by calling the Update OAuth Session endpoint when ever your user visits your app.

              diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 9bae92804..ed68f5229 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -102,4 +102,4 @@ Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal data. Personal data includes the user's name, email, and phone number.

              -

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

              +

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

              From 56213ec352b30326859e6bdbd2cdf7aa4f8cd85f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Sun, 27 Aug 2023 19:29:31 +0000 Subject: [PATCH 166/183] Fix code example errors and other items pointed out during review --- app/views/docs/authentication-anonymous.phtml | 2 +- app/views/docs/authentication-magic.phtml | 106 +----------------- .../docs/authentication-management.phtml | 48 +++++--- app/views/docs/authentication-oauth.phtml | 15 ++- 4 files changed, 50 insertions(+), 121 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 4992ebe29..a64394aca 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -97,7 +97,7 @@ mutation {

              Attaching an Account

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

              diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index e50694877..2e3ea2262 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -8,7 +8,7 @@

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

              @@ -25,7 +25,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); +const promise = account.createMagicURLSession(ID.unique(), 'email@example.com'); promise.then(function (response) { console.log(response); // Success @@ -34,61 +34,12 @@ promise.then(function (response) { });
              -
            14. -

              Flutter

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

              Android

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

              Apple

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

              mutation {
                   accountCreateMagicURLSession(
              -        userId: "email@example.com",
              +        userId: "ID.unique()",
                       email: "email@example.com"
                   ) {
                       _id
              @@ -127,61 +78,12 @@ const userId = urlParams.get('userId');
               const user = await account.updateMagicURLSession(userId, secret);
            20. -
            21. -

              Flutter

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

              Android

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

              Apple

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

              mutation {
                   accountUpdateMagicURLSession(
              -        userId: "email@example.com",
              +        userId: "[USER_ID]",
                       secret: "[SECRET]"
                   ) {
                       _id
              diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml
              index 4e3514b27..d0b15fb2a 100644
              --- a/app/views/docs/authentication-management.phtml
              +++ b/app/views/docs/authentication-management.phtml
              @@ -26,7 +26,13 @@ const client = new Client()
               
               const account = new Account(client);
               
              -const user = await account.updatePrefs({darkTheme: true, language: 'en'});
              +const promise = account.updatePrefs({darkTheme: true, language: 'en'}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
            27. @@ -86,16 +92,7 @@ let user = try await account.updatePrefs( prefs: "{\"darkTheme\": true, \"language\": \"en\"}" ) { _id - _createdAt - _updatedAt name - registration - status - passwordUpdate - email - phone - emailVerification - phoneVerification prefs { data } @@ -119,7 +116,13 @@ const client = new Client() const account = new Account(client); -const user = await account.getPrefs(); +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
            28. @@ -205,11 +208,24 @@ let prefs = try await account.getPrefs()
              const sdk = require('node-appwrite');
               
              +// Init SDK
               const client = new sdk.Client();
               
               const users = new sdk.Users(client);
               
              -let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
              +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
            29. @@ -294,7 +310,13 @@ client ; -let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); +const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
            30. diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 0a3ec4854..00fa1c211 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -15,10 +15,13 @@

                -
              1. Navigate to your Appwrite project
              2. -
              3. Navigate to Auth > Settings
              4. +
              5. Navigate to your Appwrite project.
              6. +
              7. Navigate to Auth > Settings.
              8. Find and open the OAuth provider.
              9. -
              10. In the OAuth 2 settings modal, use the toggle to enable the provider
              11. +
              12. In the OAuth 2 settings modal, use the toggle to enable the provider.
              13. +
              14. Create and OAuth 2 app on the provider's developer platform.
              15. +
              16. Copy information from your OAuth2 provider's developer platform to fill the OAuth2 Settings modal in the Appwrite Console.
              17. +
              18. Configure redirect URL in your OAuth 2 provider's developer platform. Set it to URL provided to you by OAuth2 Settings modal in Appwrite Console.
              @@ -152,7 +155,7 @@ try await account.createOAuth2Session(provider: "amazon")

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

              @@ -285,7 +288,9 @@ print(session.providerAccessToken);

              Refresh Tokens

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

              From 36bda50ba9dc89de1211103c327e8fe71fc7bbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 29 Aug 2023 13:25:38 +0000 Subject: [PATCH 167/183] Improve destructuring snippets --- app/views/docs/functions-develop.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index b2b7bad38..a8a01e4ba 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -490,13 +490,13 @@ public class Main {
              // before destructuring
               export default async function (context) {
                   context.log("This is a log!");
              -    // ... more code
              +    return context.res.send("This is a response!");
               }
               
               // after destructuring
               export default async function ({ req, res, log, error }) {
                   log("This is a log!");
              -    // ... more code
              +    return res.send("This is a response!");
               }
            31. @@ -506,13 +506,13 @@ export default async function ({ req, res, log, error }) {
              // before destructuring
               export default async function (context: any) {
                   context.log("This is a log!");
              -    // ... more code
              +    return context.res.send("This is a response!");
               }
                  
               // after destructuring
               export default async function ({ req, res, log, error }: any) {
                   context.log("This is a log!");
              -    // ... more code
              +    return res.send("This is a response!");
               }
              From 6e68633af77f648c860eb7a3701730715e80f386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 29 Aug 2023 13:26:26 +0000 Subject: [PATCH 168/183] Fix deno destructing --- 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 a8a01e4ba..4f5adbb6e 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -511,7 +511,7 @@ export default async function (context: any) { // after destructuring export default async function ({ req, res, log, error }: any) { - context.log("This is a log!"); + log("This is a log!"); return res.send("This is a response!"); }
              From 034de4ad39903e4a761011ed9a58ce04830e67da Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 29 Aug 2023 13:49:28 +0000 Subject: [PATCH 169/183] Add SMTP steps --- app/views/docs/email-and-sms-templates.phtml | 22 +++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/views/docs/email-and-sms-templates.phtml b/app/views/docs/email-and-sms-templates.phtml index f1327335d..e685405f0 100644 --- a/app/views/docs/email-and-sms-templates.phtml +++ b/app/views/docs/email-and-sms-templates.phtml @@ -6,6 +6,26 @@ depending on the configured locale.

              +

              Custom SMTP server

              +

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

              + +

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

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

              Customize Templates

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

              @@ -17,7 +37,7 @@
            32. Under the Auth service, navigate to the Templates tab.
            33. Expand the email template you want to edit.
            34. Select the Template language. You can have a different template for each language your app supports.
            35. -
            36. Update the email template fields and click **Update** to save your changes.
            37. +
            38. Update the email template fields and click Update to save your changes.

            Email Templates

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

            From 4deefa26750f9512db482ee0795910dea897c9a5 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:58:48 +0100 Subject: [PATCH 170/183] fix: response helper examples --- app/views/docs/functions-develop.phtml | 339 ++++++++++++------------- 1 file changed, 167 insertions(+), 172 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 4f5adbb6e..dc1929220 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -841,8 +841,8 @@ public class Main {
            export default async ({ req, res, log }) => {
             
                 switch (req.query.type) {
            -        case 'text': 
            -            return res.send("This is a text response", 200);
            +        case 'empty': 
            +            return res.empty();
                     case 'json':
                         return res.json({"type": "This is a JSON response"}, 200);
                     case 'redirect':
            @@ -853,7 +853,7 @@ public class Main {
                                 "content-type": "text/html"
                             });
                     default:
            -            return res.empty();
            +            return res.send("This is a text response", 200);
                 }
             }
            @@ -865,8 +865,8 @@ public class Main { return function ($context) { switch ($context->req->query['type']) { - case 'text': - return $context->res->send("This is a text response", 200); + case 'empty': + return $context->res->empty(); case 'json': return $context->res->json(["type" => "This is a JSON response"], 200); case 'redirect': @@ -876,7 +876,7 @@ return function ($context) { "content-type" => "text/html" ]); default: - return $context->res->empty(); + return $context->res->send("This is a text response", 200); } };
            @@ -886,8 +886,8 @@ return function ($context) {
            def main(context):
                 switch context.req.query['type']:
            -        case 'text':
            -            return context.res.send("This is a text response", 200)
            +        case 'empty':
            +            return context.res.empty()
                     case 'json':
                         return context.res.json({"type": "This is a JSON response"}, 200)
                     case 'redirect':
            @@ -897,7 +897,7 @@ return function ($context) {
                             "content-type": "text/html"
                         })
                     default:
            -            return context.res.empty()
            + return context.res.send("This is a text response", 200)
          5. @@ -905,8 +905,8 @@ return function ($context) {
            def main(context)
                 case context.req.query['type'] 
            -        when 'text'
            -            return context.res.send("This is a text response", 200)
            +        when 'empty'
            +            return context.res.empty()
                     when 'json'
                         return context.res.json({"type": "This is a JSON response"}, 200)
                     when 'redirect'
            @@ -916,7 +916,8 @@ return function ($context) {
                             "content-type": "text/html"
                         })
                     else
            -            return context.res.empty()
            +            return context.res.send("This is a text response", 200)
            +            
                 end
             end
            @@ -927,8 +928,8 @@ end
            export default async ({ req, res, log }) => {
             
                 switch (req.query.type) {
            -        case 'text':
            -            return res.send("This is a text response", 200);
            +        case 'empty':
            +            return res.empty();
                     case 'json':
                         return res.json({type": "This is a JSON response"}, 200);
                     case 'redirect':
            @@ -939,7 +940,7 @@ end
            "content-type": "text/html" }); default: - return res.empty(); + return res.send("This is a text response", 200); } } @@ -951,24 +952,18 @@ end Future<dynamic> main(final context) async { switch (context.req.query['type']) { - case 'text': - return context.res - .send('This is a text response', 200); + case 'empty': + return context.res.empty(); case 'json': - return context.res - .json({'type': 'This is a JSON response'}); + return context.res.json({'type': 'This is a JSON response'}); 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(); - } + return context.res.send('This is a text response', 200); + } }
          6. @@ -979,18 +974,18 @@ Future<dynamic> main(final context) async { 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 "empty": + return try await context.res.empty() case "json": - return try await context.send(["type": "This is a JSON response"], 200) + return try await context.res.send(["type": "This is a JSON response"], 200) case "redirect": - return try await context.redirect("https://appwrite.io", 301) + return try await context.res.redirect("https://appwrite.io", 301) case "html": - return try await context.send("<h1>This is an HTML response</h1>", 200, [ + return try await context.res.send("<h1>This is an HTML response</h1>", 200, [ "content-type": "text/html" ]) default: - return try await context.empty() + return try await context.res.send("This is a text response", 200) } } @@ -1005,18 +1000,18 @@ public class Handler { { switch (Context.Request.Query["type"]) { - case "text": - return await Context.Send("This is a text response", 200); + case "empty": + return await Context.Res.Empty(); case "json": - return await Context.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }, 200); + return await Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }, 200); case "redirect": - return await Context.Redirect("https://appwrite.io", 301); + return await Context.Res.Redirect("https://appwrite.io", 301); case "html": - return await Context.Send("<h1>This is an HTML response</h1>", 200, new Dictionary<string, string>() { + return await Context.Res.Send("<h1>This is an HTML response</h1>", 200, new Dictionary<string, string>() { { "content-type", "text/html" } }); - default: - return await Context.Empty(); + default: + return await Context.Res.Send("This is a text response", 200); } } } @@ -1033,11 +1028,11 @@ 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() + "empty" -> return context.res.empty() + "json" -> return context.res.send(mapOf("type" to "This is a JSON response"), 200) + "redirect" -> return context.res.redirect("https://appwrite.io", 301) + "html" -> return context.res.send("<h1>This is an HTML response</h1>", 200, mapOf("content-type" to "text/html")) + else -> return context.res.send("This is a text response", 200) } } } @@ -1057,17 +1052,17 @@ 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); + return context.getRes().empty(); case "json": HashMap<String, Object> data = new HashMap<>(); data.put("type", "This is a JSON response"); - return context.send(data, 200); + return context.getRes().send(data, 200); case "redirect": - return context.redirect("https://appwrite.io", 301); + return context.getRes().redirect("https://appwrite.io", 301); case "html": - return context.send("<h1>This is an HTML response</h1>", 200, Map.of("content-type", "text/html")); + return context.getRes().send("<h1>This is an HTML response</h1>", 200, Map.of("content-type", "text/html")); default: - return context.empty(); + return context.getRes().send("This is a text response", 200); } } } @@ -1087,20 +1082,20 @@ namespace runtime { static RuntimeOutput main(RuntimeContext &context) { std::string type = context.req.query["type"]; - if (type == "text") { - return context.send("This is a text response", 200); + if (type == "empty") { + return context.res.empty(); } else if (type == "json") { Json::Value data; data["type"] = "This is a JSON response"; - return context.send(data, 200); + return context.res.send(data, 200); } else if (type == "redirect") { - return context.redirect("https://appwrite.io", 301); + return context.res.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); + return context.res.send("<h1>This is an HTML response</h1>", 200, headers); } else { - return context.empty(); + return context.res.send("This is a text response", 200); } } }; @@ -1193,7 +1188,7 @@ return function ($context) { 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!") + return context.res.send("Check the Appwrite Console to see logs and errors!")
          7. @@ -1204,7 +1199,7 @@ return function ($context) { 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!") + return context.res.send("Check the Appwrite Console to see logs and errors!") end
          8. @@ -1230,7 +1225,7 @@ Future<dynamic> main(final context) async { 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!"); + return context.res.send("Check the Appwrite Console to see logs and errors!"); } @@ -1244,7 +1239,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { context.log("This function was called with \(context.req.method) method") context.error("This is an error, use for logging errors to console") - return try context.send("Check the Appwrite Console to see logs and errors!") + return context.res.send("Check the Appwrite Console to see logs and errors!") } @@ -1260,7 +1255,7 @@ public class Handler { Context.Log($"This function was called with {Context.Req.Method} method"); Context.Error("This is an error, use for logging errors to console"); - return await Context.Send("Check the Appwrite Console to see logs and errors!"); + return await Context.Res.Send("Check the Appwrite Console to see logs and errors!"); } } @@ -1279,7 +1274,7 @@ class Main { 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!") + return context.res.send("Check the Appwrite Console to see logs and errors!") } } @@ -1298,7 +1293,7 @@ public class Main { 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!"); + return context.getRes().send("Check the Appwrite Console to see logs and errors!"); } } @@ -1319,7 +1314,7 @@ namespace runtime { 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!"); + return context.res.send("Check the Appwrite Console to see logs and errors!"); } }; } @@ -1486,7 +1481,7 @@ Future<dynamic> main(final context) async {
            import Foundation
             
             func main(context: RuntimeContext) async throws -> RuntimeOutput {
            -    return try await context.send(ProcessInfo.processInfo.environment["MY_VAR"], 200)
            +    return await context.res.send(ProcessInfo.processInfo.environment["MY_VAR"], 200)
             }
            @@ -1498,7 +1493,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { public class Handler { public async Task<RuntimeOutput> Main(RuntimeContext Context) { - return await Context.Send(Environment.GetEnvironmentVariable("MY_VAR"), 200); + return await Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR"), 200); } } @@ -1513,7 +1508,7 @@ import io.openruntimes.kotlin.RuntimeOutput class Main { fun main(context: RuntimeContext): RuntimeOutput { - return context.send(System.getenv("MY_VAR"), 200) + return context.res.send(System.getenv("MY_VAR"), 200) } } @@ -1528,7 +1523,7 @@ import io.openruntimes.java.RuntimeOutput; public class Main { public RuntimeOutput main(RuntimeContext context) throws Exception { - return context.send(System.getenv("MY_VAR"), 200); + return context.getRes().send(System.getenv("MY_VAR"), 200); } } @@ -1546,7 +1541,7 @@ namespace runtime { public: static RuntimeOutput main(RuntimeContext &context) { - return context.send(std::getenv("MY_VAR"), 200); + return context.res.send(std::getenv("MY_VAR"), 200); }; } @@ -1559,114 +1554,114 @@ 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:

            - - +
            + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            LanguagePackage ManagerCommands
            LanguagePackage ManagerCommands + Node icon + Node.jsnpmnpm install
            - Node icon - Node.jsnpmnpm install
            - PHP icon - PHPComposercomposer install
            - Python icon - Pythonpippip install -r requirements.txt
            - Ruby icon - RubyBundlerbundle install
            - Deno icon - Denodenodeno cache <ENTRYPOINT_FILE>
            - Dart icon - Dartpubpub get
            - Swift icon - SwiftSwift Package ManagerN/A
            - Swift icon - .NETNuGetN/A
            - Swift icon - KotlinGradleN/A
            - Swift icon - JavaGradleN/A
            - C++ icon - C++NoneN/A
            + + + PHP icon + + PHP + Composer + composer install + + + + Python icon + + Python + pip + pip install -r requirements.txt + + + + Ruby icon + + Ruby + Bundler + bundle install + + + + Deno icon + + Deno + deno + deno cache <ENTRYPOINT_FILE> + + + + Dart icon + + Dart + pub + pub get + + + + Swift icon + + Swift + Swift Package Manager + N/A + + + + Swift icon + + .NET + NuGet + N/A + + + + Swift icon + + Kotlin + Gradle + N/A + + + + Swift icon + + Java + Gradle + N/A + + + + C++ icon + + 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. -

            +

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

            From 4dc3e51bc3ee329fdd5a38d7c9e929b3be0d76b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 29 Aug 2023 14:39:31 +0000 Subject: [PATCH 171/183] Review changes --- app/views/docs/functions-develop.phtml | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index dc1929220..abe69d73b 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -876,7 +876,7 @@ return function ($context) { "content-type" => "text/html" ]); default: - return $context->res->send("This is a text response", 200); + return $context->res->send("This is a text response", 200); } }; @@ -917,7 +917,6 @@ return function ($context) { }) else return context.res.send("This is a text response", 200) - end end @@ -1159,7 +1158,7 @@ namespace runtime {

            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`);
            +    log(`This function was called with ${req.method} method`);
                 error("This is an error, use for logging errors to console");
             
                 return res.send("Check the Appwrite Console to see logs and errors!");
            @@ -1428,7 +1427,7 @@ namespace runtime {
                         

            Node.js

            export default async ({ req, res, log }) => {
            -    return res.send(process.env.MY_VAR, 200);
            +    return res.send(process.env.MY_VAR);
             }
            @@ -1438,7 +1437,7 @@ namespace runtime {
            <?php
             
             return function ($context) {
            -    return $context->res->send(getenv('MY_VAR'), 200);
            +    return $context->res->send(getenv('MY_VAR'));
             };
            @@ -1446,14 +1445,14 @@ return function ($context) {

            Python

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

            def main(context)
            -    return context.res.send(ENV['MY_VAR'], 200)
            +    return context.res.send(ENV['MY_VAR'])
             end
          10. @@ -1461,7 +1460,7 @@ end

            Deno

            export default async ({ req, res, log }) => {
            -    return res.send(Deno.env.get('MY_VAR'), 200);
            +    return res.send(Deno.env.get('MY_VAR'));
             }
            @@ -1471,7 +1470,7 @@ end
            import 'dart:async';
             
             Future<dynamic> main(final context) async {
            -    return context.res.send(Platform.environment['MY_VAR'], 200);
            +    return context.res.send(Platform.environment['MY_VAR']);
             }
            @@ -1481,7 +1480,7 @@ Future<dynamic> main(final context) async {
            import Foundation
             
             func main(context: RuntimeContext) async throws -> RuntimeOutput {
            -    return await context.res.send(ProcessInfo.processInfo.environment["MY_VAR"], 200)
            +    return await context.res.send(ProcessInfo.processInfo.environment["MY_VAR"])
             }
            @@ -1493,7 +1492,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { public class Handler { public async Task<RuntimeOutput> Main(RuntimeContext Context) { - return await Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR"), 200); + return await Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR")); } } @@ -1508,7 +1507,7 @@ import io.openruntimes.kotlin.RuntimeOutput class Main { fun main(context: RuntimeContext): RuntimeOutput { - return context.res.send(System.getenv("MY_VAR"), 200) + return context.res.send(System.getenv("MY_VAR")) } } @@ -1523,7 +1522,7 @@ import io.openruntimes.java.RuntimeOutput; public class Main { public RuntimeOutput main(RuntimeContext context) throws Exception { - return context.getRes().send(System.getenv("MY_VAR"), 200); + return context.getRes().send(System.getenv("MY_VAR")); } } @@ -1541,7 +1540,7 @@ namespace runtime { public: static RuntimeOutput main(RuntimeContext &context) { - return context.res.send(std::getenv("MY_VAR"), 200); + return context.res.send(std::getenv("MY_VAR")); }; } @@ -2348,7 +2347,7 @@ export function add(a, b) { import { add } from './utils.js'; -export default function ({res}) { +export default function ({ res }) { return res.send(add(1, 2)); } From d6d63a639440f8d59f9eb6a32c8f5553bf8cee1d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:40:11 +0100 Subject: [PATCH 172/183] fix: remove duplicate python example + add missing php --- app/views/docs/functions-examples.phtml | 86 +++++++++++-------------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml index 485c4fe3b..96af6e772 100644 --- a/app/views/docs/functions-examples.phtml +++ b/app/views/docs/functions-examples.phtml @@ -139,6 +139,43 @@ export default async function ({ req, res }) { +
          11. +

            PHP

            +
            +

            +

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

            @@ -555,55 +592,6 @@ Future main(final context) async {
          13. -
          14. -

            Python

            -
            -

            -

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

    From 5e5061cb96002dcb87e9d020a7a1e1db9bf9b562 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:44:45 +0100 Subject: [PATCH 173/183] chore: remove unneccessary 200 codes --- app/views/docs/functions-develop.phtml | 42 ++++++++++++------------- app/views/docs/functions-examples.phtml | 10 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index abe69d73b..77ff76a59 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -844,7 +844,7 @@ public class Main { case 'empty': return res.empty(); case 'json': - return res.json({"type": "This is a JSON response"}, 200); + return res.json({"type": "This is a JSON response"}); case 'redirect': return res.redirect("https://appwrite.io", 301); case 'html': @@ -853,7 +853,7 @@ public class Main { "content-type": "text/html" }); default: - return res.send("This is a text response", 200); + return res.send("This is a text response"); } } @@ -868,7 +868,7 @@ return function ($context) { case 'empty': return $context->res->empty(); case 'json': - return $context->res->json(["type" => "This is a JSON response"], 200); + return $context->res->json(["type" => "This is a JSON response"]); case 'redirect': return $context->res->redirect("https://appwrite.io", 301); case 'html': @@ -876,7 +876,7 @@ return function ($context) { "content-type" => "text/html" ]); default: - return $context->res->send("This is a text response", 200); + return $context->res->send("This is a text response"); } }; @@ -889,7 +889,7 @@ return function ($context) { case 'empty': return context.res.empty() case 'json': - return context.res.json({"type": "This is a JSON response"}, 200) + return context.res.json({"type": "This is a JSON response"}) case 'redirect': return context.res.redirect("https://appwrite.io", 301) case 'html': @@ -897,7 +897,7 @@ return function ($context) { "content-type": "text/html" }) default: - return context.res.send("This is a text response", 200) + return context.res.send("This is a text response")

  • @@ -908,7 +908,7 @@ return function ($context) { when 'empty' return context.res.empty() when 'json' - return context.res.json({"type": "This is a JSON response"}, 200) + return context.res.json({"type": "This is a JSON response"}) when 'redirect' return context.res.redirect("https://appwrite.io", 301) when 'html' @@ -916,7 +916,7 @@ return function ($context) { "content-type": "text/html" }) else - return context.res.send("This is a text response", 200) + return context.res.send("This is a text response") end end @@ -930,7 +930,7 @@ end case 'empty': return res.empty(); case 'json': - return res.json({type": "This is a JSON response"}, 200); + return res.json({type": "This is a JSON response"}); case 'redirect': return res.redirect("https://appwrite.io", 301); case 'html': @@ -939,7 +939,7 @@ end "content-type": "text/html" }); default: - return res.send("This is a text response", 200); + return res.send("This is a text response"); } } @@ -961,7 +961,7 @@ Future<dynamic> main(final context) async { return context.res.send('<h1>This is an HTML response</h1>', 200, {'content-type': 'text/html'}); default: - return context.res.send('This is a text response', 200); + return context.res.send('This is a text response'); } } @@ -976,7 +976,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { case "empty": return try await context.res.empty() case "json": - return try await context.res.send(["type": "This is a JSON response"], 200) + return try await context.res.send(["type": "This is a JSON response"]) case "redirect": return try await context.res.redirect("https://appwrite.io", 301) case "html": @@ -984,7 +984,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { "content-type": "text/html" ]) default: - return try await context.res.send("This is a text response", 200) + return try await context.res.send("This is a text response") } } @@ -1002,7 +1002,7 @@ public class Handler { case "empty": return await Context.Res.Empty(); case "json": - return await Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }, 200); + return await Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }); case "redirect": return await Context.Res.Redirect("https://appwrite.io", 301); case "html": @@ -1010,7 +1010,7 @@ public class Handler { { "content-type", "text/html" } }); default: - return await Context.Res.Send("This is a text response", 200); + return await Context.Res.Send("This is a text response"); } } } @@ -1028,10 +1028,10 @@ class Main { fun main(context: RuntimeContext): RuntimeOutput { when (context.req.query["type"]) { "empty" -> return context.res.empty() - "json" -> return context.res.send(mapOf("type" to "This is a JSON response"), 200) + "json" -> return context.res.send(mapOf("type" to "This is a JSON response")) "redirect" -> return context.res.redirect("https://appwrite.io", 301) "html" -> return context.res.send("<h1>This is an HTML response</h1>", 200, mapOf("content-type" to "text/html")) - else -> return context.res.send("This is a text response", 200) + else -> return context.res.send("This is a text response") } } } @@ -1055,13 +1055,13 @@ public class Main { case "json": HashMap<String, Object> data = new HashMap<>(); data.put("type", "This is a JSON response"); - return context.getRes().send(data, 200); + return context.getRes().send(data); case "redirect": return context.getRes().redirect("https://appwrite.io", 301); case "html": return context.getRes().send("<h1>This is an HTML response</h1>", 200, Map.of("content-type", "text/html")); default: - return context.getRes().send("This is a text response", 200); + return context.getRes().send("This is a text response"); } } } @@ -1086,7 +1086,7 @@ namespace runtime { } else if (type == "json") { Json::Value data; data["type"] = "This is a JSON response"; - return context.res.send(data, 200); + return context.res.send(data); } else if (type == "redirect") { return context.res.redirect("https://appwrite.io", 301); } else if (type == "html") { @@ -1094,7 +1094,7 @@ namespace runtime { headers["content-type"] = "text/html"; return context.res.send("<h1>This is an HTML response</h1>", 200, headers); } else { - return context.res.send("This is a text response", 200); + return context.res.send("This is a text response"); } } }; diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml index 96af6e772..cc0fed6fb 100644 --- a/app/views/docs/functions-examples.phtml +++ b/app/views/docs/functions-examples.phtml @@ -684,7 +684,7 @@ export default async function ({ req, res }) { 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("Message sent"); } return res.send('Not found', 404); @@ -743,7 +743,7 @@ def main(context): 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("Message sent") return context.res.send('Not found', 404) @@ -803,7 +803,7 @@ return function ($context) { $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("Message sent"); } return $context->res->send('Not found', 404); @@ -858,7 +858,7 @@ def main(context) databases = Appwrite::Database.new(client) document = databases.create_document('[DATABASE_ID]', '[MESSAGES_COLLECTION_ID]', ID.unique(), message) - return context.res.send("Message sent", 200) + return context.res.send("Message sent") end return context.res.send('Not found', 404) @@ -913,7 +913,7 @@ Future main(final context) async { 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("Message sent"); } return context.res.send('Not found', 404); From 5d6d411360946e31d052c4750eab508d8f51e476 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:24:22 +0100 Subject: [PATCH 174/183] fix: standardise appwrite sdk setup for python --- app/views/docs/functions-examples.phtml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/views/docs/functions-examples.phtml b/app/views/docs/functions-examples.phtml index cc0fed6fb..0fdabae89 100644 --- a/app/views/docs/functions-examples.phtml +++ b/app/views/docs/functions-examples.phtml @@ -398,10 +398,12 @@ def main(context): if vote['vote'] != 'yes' and vote['vote'] != 'no': return context.res.json({'ok': False, 'message': 'You must vote yes or no.'}, 400) - client = Client() - client.set_endpoint('https://cloud.appwrite.io/v1') - client.set_project(os.environ['APPWRITE_FUNCTION_PROJECT_ID']) - client.set_key(os.environ['APPWRITE_API_KEY']) + client = ( + Client() + .set_endpoint("https://cloud.appwrite.io/v1") + .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) + .set_key(os.environ["APPWRITE_API_KEY"]) + ) database = Databases(client) @@ -734,10 +736,10 @@ def main(context): } client = ( - Client() - .set_endpoint('https://cloud.appwrite.io/v1') - .set_project(os.environ['APPWRITE_FUNCTION_PROJECT_ID']) - .set_key(os.environ['APPWRITE_API_KEY']) + 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) From 1678f8e58ff00b9a3c0b6e32c84dcee734c5a226 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:44:10 +0100 Subject: [PATCH 175/183] fix: python code splitting --- 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 77ff76a59..63664e37a 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -2383,10 +2383,10 @@ def add(a, b):
    // src/main.py
     
    -import utils
    +from .utils import add
     
     def main(context):
    -    return context.res.send(utils.add(1, 2))
    + return context.res.send(add(1, 2))
  • From 31598efbf8e4259a47b12c9c9f738d840ea6708a Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 29 Aug 2023 13:19:42 -0400 Subject: [PATCH 176/183] Fix try/awaits --- app/views/docs/functions-develop.phtml | 48 ++++++++++++-------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 63664e37a..42b8d4f19 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -171,14 +171,12 @@ def main(context) 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", - } - ) + 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
  • @@ -286,7 +284,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { 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!") + return context.res.send("Hello, World!") } // `context.res.json()` is a handy helper for sending JSON @@ -671,7 +669,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { context.log(context.req.queryString) // Raw query params string. For example "limit=12&offset=50" context.log(NSJSONSerialization.jsonObject(with: context.req.query, options: [])!) // Parsed query params. For example, req.query.limit - return try context.res.send("All the request parameters are logged to the Appwrite Console.") + return context.res.send("All the request parameters are logged to the Appwrite Console.") }
    @@ -974,17 +972,17 @@ Future<dynamic> main(final context) async { func main(context: RuntimeContext) async throws -> RuntimeOutput { switch context.req.query["type"] { case "empty": - return try await context.res.empty() + return context.res.empty() case "json": - return try await context.res.send(["type": "This is a JSON response"]) + return context.res.send(["type": "This is a JSON response"]) case "redirect": - return try await context.res.redirect("https://appwrite.io", 301) + return context.res.redirect("https://appwrite.io", 301) case "html": - return try await context.res.send("<h1>This is an HTML response</h1>", 200, [ + return context.res.send("<h1>This is an HTML response</h1>", 200, [ "content-type": "text/html" ]) default: - return try await context.res.send("This is a text response") + return context.res.send("This is a text response") } } @@ -1000,17 +998,17 @@ public class Handler { switch (Context.Request.Query["type"]) { case "empty": - return await Context.Res.Empty(); + return Context.Res.Empty(); case "json": - return await Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }); + return Context.Res.Send(new Dictionary<string, object>() { { "type", "This is a JSON response" } }); case "redirect": - return await Context.Res.Redirect("https://appwrite.io", 301); + return Context.Res.Redirect("https://appwrite.io", 301); case "html": - return await Context.Res.Send("<h1>This is an HTML response</h1>", 200, new Dictionary<string, string>() { + return Context.Res.Send("<h1>This is an HTML response</h1>", 200, new Dictionary<string, string>() { { "content-type", "text/html" } }); default: - return await Context.Res.Send("This is a text response"); + return Context.Res.Send("This is a text response"); } } } @@ -1156,7 +1154,7 @@ namespace runtime {
  • Node.js

    -
    export default async ({ res, log, error }) => {
    +                
    export default async ({ req, res, log, error }) => {
         log("This is a log, use for logging information to console");
         log(`This function was called with ${req.method} method`);
         error("This is an error, use for logging errors to console");
    @@ -1254,7 +1252,7 @@ public class Handler {
             Context.Log($"This function was called with {Context.Req.Method} method");
             Context.Error("This is an error, use for logging errors to console");
     
    -        return await Context.Res.Send("Check the Appwrite Console to see logs and errors!");
    +        return Context.Res.Send("Check the Appwrite Console to see logs and errors!");
         }
     }
    @@ -1480,7 +1478,7 @@ Future<dynamic> main(final context) async {
    import Foundation
     
     func main(context: RuntimeContext) async throws -> RuntimeOutput {
    -    return await context.res.send(ProcessInfo.processInfo.environment["MY_VAR"])
    +    return context.res.send(ProcessInfo.processInfo.environment["MY_VAR"])
     }
  • @@ -1492,7 +1490,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { public class Handler { public async Task<RuntimeOutput> Main(RuntimeContext Context) { - return await Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR")); + return Context.Res.Send(Environment.GetEnvironmentVariable("MY_VAR")); } } @@ -1862,7 +1860,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:]) } catch { context.error("Failed to create document: \(error.localizedDescription)") - return try await context.res.send("Failed to create document") + return context.res.send("Failed to create document") } return context.res.send("Document created") From 66ddf617a3d278614c7d5bb9b21d3b1566ba12a0 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 29 Aug 2023 13:23:30 -0400 Subject: [PATCH 177/183] ctx -> context --- app/views/docs/functions-develop.phtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index 42b8d4f19..7309b25fc 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -124,13 +124,13 @@ def main(context): # If something goes wrong, log an error context.error("Hello, Errors!") - # The `ctx.req` object contains the request data + # The `context.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 + # `context.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 + # `context.res.json()` is a handy helper for sending JSON return context.res.json( { "motto": "Build Fast. Scale Big. All in One Place.", @@ -163,14 +163,14 @@ def main(context) # If something goes wrong, log an error context.error("Hello, Errors!") - # The `ctx.req` object contains the request data + # The `context.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 + # `context.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 + # `context.res.json()` is a handy helper for sending JSON return context.res.json({ "motto": "Build Fast. Scale Big. All in One Place.", "learn": "https://appwrite.io/docs", @@ -765,7 +765,7 @@ 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. + These are provided alongside any custom headers sent to the function.

    From 9935d70c698adedc355b52626f17735f4866fdb5 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 29 Aug 2023 13:23:39 -0400 Subject: [PATCH 178/183] Fix mismatched tags --- 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 7309b25fc..efef145bf 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -762,7 +762,7 @@ public class Main { -

    Headers

    +

    Headers

    Appwrite Functions will always receive a set of headers that provide meta data about the function execution. These are provided alongside any custom headers sent to the function. From 81749e9eaf9ce5fce813e33cb316d8a45bae8d07 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 29 Aug 2023 20:11:44 +0000 Subject: [PATCH 179/183] Add blub about self-hosted git integration --- app/views/docs/configuration.phtml | 49 ++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/app/views/docs/configuration.phtml b/app/views/docs/configuration.phtml index 44f0132e1..f235bf2e1 100644 --- a/app/views/docs/configuration.phtml +++ b/app/views/docs/configuration.phtml @@ -19,6 +19,51 @@

    Set up SMS delivery

    +

    Configure GitHub App

    +

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

    + +

    You'll have to configure the following environment variables.

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

    Learn more about environment variables

    +

    Configure Function Runtimes

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

    Storage Adaptors

    Appwrite's Storage Service can be configured to store files locally, or with self-hosted and cloud storage services. By default, Appwrite's Storage Service stores files on your server's local storage. If you expect large volumes of data or the need to have scalable data storage, you may choose to use a separate storage service.

    -

    Appwrite supports AWS S3, Digital Ocean Spaces, Backblaze, Akamai Object Storage, and Wasabi as storage adaptors. Some of these services can be self-hosted, just like Appwrite.

    +

    Appwrite supports AWS S3, Digital Ocean Spaces, Backblaze, Linode, and Wasabi as storage adaptors. Some of these services can be self-hosted, just like Appwrite.

    You can select which storage adaptor to use by setting the _APP_STORAGE_DEVICE environment variable. Valid values are local, s3, dospaces, backblaze, linode and wasabi. Each storage adaptor requires its own set of additional environment variables to configure.

    @@ -62,4 +107,4 @@

    More Configurable Options

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

    -

    Learn more about environment variables

    +

    Learn more about environment variables

    \ No newline at end of file From 476486305e696aec78bddaca782b3250078b9b48 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 29 Aug 2023 16:13:20 -0400 Subject: [PATCH 180/183] revert change from akamai to linode --- app/views/docs/configuration.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/configuration.phtml b/app/views/docs/configuration.phtml index f235bf2e1..34c52eeb2 100644 --- a/app/views/docs/configuration.phtml +++ b/app/views/docs/configuration.phtml @@ -85,7 +85,7 @@

    Storage Adaptors

    Appwrite's Storage Service can be configured to store files locally, or with self-hosted and cloud storage services. By default, Appwrite's Storage Service stores files on your server's local storage. If you expect large volumes of data or the need to have scalable data storage, you may choose to use a separate storage service.

    -

    Appwrite supports AWS S3, Digital Ocean Spaces, Backblaze, Linode, and Wasabi as storage adaptors. Some of these services can be self-hosted, just like Appwrite.

    +

    Appwrite supports AWS S3, Digital Ocean Spaces, Backblaze, Akamai Object Storage, and Wasabi as storage adaptors. Some of these services can be self-hosted, just like Appwrite.

    You can select which storage adaptor to use by setting the _APP_STORAGE_DEVICE environment variable. Valid values are local, s3, dospaces, backblaze, linode and wasabi. Each storage adaptor requires its own set of additional environment variables to configure.

    From b00f36757245f3d0a63e44a341965326e0fdac98 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Tue, 29 Aug 2023 21:00:46 +0000 Subject: [PATCH 181/183] Fix width for configuration.phtml --- app/views/docs/configuration.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/configuration.phtml b/app/views/docs/configuration.phtml index 34c52eeb2..9a0fc31f7 100644 --- a/app/views/docs/configuration.phtml +++ b/app/views/docs/configuration.phtml @@ -30,7 +30,7 @@ - + From 87a27b061c4692afcd7ca952b75096aa4886d59e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 29 Aug 2023 17:11:06 -0400 Subject: [PATCH 182/183] WIP fix code samples --- app/views/docs/authentication-anonymous.phtml | 8 +- .../docs/authentication-email-pass.phtml | 151 ++-- app/views/docs/authentication-magic.phtml | 5 +- .../docs/authentication-management.phtml | 179 ++--- app/views/docs/authentication-oauth.phtml | 32 +- app/views/docs/authentication-server.phtml | 225 +++--- app/views/docs/authentication-sms.phtml | 29 +- app/views/docs/functions-develop.phtml | 658 ++++++++++-------- app/views/docs/functions-execute.phtml | 374 +++++----- .../docs/getting-started-for-server.phtml | 6 +- 10 files changed, 859 insertions(+), 808 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index a64394aca..97aa74381 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -22,7 +22,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -42,7 +42,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -57,7 +57,7 @@ import io.appwrite.services.Account val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -71,7 +71,7 @@ val user = account.createAnonymousSession() let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 8fde1db9a..2f6604c93 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -89,8 +89,7 @@ let user = try await account.create(
  • GraphQL

    -
    
    -mutation {
    +            
    mutation {
         accountCreate(userId: "unique()", email: "email@example.com", password: "password") {
             _id
             email
    @@ -124,21 +123,18 @@ mutation {
             
    import { Client, Account } from "appwrite";
     
    -const client = new Client();
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
     
     const account = new Account(client);
     
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -;
    -
     const promise = account.createVerification('https://example.com');
     
     promise.then(function (response) {
    -    console.log(response); // Success
    +    console.log(response);
     }, function (error) {
    -    console.log(error); // Failure
    +    console.log(error);
     });
  • @@ -147,55 +143,31 @@ promise.then(function (response) {
    import 'package:appwrite/appwrite.dart';
     
    -void main() { // Init SDK
    -  Client client = Client();
    -  Account account = Account(client);
    -
    -  client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -  ;
    -  Future result = account.createVerification(
    +    .setProject('5df5acd0d48c2');                // Your project ID
    +
    +final account = Account(client);
    +
    +final token = await account.createVerification(
         url: 'https://example.com',
    -  );
    -
    -  result
    -    .then((response) {
    -      print(response);
    -    }).catchError((error) {
    -      print(error.response);
    -  });
    -}
    +);
  • Android

    -
    import androidx.appcompat.app.AppCompatActivity
    -import android.os.Bundle
    -import kotlinx.coroutines.GlobalScope
    -import kotlinx.coroutines.launch
    -import io.appwrite.Client
    +            
    import io.appwrite.Client
     import io.appwrite.services.Account
     
    -class MainActivity : AppCompatActivity() {
    -    override fun onCreate(savedInstanceState: Bundle?) {
    -        super.onCreate(savedInstanceState)
    -        setContentView(R.layout.activity_main)
    -
    -        val client = Client(applicationContext)
    -            .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -            .setProject("5df5acd0d48c2") // Your project ID
    +val client = Client(applicationContext)
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
     
    -        val account = Account(client)
    +val account = Account(client)
     
    -        GlobalScope.launch {
    -            val response = account.createVerification(
    -                url = "https://example.com"
    -            )
    -            val json = response.body?.string()        
    -        }
    -    }
    -}
    +val token = account.createVerification( + url = "https://example.com" +)
  • @@ -203,17 +175,15 @@ class MainActivity : AppCompatActivity() {
    import Appwrite
     
    -func main() async throws {
    -    let client = Client()
    -      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -      .setProject("5df5acd0d48c2") // Your project ID
    -    let account = Account(client)
    -    let token = try await account.createVerification(
    -        url: "https://example.com"
    -    )
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
     
    -    print(String(describing: token)
    -}
    +let account = Account(client) + +let token = try await account.createVerification( + url: "https://example.com" +)
  • @@ -252,7 +222,7 @@ func main() async throws { const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -274,26 +244,16 @@ promise.then(function (response) {
    import 'package:appwrite/appwrite.dart';
     
    -void main() { // Init SDK
    -  Client client = Client();
    -  Account account = Account(client);
    -
    -  client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -  ;
    -  Future result = account.updateVerification(
    +    .setProject('5df5acd0d48c2');                // Your project ID
    +
    +final account = Account(client);
    +
    +final result = account.updateVerification(
         userId: '[USER_ID]',
         secret: '[SECRET]',
    -  );
    -
    -  result
    -    .then((response) {
    -      print(response);
    -    }).catchError((error) {
    -      print(error.response);
    -  });
    -}
    +);
  • Android

    @@ -303,7 +263,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID + .setProject("5df5acd0d48c2") // Your project ID val account = Account(client) @@ -320,7 +280,7 @@ val response = account.updateVerification( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID + .setProject("5df5acd0d48c2") // Your project ID let account = Account(client) @@ -364,7 +324,7 @@ let token = try await account.updateVerification( const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -384,7 +344,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -401,7 +361,7 @@ import io.appwrite.services.Account val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -417,7 +377,7 @@ val session = account.createEmailSession( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -458,7 +418,7 @@ let session = try await account.createEmailSession( const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const promise = account.createRecovery('email@example.com', 'https://example.com'); @@ -476,7 +436,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -493,7 +453,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -509,7 +469,7 @@ val response = account.createRecovery( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -549,9 +509,14 @@ After receiving an email with the secret attached to the redirect link, submit a const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID -const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); +const promise = account.updateRecovery( + '[USER_ID]', + '[SECRET]', + 'password', + 'password' +); promise.then(function (response) { console.log(response); // Success @@ -567,7 +532,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -586,7 +551,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -604,7 +569,7 @@ val token = account.updateRecovery( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -638,7 +603,7 @@ let token = try await account.updateRecovery(

    Security

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

    diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 0c25a3a0d..d126549c6 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -20,11 +20,10 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); - const promise = account.createMagicURLSession(ID.unique(), 'email@example.com'); promise.then(function (response) { @@ -67,7 +66,7 @@ promise.then(function (response) { const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index d0b15fb2a..e9a083910 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -22,7 +22,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -42,7 +42,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -61,12 +61,15 @@ import io.appwrite.services.Account val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) val user = account.updatePrefs( - prefs = mapOf("darkTheme" to true, "language" to "en") + prefs = mapOf( + "darkTheme" to true, + "language" to "en" + ) )
  • @@ -76,12 +79,15 @@ val user = account.updatePrefs( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) let user = try await account.updatePrefs( - prefs: ["darkTheme": true, "language": "en"] + prefs: [ + "darkTheme": true, + "language": "en" + ] )
  • @@ -112,7 +118,7 @@ let user = try await account.updatePrefs( const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -132,7 +138,7 @@ promise.then(function (response) { final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -146,7 +152,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -159,7 +165,7 @@ val prefs = account.getPrefs() let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -207,19 +213,18 @@ let prefs = try await account.getPrefs()

    Node.js

    const sdk = require('node-appwrite');
    -
    -// Init SDK
    -const client = new sdk.Client();
    +                    
    +const client = new sdk.Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
     const users = new sdk.Users(client);
     
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
    -;
    -
    -const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
    +const promise = users.updateLabels(
    +    '[USER_ID]',
    +    [ Role.label('subscriber') ]
    +);
     
     promise.then(function (response) {
         console.log(response); // Success
    @@ -240,17 +245,14 @@ $client = new Client();
     
     $client
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
    -;
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
     $users = new Users($client);
     
     $result = $users->updateLabels(
         '[USER_ID]', 
    -    [
    -        Role.label('subscriber'),
    -    ]
    +    [ Role.label('subscriber') ]
     );
  • @@ -265,32 +267,36 @@ client = Client() (client .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('5df5acd0d48c2') # Your project ID - .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + .set_project('5df5acd0d48c2') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key ) users = Users(client) -result = users.update_labels('[USER_ID]', [ Role.label('subscriber') ]) +result = users.update_labels( + '[USER_ID]', + [ Role.label('subscriber') ] +)
  • Ruby

    -
    require 'Appwrite'
    +            
    require 'appwrite'
     
     include Appwrite
     
     client = Client.new
         .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint
    -    .set_project('5df5acd0d48c2') # Your project ID
    -    .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key
    +    .set_project('5df5acd0d48c2')                 # Your project ID
    +    .set_key('98fd4...a2ad2')                     # Your secret API key
     
     users = Users.new(client)
     
    -response = users.update_labels(user_id: '[USER_ID]', labels: [ Role.label('subscriber') ])
    -
    -puts response.inspect
    +response = users.update_labels( + user_id: '[USER_ID]', + labels: [ Role.label('subscriber') ] +)
  • @@ -298,19 +304,17 @@ puts response.inspect
    import * as sdk from "https://deno.land/x/appwrite/mod.ts";
     
    -// Init SDK
    -let client = new sdk.Client();
    -
    -let users = new sdk.Users(client);
    -
    -client
    +let client = new sdk.Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
    -;
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
    +let users = new sdk.Users(client);
     
    -const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
    +const promise = users.updateLabels(
    +    '[USER_ID]',
    +    [ Role.label('subscriber') ]
    +);
     
     promise.then(function (response) {
         console.log(response); // Success
    @@ -324,50 +328,37 @@ promise.then(function (response) {
             
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -void main() { // Init SDK
    -  Client client = Client();
    -  Users users = Users(client);
    -
    -  client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
    -  ;
    +    .setProject('5df5acd0d48c2')                 // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
    -  Future result = users.updateLabels(
    +final users = Users(client);
    +
    +final result = await users.updateLabels(
         userId: '[USER_ID]',
         labels: [ Role.label('subscriber') ],
    -  );
    -
    -  result
    -    .then((response) {
    -      print(response);
    -    }).catchError((error) {
    -      print(error.response);
    -  });
    -}
    +);
  • Kotlin

    import io.appwrite.Client
    -import io.appwrite.services.Users
     import io.appwrite.Role
    +import io.appwrite.services.Users
     
    -suspend fun main() {
    -    val client = Client(context)
    -      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -      .setProject("5df5acd0d48c2") // Your project ID
    -      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
    +val client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +    .setKey("98fd4...a2ad2")                     // Your secret API key
     
    -    val users = Users(client)
    -    val response = users.updateLabels(
    -        userId = "[USER_ID]",
    -        labels = [ Role.label('subscriber') ]
    -    )
    -    val json = response.body?.string()
    -}
    +val users = Users(client) + +val response = users.updateLabels( + userId = "[USER_ID]", + labels = [ Role.label('subscriber') ] +)
  • @@ -375,25 +366,35 @@ suspend fun main() {
    import Appwrite
     
    -func main() async throws {
    -    let client = Client()
    -      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    -      .setProject("5df5acd0d48c2") // Your project ID
    -      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
    -    let users = Users(client)
    -    let response = try await users.updateLabels(
    -        userId: "[USER_ID]",
    -        labels: [ Role.label('subscriber') ]
    -    )
    +let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("5df5acd0d48c2")                 // Your project ID
    +    .setKey("98fd4...a2ad2")                     // Your secret API key
     
    -    print(String(describing: response)
    -}
    +let users = Users(client) + +let response = try await users.updateLabels( + userId: "[USER_ID]", + labels: [ Role.label('subscriber') ] +)
  • .NET

    -
    +
    using Appwrite;
    +
    +var client = new Client()
    +    .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .SetProject("5df5acd0d48c2")                 // Your project ID
    +    .SetKey("98fd4...a2ad2");                    // Your secret API key
    +
    +var users = new Users(client);
    +
    +var response = await users.UpdateLabels(
    +    userId: "[USER_ID]",
    +    labels: [ Role.Label('subscriber') ]
    +);
  • diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 53b77ae2d..b2937de3c 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -39,7 +39,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -90,7 +90,7 @@ import io.appwrite.services.Account val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -316,25 +316,15 @@ promise.then(function (response) {
    import 'package:appwrite/appwrite.dart';
     
    -void main() { // Init SDK
    -  Client client = Client();
    -  Account account = Account(client);
    -
    -  client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('5df5acd0d48c2') // Your project ID
    -  ;
    -  Future result = account.updateSession(
    -    sessionId: '[SESSION_ID]',
    -  );
    -
    -  result
    -    .then((response) {
    -      print(response);
    -    }).catchError((error) {
    -      print(error.response);
    -  });
    -}
    + .setProject('5df5acd0d48c2'); // Your project ID + +Account account = Account(client); + +final result = await account.updateSession( + sessionId: '[SESSION_ID]' +);
  • @@ -345,7 +335,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID + .setProject("5df5acd0d48c2") // Your project ID val account = Account(client) diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index de1c90211..52c2e1ff9 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -95,9 +95,7 @@ let jwt = try await account.createJWT()
    const { Client } = require('node-appwrite');
     
    -const client = new Client();
    -
    -client
    +const client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
         .setProject('[PROJECT_ID]')                  // Your project ID
         .setJWT('eyJJ9.eyJ...886ca');                // Your secret JSON Web Token
    @@ -109,9 +107,7 @@ client
    use Appwrite\Client;
     
    -$client = new Client();
    -
    -$client
    +$client = (new Client())
         ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
         ->setProject('[PROJECT_ID]')                             // Your project ID
         ->setJWT('eyJJ9.eyJ...886ca');                           // Your secret JSON Web Token
    @@ -139,8 +135,6 @@ client = Client() include Appwrite client = Client.new - -client .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint .set_project('[PROJECT_ID]') # Your project ID .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token @@ -151,9 +145,7 @@ client
    import { Client } from "https://deno.land/x/appwrite/mod.ts";
     
    -let client = new Client();
    -
    -client
    +let client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
         .setProject('[PROJECT_ID]')                     // Your project ID
         .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
    @@ -164,9 +156,7 @@ client
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -final client = Client();
    -
    -client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
         .setProject('[PROJECT_ID]')                     // Your project ID
         .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
    @@ -178,8 +168,6 @@ client
    import io.appwrite.Client
     
     val client = Client()
    -
    -client
         .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
         .setProject("[PROJECT_ID]")                     // Your project ID
         .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
    @@ -191,8 +179,6 @@ client
    import Appwrite
     
     let client = Client()
    -
    -client
         .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
         .setProject("[PROJECT_ID]")                     // Your project ID
         .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
    @@ -203,9 +189,7 @@ client
    using Appwrite;
     
    -var client = new Client();
    -
    -client
    +var client = new Client()
         .SetEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
         .SetProject("[PROJECT_ID]")                     // Your project ID
         .SetJWT("eyJJ9.eyJ...886ca");                   // Your secret JSON Web Token
    @@ -263,16 +247,17 @@ client
    const { Client } = require('node-appwrite');
     
    -const client = new Client();
    -
    -client
    +const client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                // Your project ID
    -    .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    +    .setProject('[PROJECT_ID]')                  // Your project ID
    +    .setJWT('eyJJ9.eyJ...886ca');                // Your secret JSON Web Token
     
     const databases = new sdk.Databases(client);
     
    -const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +const documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
  • @@ -282,16 +267,17 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592
    use Appwrite\Client;
     
    -$client = new Client();
    -
    -$client
    +$client = (new Client())
         ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
         ->setProject('[PROJECT_ID]')                           // Your project ID
         ->setJWT('eyJJ9.eyJ...886ca');                          // Your secret JSON Web Tokens
     
     $databases = new Databases($client);
     
    -$result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +$documents = $databases->listDocuments(
    +    databaseId: '642f358bf4084c662590',
    +    collectionId: '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -310,7 +296,10 @@ client = Client() databases = Databases(client) -result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id='642f358bf4084c662590', + collection_id='642f3592aa5fc856ad1e' +) # ... More code to manipulate the results @@ -322,16 +311,17 @@ result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e' include Appwrite -client = Client - -client.new +client = Client.new .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint .set_project('[PROJECT_ID]') # Your project ID .set_jwt('eyJJ9.eyJ...886ca') # Your secret JSON Web Token databases = Databases.new(client) -response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id: '642f358bf4084c662590', + collection_id: '642f3592aa5fc856ad1e' +) # ... More code to manipulate the results @@ -340,16 +330,17 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35
    import { Client } from "https://deno.land/x/appwrite/mod.ts";
     
    -let client = new Client();
    -
    -client
    +let client = new Client()
         .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
         .setProject('[PROJECT_ID]')                     // Your project ID
         .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
     
     let databases = new sdk.Databases(client);
     
    -let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +let documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -358,16 +349,14 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -final client = Client();
    -
    -client
    +final client = Client()
         .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
         .setProject('[PROJECT_ID]')                     // Your project ID
         .setJWT('eyJJ9.eyJ...886ca');                   // Your secret JSON Web Token
     
    -Databases databases = Databases(client);
    +final databases = Databases(client);
     
    -Future result = databases.listDocuments(
    +final documents = await databases.listDocuments(
         databaseId: '642f358bf4084c662590',
         collectionId: '642f3592aa5fc856ad1e',
     );
    @@ -380,15 +369,13 @@ Future result = databases.listDocuments(
                 
    import io.appwrite.Client
     
     val client = Client()
    -
    -client
         .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
         .setProject("[PROJECT_ID]")                     // Your project ID
         .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
     
     val databases = Databases(client)
     
    -val response = databases.listDocuments(
    +val documents = databases.listDocuments(
         databaseId = "642f358bf4084c662590",
         collectionId = "642f3592aa5fc856ad1e",
     )
    @@ -401,19 +388,17 @@ val response = databases.listDocuments(
                 
    import Appwrite
     
     let client = Client()
    -
    -client
         .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
         .setProject("[PROJECT_ID]")                     // Your project ID
         .setJWT("eyJJ9.eyJ...886ca")                    // Your secret JSON Web Token
         
     let databases = Databases(client)
     
    -let documentList = try await databases.listDocuments(
    +let documents = try await databases.listDocuments(
         databaseId: "642f358bf4084c662590",
         collectionId: "642f3592aa5fc856ad1e"
     )
    -/ ... More code to manipulate the results
    +// ... More code to manipulate the results
  • @@ -423,16 +408,14 @@ let documentList = try await databases.listDocuments( using Appwrite.Services; using Appwrite.Models; -var client = new Client(); - -client +var client = new Client() .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint .SetProject("[PROJECT_ID]") // Your project ID .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token var databases = new Databases(client); -var documentList = await databases.ListDocuments( +var documents = await databases.ListDocuments( databaseId: "642f358bf4084c662590", collectionId: "642f3592aa5fc856ad1e"); @@ -468,16 +451,17 @@ var documentList = await databases.ListDocuments(
    const { Client } = require('node-appwrite');
     
    -const client = new Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                     // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')    // Your secret API key
    +const client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]')                  // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
     const databases = new sdk.Databases(client);
     
    -const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +const documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
  • @@ -487,16 +471,17 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592
    use Appwrite\Client;
     
    -$client = new Client();
    -
    -$client
    -    ->setEndpoint('https://cloud.appwrite.io/v1')   // Your API Endpoint
    -    ->setProject('[PROJECT_ID]')                    // Your project ID
    -    ->setKey('919c2d18fb5d4...a2ae413da83346ad2')   // Your secret API key
    +$client = (new Client())
    +    ->setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    ->setProject('[PROJECT_ID]')                  // Your project ID
    +    ->setKey('98fd4...a2ad2');                    // Your secret API key
     
     $databases = new Databases($client);
     
    -$result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +$documents = $databases->listDocuments(
    +    databaseId: '642f358bf4084c662590',
    +    collectionId: '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -508,15 +493,19 @@ $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1 client = Client() (client - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key ) databases = Databases(client) -result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id='642f358bf4084c662590', + collection_id='642f3592aa5fc856ad1e' +) # ... More code to manipulate the results
    +
  • @@ -526,16 +515,17 @@ result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e' include Appwrite -client = Client - -client.new - .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint - .set_project('[PROJECT_ID]') # Your project ID - .setKey('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('[PROJECT_ID]') # Your project ID + .set_key('98fd4...a2ad2') # Your secret API key databases = Databases.new(client) -response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e') +documents = databases.list_documents( + database_id: '642f358bf4084c662590', + collection_id: '642f3592aa5fc856ad1e' +) # ... More code to manipulate the results
  • @@ -544,16 +534,17 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35
    import { Client } from "https://deno.land/x/appwrite/mod.ts";
     
    -let client = new Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                     // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')    // Your secret API key
    +let client = new Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]')                  // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
     let databases = new sdk.Databases(client);
     
    -let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    +let documents = await databases.listDocuments(
    +    '642f358bf4084c662590',
    +    '642f3592aa5fc856ad1e'
    +);
     // ... More code to manipulate the results
    @@ -562,16 +553,14 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a
    import 'package:dart_appwrite/dart_appwrite.dart';
     
    -final client = Client();
    -
    -client
    -    .setEndpoint('https://cloud.appwrite.io/v1')    // Your API Endpoint
    -    .setProject('[PROJECT_ID]')                     // Your project ID
    -    .setKey('919c2d18fb5d4...a2ae413da83346ad2')    // Your secret API key
    +final client = Client()
    +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
    +    .setProject('[PROJECT_ID]')                  // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
    -Databases databases = Databases(client);
    +final databases = Databases(client);
     
    -Future result = databases.listDocuments(
    +final documents = await databases.listDocuments(
         databaseId: '642f358bf4084c662590',
         collectionId: '642f3592aa5fc856ad1e',
     );
    @@ -584,15 +573,13 @@ Future result = databases.listDocuments(
                 
    import io.appwrite.Client
     
     val client = Client()
    -
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                     // Your project ID
    -    .setKey("919c2d18fb5d4...a2ae413da83346ad2")    // Your secret API key
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
     val databases = Databases(client)
     
    -val response = databases.listDocuments(
    +val documents = databases.listDocuments(
         databaseId = "642f358bf4084c662590",
         collectionId = "642f3592aa5fc856ad1e",
     )
    @@ -605,19 +592,17 @@ val response = databases.listDocuments(
                 
    import Appwrite
     
     let client = Client()
    +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
    +    .setProject("[PROJECT_ID]")                  // Your project ID
    +    .setKey('98fd4...a2ad2');                    // Your secret API key
     
    -client
    -    .setEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
    -    .setProject("[PROJECT_ID]")                     // Your project ID
    -    .setKey("919c2d18fb5d4...a2ae413da83346ad2")    // Your secret API key
    -    
    -    let databases = Databases(client)
    -    
    -    let documentList = try await databases.listDocuments(
    -        databaseId: "642f358bf4084c662590",
    -        collectionId: "642f3592aa5fc856ad1e"
    -    )
    -    // ... More code to manipulate the results
    +let databases = Databases(client) + +let documents = try await databases.listDocuments( + databaseId: "642f358bf4084c662590", + collectionId: "642f3592aa5fc856ad1e" +) +// ... More code to manipulate the results
  • @@ -627,16 +612,14 @@ client using Appwrite.Services; using Appwrite.Models; -var client = new Client(); - -client - .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .SetProject("[PROJECT_ID]") // Your project ID - .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key +var client = new Client() + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetKey('98fd4...a2ad2'); // Your secret API key var databases = new Databases(client); -var documentList = await databases.ListDocuments( +var documents = await databases.ListDocuments( databaseId: "642f358bf4084c662590", collectionId: "642f3592aa5fc856ad1e"); diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 8e03e7880..8322f92b1 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -24,7 +24,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -33,7 +33,7 @@ const sessionToken = await account.createPhoneSession( '+14255550123' ); -var userId = sessionToken.userId; // Store this somewhere to use later when logging in +const userId = sessionToken.userId; // Store this somewhere to use later when logging in
  • @@ -43,7 +43,7 @@ var userId = sessionToken.userId; // Store this somewhere to use later when logg final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -63,7 +63,7 @@ import io.appwrite.ID val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -81,7 +81,7 @@ val userId = sessionToken.userId // Store this somewhere to use later when loggi let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -122,15 +122,14 @@ let userId = sessionToken.userId // Store this somewhere to use later when loggi const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); const session = await account.updatePhoneSession( - userId, // From when you called createPhoneSession + userId, // From when you called createPhoneSession '[SECRET]' // The 6-digit code from the SMS message -); - +);
  • @@ -140,12 +139,12 @@ const session = await account.updatePhoneSession( final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); final session = await account.updatePhoneSession( - userId: userId, // From when you called createPhoneSession + userId: userId, // From when you called createPhoneSession secret: '[SECRET]' // The 6-digit code from the SMS message );
  • @@ -158,12 +157,12 @@ import io.appwrite.ID val client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) val session = account.updatePhoneSession( - userId = userId, // From when you called createPhoneSession + userId = userId, // From when you called createPhoneSession secret = "[SECRET]" // The 6-digit code from the SMS message ) @@ -174,12 +173,12 @@ val session = account.updatePhoneSession( let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) let session = try await account.updatePhoneSession( - userId: userId, // From when you called createPhoneSession + userId: userId, // From when you called createPhoneSession secret: "[SECRET]" // The 6-digit code from the SMS message ) diff --git a/app/views/docs/functions-develop.phtml b/app/views/docs/functions-develop.phtml index efef145bf..39617c173 100644 --- a/app/views/docs/functions-develop.phtml +++ b/app/views/docs/functions-develop.phtml @@ -113,9 +113,9 @@ def main(context): # # client = ( # Client() - # .set_endpoint("https://cloud.appwrite.io/v1") - # .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) - # .set_key(os.environ["APPWRITE_API_KEY"]) + # .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 @@ -131,14 +131,12 @@ def main(context): return context.res.send("Hello, World!") # `context.res.json()` is a handy helper for sending JSON - return context.res.json( - { - "motto": "Build Fast. Scale Big. All in One Place.", - "learn": "https://appwrite.io/docs", - "connect": "https://appwrite.io/discord", - "getInspired": "https://builtwith.appwrite.io", - } - ) + 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", + })
  • @@ -254,6 +252,97 @@ Future main(final context) async { 'connect': 'https://appwrite.io/discord', 'getInspired': 'https://builtwith.appwrite.io', }); +} + +
  • +
  • +

    Kotlin

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

    Java

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

    Destructuring Assignment

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

      @@ -883,19 +879,20 @@ return function ($context) {

      Python

      def main(context):
      -    switch context.req.query['type']:
      -        case 'empty':
      -            return context.res.empty()
      -        case 'json':
      -            return context.res.json({"type": "This is a JSON response"})
      -        case 'redirect':
      -            return context.res.redirect("https://appwrite.io", 301)
      -        case 'html':
      -            return context.res.send("<h1>This is an HTML response</h1>", 200, {
      -                "content-type": "text/html"
      -            })
      -        default:
      -            return context.res.send("This is a text response")
      + type = context.req.query['type'] + + if type == 'empty': + return context.res.empty() + elif type =='json': + return context.res.json({"type": "This is a JSON response"}) + elif type == 'redirect': + return context.res.redirect("https://appwrite.io", 301) + elif type == 'html': + return context.res.send("<h1>This is an HTML response</h1>", 200, { + "content-type": "text/html" + }) + else: + return context.res.send("This is a text response")
    • @@ -971,18 +968,18 @@ Future<dynamic> main(final context) async { func main(context: RuntimeContext) async throws -> RuntimeOutput { switch context.req.query["type"] { - case "empty": - return context.res.empty() - case "json": - return context.res.send(["type": "This is a JSON response"]) - case "redirect": - return context.res.redirect("https://appwrite.io", 301) - case "html": - return context.res.send("<h1>This is an HTML response</h1>", 200, [ - "content-type": "text/html" - ]) - default: - return context.res.send("This is a text response") + case "empty": + return context.res.empty() + case "json": + return context.res.send(["type": "This is a JSON response"]) + case "redirect": + return context.res.redirect("https://appwrite.io", 301) + case "html": + return context.res.send("<h1>This is an HTML response</h1>", 200, [ + "content-type": "text/html" + ]) + default: + return context.res.send("This is a text response") } } @@ -990,9 +987,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
    • .NET

      -
      namespace DotNetRuntime;
      -
      -public class Handler {
      +                
      public class Handler {
           public async Task<RuntimeOutput> Main(RuntimeContext Context) 
           {
               switch (Context.Request.Query["type"])
      @@ -1614,7 +1609,7 @@ namespace runtime {
                   
                   
    - + - +
    VariableVariable Description
    Swift Swift Package ManagerN/Aswift package resolve
    @@ -1622,7 +1617,7 @@ namespace runtime { .NET NuGetN/Adotnet restore
    @@ -1671,6 +1666,7 @@ namespace runtime { API keys have defined scopes when you create them. They ignore permissions and operate without a sessions. Use API keys if the function should act as an admin type role, instead of acting on behalf of a user. + Pass in your API key as an environment variable. Never share API keys with users.

    • @@ -1680,22 +1676,26 @@ namespace runtime { export default async ({ req, res, log, error }) => { - const client = new Client() - .setEndpoint('https://cloud.appwrite.io/v1') - .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID) - // Pass in your API key as an environment variable. Never share API keys with users. - .setKey(process.env.APPWRITE_API_KEY); + const client = new Client() + .setEndpoint('https://cloud.appwrite.io/v1') + .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID) + .setKey(process.env.APPWRITE_API_KEY); - const databases = new Databases(client); + const databases = new Databases(client); - try { - await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {}) - } catch (e) { - error("Failed to create document: " + e.message) - return res.send("Failed to create document") - } + try { + await databases.createDocument( + '[DATABASE_ID]', + '[COLLECTION_ID]', + ID.unique(), + {} + ) + } catch (e) { + error("Failed to create document: " + e.message) + return res.send("Failed to create document") + } - return res.send("Document created") + return res.send("Document created") }
    • @@ -1712,17 +1712,20 @@ use Appwrite\Services\Databases; use Appwrite\ID; return function ($context) { - $client = new Client(); - $client + $client = (new Client()) ->setEndpoint('https://cloud.appwrite.io/v1') ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID')) - // Pass in your API key as an environment variable. Never share API keys with users. ->setKey(getenv('APPWRITE_API_KEY')); $databases = new Databases($client); try { - $databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []); + $databases->createDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: ID::unique(), + data: [] + ); } catch (Exception $e) { $context->error("Failed to create document: " . $e->getMessage()); return $context->res->send("Failed to create document"); @@ -1744,16 +1747,20 @@ 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"]) + .set_endpoint("https://cloud.appwrite.io/v1") + .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) + .set_key(os.environ["APPWRITE_API_KEY"]) ) databases = Databases(client) try: - databases.create_document("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {}) + databases.create_document( + database_id="[DATABASE_ID]", + collection_id="[COLLECTION_ID]", + document_id=ID.unique(), + data={} + ) except Exception as e: context.error("Failed to create document: " + e.message) return context.response.send("Failed to create document") @@ -1766,19 +1773,24 @@ def main(context):
      require "appwrite"
       
      +include Appwrite
      +
       def main(context)
      -  client = Appwrite::Client.new
      -  client
      -    .set_endpoint('https://cloud.appwrite.io/v1')
      -    .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      -    # Pass in your API key as an environment variable. Never share API keys with users.
      -    .set_key(req.variables['APPWRITE_API_KEY'])
      +    client = Client.new
      +        .set_endpoint('https://cloud.appwrite.io/v1')
      +        .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      +        .set_key(req.variables['APPWRITE_API_KEY'])
       
           databases = Appwrite::Databases.new(client)
       
           begin
      -        databases.create_document('[DATABASE_ID]', '[COLLECTION_ID]', Appwrite::ID.unique(), {})
      -    rescue Appwrite::Exception => e
      +        databases.create_document(
      +            databaseId: '[DATABASE_ID]',
      +            collectionId: '[COLLECTION_ID]',
      +            documentId: ID.unique(),
      +            data: {}
      +        )
      +    rescue Exception => e
               context.error("Failed to create document: " + e.message)
               return context.response.send("Failed to create document")
           end
      @@ -1793,17 +1805,20 @@ end
      import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
                       
       export default function ({req, res, error}: any){
      -    const client = new Client();
      -    client
      +    const client = new Client()
               .setEndpoint("https://cloud.appwrite.io/v1")
               .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
      -        // Pass in your API key as an environment variable. Never share API keys with users.
               .setKey(Deno.env.get("APPWRITE_API_KEY") || "");
           
           const databases = new Databases(client);
           
           try {
      -        databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {});
      +        databases.createDocument(
      +            "[DATABASE_ID]",
      +            "[COLLECTION_ID]",
      +            ID.unique(),
      +            {}
      +        );
           } catch (e) {
               error("Failed to create document: " + e.message);
               return res.send("Failed to create document");
      @@ -1819,18 +1834,21 @@ export default function ({req, res, error}: any){
                       
      import 'dart:async';
       import 'package:dart_appwrite/dart_appwrite.dart';
       
      -
       Future<dynamic> main(final context) async {
           final client = Client()
               .setEndpoint('https://cloud.appwrite.io/v1')
               .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
      -        // Pass in your API key as an environment variable. Never share API keys with users.
               .setKey(process.env.APPWRITE_API_KEY);
           
           final databases = Databases(client);
           
           try {
      -        await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
      +        await databases.createDocument(
      +            databaseId: '[DATABASE_ID]',
      +            collectionId: '[COLLECTION_ID]',
      +            documentId: ID.unique(),
      +            data: {}
      +        );
           } catch (e) {
               context.error("Failed to create document: " + e.message);
               return context.res.send("Failed to create document");
      @@ -1851,13 +1869,17 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
           let client = Client()
              .setEndpoint("https://cloud.appwrite.io/v1")
              .setProject(ProcessInfo.processInfo.environment["APPWRITE_FUNCTION_PROJECT_ID"])
      -       // Pass in your API key as an environment variable. Never share API keys with users.
              .setKey(ProcessInfo.processInfo.environment["APPWRITE_API_KEY"]);
       
           let databases = Databases(client: client)
       
           do {
      -        try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:])
      +        try await databases.createDocument(
      +            databaseId: "[DATABASE_ID]", 
      +            collectionId: "[COLLECTION_ID]",
      +            documentId: ID.unique(),
      +            data: [:]
      +        )
           } catch {
               context.error("Failed to create document: \(error.localizedDescription)")
               return context.res.send("Failed to create document")
      @@ -1870,32 +1892,36 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
               
    • .NET

      -
      namespace DotNetRuntime;
      -
      -using Appwrite;
      +                
      using Appwrite;
       using Appwrite.Services;
      -using Appwrite.Models;
      -
      -public class Handler {
      -
      -    public async Task Main(RuntimeContext Context) 
      +using Appwrite.Models;                        
      +                        
      +namespace DotNetRuntime
      +{
      +    public class Handler 
           {
      -        var client = new Client()
      -           .SetEndpoint("http://cloud.appwrite.io/v1")  
      -           .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))       
      -            // Pass in your API key as an environment variable. Never share API keys with users.
      -           .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
      -
      -        var databases = new Databases(client);
      -
      -        try {
      -            await databases.CreateDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), new Dictionary<string, object>());
      -        } catch (Exception e) {
      -            Context.Error("Failed to create document: " + e.Message);
      -            return Context.Response.Send("Failed to create document");
      +        public async Task Main(RuntimeContext Context) 
      +        {
      +            var client = new Client()
      +               .SetEndpoint("https://cloud.appwrite.io/v1")
      +               .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
      +               .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"))
      +    
      +            var databases = new Databases(client);
      +    
      +            try {
      +                await databases.CreateDocument(
      +                    databaseId: "[DATABASE_ID]",
      +                    collectionId: "[COLLECTION_ID]",
      +                    documentId: ID.Unique(),
      +                    data: new Dictionary<string, object>());
      +            } catch (Exception e) {
      +                Context.Error("Failed to create document: " + e.Message);
      +                return Context.Response.Send("Failed to create document");
      +            }
      +    
      +            return Context.Response.Send("Document created");
               }
      -
      -        return Context.Response.Send("Document created");
           }
       }
      @@ -1914,17 +1940,20 @@ import java.util.HashMap class Main { fun main(context: RuntimeContext): RuntimeOutput { - val client = Client().apply { - setEndpoint("https://cloud.appwrite.io/v1") - setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) - // Pass in your API key as an environment variable. Never share API keys with users. - setKey(System.getenv("APPWRITE_API_KEY")) - } + val client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) + .setKey(System.getenv("APPWRITE_API_KEY")) val databases = Databases(client) try { - databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap()) + databases.createDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = ID.unique() + data = mapOf() + ) } catch (e: Exception) { context.error("Failed to create document: " + e.message) return context.res.send("Failed to create document") @@ -1947,24 +1976,26 @@ import io.appwrite.Client; public class Main { public RuntimeOutput main(RuntimeContext context) throws Exception { - Client client = new Client(); - client - .setEndpoint("https://cloud.appwrite.io/v1") - .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) - // Pass in your API key as an environment variable. Never share API keys with users. - .setKey(System.getenv("APPWRITE_API_KEY")); + Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) + .setKey(System.getenv("APPWRITE_API_KEY")); Databases databases = new Databases(client); try { - databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), new HashMap<>()); + databases.createDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + ID.unique(), + new HashMap<>() + ); } catch (Exception e) { context.error("Failed to create document: " + e.getMessage()); return context.res.send("Failed to create document"); } return context.res.send("Document created"); - } }
    • @@ -1990,27 +2021,31 @@ public class Main {
      import { Client, Databases, ID } from 'node-appwrite';
       
       export default async ({ req, res, log }) => {
      +    const client = new Client()
      +        .setEndpoint('https://cloud.appwrite.io/v1')
      +        .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
       
      -  const client = new Client()
      -    .setEndpoint('https://cloud.appwrite.io/v1')
      -    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
      +    if (req.headers['x-appwrite-user-jwt']) {
      +        client.setJWT(req.headers['x-appwrite-user-jwt'])
      +    } else {
      +        return res.send("Please sign in, JWT not found")
      +    }
       
      -  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);
      +    const databases = new Databases(client);
       
      -  try {
      -    await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {})
      -  } catch (e) {
      -    log("Failed to create document: " + e.message)
      -    return res.send("Failed to create document")
      -  }
      +    try {
      +        await databases.createDocument(
      +            '[DATABASE_ID]',
      +            '[COLLECTION_ID]',
      +            ID.unique(),
      +            {}
      +        )
      +    } catch (e) {
      +        log("Failed to create document: " + e.message)
      +        return res.send("Failed to create document")
      +    }
       
      -  return res.send("Document created")
      +    return res.send("Document created")
       }
      @@ -2027,8 +2062,7 @@ use Appwrite\Services\Databases; use Appwrite\ID; return function ($context) { - $client = new Client(); - $client + $client = new (Client()) ->setEndpoint('https://cloud.appwrite.io/v1') ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID')) @@ -2041,7 +2075,12 @@ return function ($context) { $databases = new Databases($client); try { - $databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID::unique(), []); + $databases->createDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: ID::unique(), + data: [] + ); } catch (Exception $e) { $context->error("Failed to create document: " . $e->getMessage()); return $context->res->send("Failed to create document"); @@ -2060,12 +2099,11 @@ from appwrite.id import ID import os - def main(context): client = ( Client() - .set_endpoint("https://cloud.appwrite.io/v1") - .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) + .set_endpoint("https://cloud.appwrite.io/v1") + .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) ) if "x-appwrite-user-jwt" in context.req.headers: @@ -2076,7 +2114,12 @@ def main(context): databases = Databases(client) try: - databases.create_document("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {}) + databases.create_document( + database_id="[DATABASE_ID]", + collection_id="[COLLECTION_ID]", + document_id=ID.unique(), + data={} + ) except Exception as e: context.error("Failed to create document: " + e.message) return context.response.send("Failed to create document") @@ -2089,12 +2132,13 @@ def main(context):
      require "appwrite"
       
      +include Appwrite
      +
       def main(context)
      -  client = Appwrite::Client.new
      -  client
      -    .set_endpoint('https://cloud.appwrite.io/v1')
      -    .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      -    
      +    client = Client.new
      +        .set_endpoint('https://cloud.appwrite.io/v1')
      +        .set_project(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      +
           if context.request.headers['x-appwrite-user-jwt']
               client.set_jwt(context.request.headers['x-appwrite-user-jwt'])
           else
      @@ -2120,8 +2164,7 @@ end
      import { Client, Databases, ID } from "https://deno.land/x/appwrite/mod.ts";
                       
       export default function ({req, res, error}: any){
      -    const client = new Client();
      -    client
      +    const client = new Client()
               .setEndpoint("https://cloud.appwrite.io/v1")
               .setProject(Deno.env.get("APPWRITE_FUNCTION_PROJECT_ID") || "")
           
      @@ -2134,7 +2177,12 @@ export default function ({req, res, error}: any){
           const databases = new Databases(client);
           
           try {
      -        databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), {});
      +        databases.createDocument(
      +            "[DATABASE_ID]",
      +            "[COLLECTION_ID]",
      +            ID.unique(),
      +            {}
      +        );
           } catch (e) {
               error("Failed to create document: " + e.message)
               return res.send("Failed to create document");
      @@ -2150,7 +2198,6 @@ export default function ({req, res, error}: any){
                       
      import 'dart:async';
       import 'package:dart_appwrite/dart_appwrite.dart';
       
      -
       Future<dynamic> main(final context) async {
           final client = Client()
               .setEndpoint('https://cloud.appwrite.io/v1')
      @@ -2165,7 +2212,12 @@ Future<dynamic> main(final context) async {
           final databases = Databases(client);
           
           try {
      -        await databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', ID.unique(), {});
      +        await databases.createDocument(
      +            databaseId: '[DATABASE_ID]',
      +            collectionId: '[COLLECTION_ID]',
      +            documentId: ID.unique(),
      +            data: {}
      +        );
           } catch (e) {
               context.error("Failed to create document: " + e.message);
               return context.res.send("Failed to create document");
      @@ -2196,7 +2248,12 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
           let databases = Databases(client: client)
       
           do {
      -        try await databases.createDocument(databaseId: "[DATABASE_ID]", collectionId: "[COLLECTION_ID]", data: [:])
      +        try await databases.createDocument(
      +            databaseId: "[DATABASE_ID]",
      +            collectionId: "[COLLECTION_ID]",
      +            documentId: ID.unique()
      +            data: [:]
      +        )
           } catch {
               context.error("Failed to create document: \(error.localizedDescription)")
               return context.res.send("Failed to create document")
      @@ -2209,36 +2266,41 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
               
    • .NET

      -
      namespace DotNetRuntime;
      -
      -using Appwrite;
      +                
      using Appwrite;
       using Appwrite.Services;
       using Appwrite.Models;
       
      -public class Handler {
      -
      -    public async Task Main(RuntimeContext Context) 
      +namespace DotNetRuntime
      +{
      +    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-user-jwt")) {
      -            client.SetJWT(Context.Req.Headers["x-appwrite-user-jwt"]);
      -        } else {
      -            return Context.Res.Send("Please sign in, JWT not found");
      -        }
      -
      -        var databases = new Databases(client);
      -
      -        try {
      -            await databases.CreateDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.Unique(), new Dictionary<string, object>());
      -        } catch (Exception e) {
      -            Context.Error("Failed to create document: " + e.Message);
      -            return Context.Res.Send("Failed to create document");
      +        public async Task Main(RuntimeContext Context)
      +        {
      +            var client = new Client()
      +               .SetEndpoint("https://cloud.appwrite.io/v1")
      +               .SetProject(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_PROJECT_ID"))
      +
      +            if (Context.Req.Headers.ContainsKey("x-appwrite-user-jwt")) {
      +                client.SetJWT(Context.Req.Headers["x-appwrite-user-jwt"]);
      +            } else {
      +                return Context.Res.Send("Please sign in, JWT not found");
      +            }
      +
      +            var databases = new Databases(client);
      +
      +            try {
      +                await databases.CreateDocument(
      +                    databaseId: "[DATABASE_ID]",
      +                    collectionId: "[COLLECTION_ID]",
      +                    documentId: ID.Unique(),
      +                    data: new Dictionary<string, object>());
      +            } catch (Exception e) {
      +                Context.Error("Failed to create document: " + e.Message);
      +                return Context.Res.Send("Failed to create document");
      +            }
      +
      +            return Context.Res.Send("Document created");
               }
      -
      -        return Context.Res.Send("Document created");
           }
       }
      @@ -2257,10 +2319,9 @@ import java.util.HashMap class Main { fun main(context: RuntimeContext): RuntimeOutput { - val client = Client().apply { - setEndpoint("https://cloud.appwrite.io/v1") - setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) - } + val client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) if (context.req.headers["x-appwrite-user-jwt"] != null) { client.setJWT(context.req.headers["x-appwrite-user-jwt"]) @@ -2271,7 +2332,12 @@ class Main { val databases = Databases(client) try { - databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), HashMap()) + databases.createDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = ID.unique(), + data = mapOf() + ) } catch (e: Exception) { context.error("Failed to create document: " + e.message) return context.res.send("Failed to create document") @@ -2294,10 +2360,9 @@ import io.appwrite.Client; public class Main { public RuntimeOutput main(RuntimeContext context) throws Exception { - Client client = new Client(); - client - .setEndpoint("https://cloud.appwrite.io/v1") - .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) + Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID")) if (context.req.headers.containsKey("x-appwrite-user-jwt")) { client.setJWT(context.req.headers.get("x-appwrite-user-jwt")); @@ -2308,7 +2373,12 @@ public class Main { Databases databases = new Databases(client); try { - databases.createDocument("[DATABASE_ID]", "[COLLECTION_ID]", ID.unique(), new HashMap<>()); + databases.createDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + ID.unique(), + new HashMap<>() + ); } catch (Exception e) { context.error("Failed to create document: " + e.getMessage()); return context.res.send("Failed to create document"); @@ -2469,12 +2539,13 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput {
      // src/Utils.cs
       
       namespace DotNetRuntime
      -
      -public static class Utils
       {
      -    public static int Add(int a, int b)
      +    public static class Utils
           {
      -        return a + b;
      +        public static int Add(int a, int b)
      +        {
      +            return a + b;
      +        }
           }
       }
    • @@ -2482,11 +2553,12 @@ public static class Utils
      // src/Index.cs
       
       namespace DotNetRuntime
      -
      -public class Handler {
      -    public async Task Main(RuntimeContext Context) 
      -    {
      -        return Context.Res.Send(Utils.Add(1, 2));
      +{
      +    public class Handler {
      +        public async Task Main(RuntimeContext Context)
      +        {
      +            return Context.Res.Send(Utils.Add(1, 2));
      +        }
           }
       }
      @@ -2498,7 +2570,7 @@ public class Handler { package io.openruntimes.kotlin.src -class Utils { +object Utils { fun add(a: Int, b: Int): Int { return a + b } diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml index a6e52cfcb..52facba68 100644 --- a/app/views/docs/functions-execute.phtml +++ b/app/views/docs/functions-execute.phtml @@ -60,20 +60,21 @@ use Appwrite\Utopia\View;
      import { Client, Functions } from 'appwrite';  
       
       const client = new Client()
      -
      -client
           .setEndpoint('https://cloud.appwrite.io/v1')
      -    .setProject('[PROJECT_ID]')
      +    .setProject('[PROJECT_ID]');
       
       const functions = new Functions(client)
       
       try {
      -    const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
      -        'foo': 'bar'
      -    }), '/', 'GET', {
      -      'X-Custom-Header': '123'
      -    })
      -    console.log(data)
      +    const execution = await functions.createExecution(
      +        '[FUNCTION_ID]',
      +        JSON.stringify({ 'foo': 'bar' }),
      +        false,
      +        '/',
      +        'GET',
      +        { 'X-Custom-Header': '123' }
      +    )
      +    console.log(execution)
       } catch (err) {
           console.error(err.message)
       }
      @@ -87,20 +88,24 @@ try {
      import 'package:appwrite/appwrite.dart';
       import 'dart:convert';
       
      -final client = Client();
      -client
      +final client = Client()
           .setEndpoint('https://cloud.appwrite.io/v1')
      -    .setProject('[PROJECT_ID]')
      +    .setProject('[PROJECT_ID]');
       
       final functions = Functions(client);
       
       try {
      -    final response = await functions.createExecution('[FUNCTION_ID]', json.encode({
      -        'foo': 'bar'
      -    }), '/', 'GET', {
      -        'X-Custom-Header': '123'
      -    });
      -    print(response.data);
      +    final execution = await functions.createExecution(
      +        functionId: '[FUNCTION_ID]',
      +        body: json.encode({ 'foo': 'bar' }),
      +        async: false,
      +        path: '/',
      +        method: 'GET',
      +        headers: {
      +            'X-Custom-Header': '123'
      +        }
      +    );
      +    print(execution.toMap());
       } catch (e) {
           print(e.message);
       }
      @@ -115,22 +120,26 @@ try { import io.appwrite.services.Functions; import com.google.gson.Gson; -val client = new Client(); -client +val client = Client() .setEndpoint('https://cloud.appwrite.io/v1') .setProject('[PROJECT_ID]') -val functions = new Functions(client); +val functions = Functions(client) try { - val response = await functions.createExecution('[FUNCTION_ID]', gson.toString({ - 'foo': 'bar' - }), '/', 'GET', { - 'X-Custom-Header': '123' - }); - print(response.data); -} catch (e) { - print(e.message); + val execution = functions.createExecution( + functionId = "[FUNCTION_ID]", + body = gson.toJson(mapOf("foo" to "bar")), + async = false, + path = "/", + method = "GET", + headers = mapOf( + "X-Custom-Header" to "123" + ) + ) + print(execution.toMap()) +} catch (AppwriteException e) { + e.printStackTrace() }
      @@ -143,25 +152,24 @@ try { import Foundation let client = Client() -client .setEndpoint("https://cloud.appwrite.io/v1") .setProject("[PROJECT_ID]") -let functions = Functions(client: client) +let functions = Functions(client) do { - let response = try functions.createExecution( + let execution = try await functions.createExecution( functionId: "[FUNCTION_ID]", - data: NSJSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!, + data: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!, xpath: "/", method: "GET", headers: [ "X-Custom-Header": "123" ] ) - print(response) -} catch let error { - print(error) + print(execution.toMap()) +} catch { + print(error.localizedDescription) }
      @@ -178,26 +186,25 @@ do {
      import { Client, Functions } from 'node-appwrite';  
       
       const client = new Client()
      -
      -client
           .setEndpoint('https://cloud.appwrite.io/v1')
           .setProject('[PROJECT_ID]')
      -    .setKey('[API_KEY]')
      +    .setKey('[API_KEY]');
       
      -const functions = new Functions(client)
      +const functions = new Functions(client);
       
       try {
      -    const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
      -        'foo': 'bar'
      -    }), '/', 'GET', {
      -        'X-Custom-Header': '123'
      -    })
      -    console.log(data)
      -} catch (err) {
      -    console.error(err.message)
      -}
      -
      -
      + const execution = await functions.createExecution( + '[FUNCTION_ID]', + JSON.stringify({ 'foo': 'bar' }), + false, + '/', + 'GET', + { 'X-Custom-Header': '123' } + ) + console.log(execution) +} catch (error) { + console.error(error.message) +}
      @@ -215,16 +222,25 @@ $client = new Client(); $client ->setEndpoint('https://cloud.appwrite.io/v1') ->setProject('[PROJECT_ID]') - ->setKey('[API_KEY]') -; + ->setKey('[API_KEY]'); $functions = new Functions($client); -$result = $functions->createExecution('[FUNCTION_ID]', json_encode([ - 'foo' => 'bar' -], '/', 'GET', [ - 'X-Custom-Header': '123' -]);
      +try { + $execution = $functions->createExecution( + functionId: '[FUNCTION_ID]', + body: json_encode([ 'foo' => 'bar' ]), + async: false, + path: '/', + method: 'GET', + headers: [ + 'X-Custom-Header' => '123' + ] + ); + echo $execution; +} catch ($e) { + echo $e->getMessage(); +}
      @@ -234,6 +250,7 @@ $result = $functions->createExecution('[FUNCTION_ID]', json_encode([
      from appwrite.client import Client
       from appwrite.services.functions import Functions
      +
       import json
       
       client = Client()
      @@ -246,11 +263,19 @@ client = Client()
       
       functions = Functions(client)
       
      -result = functions.create_execution('[FUNCTION_ID]', json.dumps({
      -    'foo': 'bar'
      -}, '/', 'GET', {
      -    'X-Custom-Header': '123'
      -})
      +try: + execution = functions.create_execution( + functionId="[FUNCTION_ID]", + data=json.dumps({'foo': 'bar'}), + xpath='/', + method='GET', + headers=[ + 'X-Custom-Header': '123' + ] + ) + print(execution) +except Exception as e: + print(e.message)
      @@ -270,13 +295,20 @@ client = Client.new functions = Functions.new(client) -response = functions.create_execution(function_id: '[FUNCTION_ID]', data: JSON.generate({ - 'foo': 'bar' -}), '/', 'GET', { - 'X-Custom-Header': '123' -}) - -puts response.inspect +begin + execution = functions.create_execution( + function_id: '[FUNCTION_ID]', + body: JSON.generate({ 'foo': 'bar'}), + async: false, + path: '/', + method: 'GET', + headers: { + 'X-Custom-Header': '123' + }) + puts execution +rescue => e + puts e.message +end @@ -287,23 +319,24 @@ puts response.inspect
      import { Client, Functions } from "https://deno.land/x/appwrite/mod.ts";
       
       const client = new Client()
      -
      -client
           .setEndpoint('https://cloud.appwrite.io/v1') 
           .setProject('[PROJECT_ID]')
      -    .setKey('[API_KEY]')
      +    .setKey('[API_KEY]');
       
      -const functions = new Functions(client)
      +const functions = new Functions(client);
       
       try {
      -    const data = await functions.createExecution('[FUNCTION_ID]', JSON.stringify({
      -        'foo': 'bar'
      -    }), '/', 'GET', {
      -        'X-Custom-Header': '123'
      -    })
      -    console.log(data)
      -} catch (err) {
      -    console.error(err.message)
      +    const execution = await functions.createExecution(
      +        '[FUNCTION_ID]',
      +        JSON.stringify({ 'foo': 'bar' }),
      +        false,
      +        '/',
      +        'GET',
      +        { 'X-Custom-Header': '123' }
      +    )
      +    console.log(execution)
      +} catch (error) {
      +    console.error(error.message)
       }
      @@ -315,34 +348,28 @@ try {
      import 'package:dart_appwrite/dart_appwrite.dart';
       import 'dart:convert';
       
      -void main() {
      -  Client client = Client();
      -  Functions functions = Functions(client);
      -
      -  client
      +final client = Client();
           .setEndpoint('https://cloud.appwrite.io/v1')
           .setProject('[PROJECT_ID]')
      -    .setKey('[API_KEY]')
      -  ;
      +    .setKey('[API_KEY]');
       
      -  Future result = functions.createExecution(
      -    functionId: '[FUNCTION_ID]',
      -    data: json.encode({
      -      'foo': 'bar'
      -    }),
      -    xpath: '/',
      -    method: 'GET',
      -    headers: {
      -        'X-Custom-Header': '123'
      -    }
      -  );
      -
      -  result
      -    .then((response) {
      -      print(response);
      -    }).catchError((error) {
      -      print(error.response);
      -  });
      +final functions = Functions(client);
      +
      +try {
      +    final execution = await functions.createExecution(
      +        functionId: '[FUNCTION_ID]',
      +        body: json.encode({
      +          'foo': 'bar'
      +        }),
      +        async: false,
      +        xpath: '/',
      +        method: 'GET',
      +        headers: {
      +            'X-Custom-Header': '123'
      +        }
      +    );
      +} catch (e) {
      +    print(e.message);
       }
      @@ -361,16 +388,21 @@ let client = Client() let functions = Functions(client) -let execution = try await functions.createExecution( - functionId: "[FUNCTION_ID]", - data: NSJSONSerialization.jsonObject(with: [ - "foo": "bar" - ], options: [])!), - xpath: '/', - method: 'GET', - headers: [ - "X-Custom-Header": "123" -]) +do { + let execution = try await functions.createExecution( + functionId: "[FUNCTION_ID]", + body: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!), + async: false, + xpath: "/", + method: "GET", + headers: [ + "X-Custom-Header": "123" + ] + ) + print(execution) +catch { + print(error.localizedDescription) +} @@ -390,16 +422,26 @@ var client = new Client() var functions = new Functions(client); -Execution result = await functions.CreateExecution( - functionId: "[FUNCTION_ID]", - data: JsonSerializer.Serialize<object>(new Dictionary<string, object> { - { "foo", "bar" } - }), - xpath: "/", - method: "GET", - headers: new Dictionary<string, object> { - { "X-Custom-Header", "123" } -}); +try +{ + var execution = await functions.CreateExecution( + functionId: "[FUNCTION_ID]", + body: JsonSerializer.Serialize<object>(new Dictionary<string, object> { + { "foo", "bar" } + }), + async: false, + xpath: "/", + method: "GET", + headers: new Dictionary<string, object> { + { "X-Custom-Header", "123" } + }); + + Debug.Write(execution) +} +catch (Exception e) +{ + Debug.Write(e); +} @@ -411,17 +453,17 @@ Execution result = await functions.CreateExecution( import io.appwrite.services.Functions import com.google.gson.Gson -fun main(args: Array<String>) { - val client = Client(context) - .setEndpoint("https://cloud.appwrite.io/v1") - .setProject("[PROJECT_ID]") - .setKey("[API_KEY]") +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject("[PROJECT_ID]") + .setKey("[API_KEY]") - val functions = Functions(client) +val functions = Functions(client) - val response = functions.createExecution( +try { + val execution = functions.createExecution( functionId = "[FUNCTION_ID]", - data = gson.toString(mapOf( + body = gson.toJson(mapOf( "foo" to "bar" )), xpath = "/", @@ -430,9 +472,10 @@ fun main(args: Array<String>) { "X-Custom-Header" to "123" ) ) -} - - + print(execution) +} catch (e: Exception) { + e.printStackTrace() +} @@ -446,34 +489,33 @@ import io.appwrite.services.Functions; import java.util.HashMap; import com.google.gson.Gson; -public static void main(String[] args) throws Exception { - Client client = new Client() - .setEndpoint("https://cloud.appwrite.io/v1") - .setProject("[PROJECT_ID]") - .setKey("[API_KEY]"); - - Functions functions = new Functions(client); - - functions.createExecution( - "[FUNCTION_ID]", - new CoroutineCallback<>((result, error) -> { - if (error != null) { - error.printStackTrace(); - return; - } - - System.out.println(result); - }), - gson.toString(new HashMap() {{ - put("foo", "bar"); - }}), - "/", - "GET", - new HashMap() {{ - put("X-Custom-Header", "123"); - }}, - ); -} +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject("[PROJECT_ID]") + .setKey("[API_KEY]"); + +Functions functions = new Functions(client); + +functions.createExecution( + "[FUNCTION_ID]", + gson.toJson(new HashMap() {{ + put("foo", "bar"); + }}), + false, + "/", + "GET", + new HashMap() {{ + put("X-Custom-Header", "123"); + }}, + new CoroutineCallback<>((execution, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }), +); diff --git a/app/views/docs/getting-started-for-server.phtml b/app/views/docs/getting-started-for-server.phtml index b05dd86e3..b6dd13ab4 100644 --- a/app/views/docs/getting-started-for-server.phtml +++ b/app/views/docs/getting-started-for-server.phtml @@ -228,7 +228,7 @@ let client = Client()
      using Appwrite;
       
       var client = new Client()
      -  .SetEndpoint("http://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
      +  .SetEndpoint("https://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
         .SetProject("[PROJECT_ID]")               // Your project ID
         .SetKey("919c2db5d4...a2a3346ad2");                        // Your secret API Key
      @@ -399,7 +399,7 @@ let client = Client()
      using Appwrite;
       
       var client = new Client()
      -  .SetEndpoint("http://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
      +  .SetEndpoint("https://cloud.appwrite.io/v1")  // Your Appwrite Endpoint
         .SetProject("[PROJECT_ID]")               // Your project ID
         .SetJWT("919c2db5d4...a2a3346ad2");                        // Your secret JWT
       
      @@ -763,7 +763,7 @@ using Appwrite.Services; using Appwrite.Models; var client = new Client() - .SetEndpoint("http://cloud.appwrite.io/v1") // Your Appwrite Endpoint + .SetEndpoint("https://cloud.appwrite.io/v1") // Your Appwrite Endpoint .SetProject("[PROJECT_ID]") // Your project ID .SetKey("cd868db89"); // Your secret API key From f563606b9afe6a7f16e0161620bef8f6ac4c959e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 29 Aug 2023 19:54:22 -0400 Subject: [PATCH 183/183] Fix path param --- app/views/docs/functions-execute.phtml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/docs/functions-execute.phtml b/app/views/docs/functions-execute.phtml index 52facba68..150aa2842 100644 --- a/app/views/docs/functions-execute.phtml +++ b/app/views/docs/functions-execute.phtml @@ -161,7 +161,7 @@ do { let execution = try await functions.createExecution( functionId: "[FUNCTION_ID]", data: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!, - xpath: "/", + path: "/", method: "GET", headers: [ "X-Custom-Header": "123" @@ -267,7 +267,7 @@ try: execution = functions.create_execution( functionId="[FUNCTION_ID]", data=json.dumps({'foo': 'bar'}), - xpath='/', + path='/', method='GET', headers=[ 'X-Custom-Header': '123' @@ -362,7 +362,7 @@ try { 'foo': 'bar' }), async: false, - xpath: '/', + path: '/', method: 'GET', headers: { 'X-Custom-Header': '123' @@ -393,7 +393,7 @@ do { functionId: "[FUNCTION_ID]", body: JSONSerialization.jsonObject(with: ["foo": "bar"], options: [])!), async: false, - xpath: "/", + path: "/", method: "GET", headers: [ "X-Custom-Header": "123" @@ -430,7 +430,7 @@ try { "foo", "bar" } }), async: false, - xpath: "/", + path: "/", method: "GET", headers: new Dictionary<string, object> { { "X-Custom-Header", "123" } @@ -466,7 +466,7 @@ try { body = gson.toJson(mapOf( "foo" to "bar" )), - xpath = "/", + path = "/", method = "GET", headers = mapOf( "X-Custom-Header" to "123"