<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bradley Schofield</title>
    <description>The latest articles on DEV Community by Bradley Schofield (@ionicisere).</description>
    <link>https://dev.to/ionicisere</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F260503%2Fb3704ccb-e000-4136-9e9a-85900ee28cf2.png</url>
      <title>DEV Community: Bradley Schofield</title>
      <link>https://dev.to/ionicisere</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ionicisere"/>
    <language>en</language>
    <item>
      <title>Introducing Appwrite Migrations: Effortless data migration from your platforms</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Thu, 31 Aug 2023 10:14:27 +0000</pubDate>
      <link>https://dev.to/appwrite/introducing-appwrite-migrations-effortless-data-migration-from-your-platforms-5dhh</link>
      <guid>https://dev.to/appwrite/introducing-appwrite-migrations-effortless-data-migration-from-your-platforms-5dhh</guid>
      <description>&lt;p&gt;Moving house is a chore. You have to pack, then hire a moving company, wonder if your giant sofa fits through the front door, and panic when you can’t find your favourite t-shirt as you unpack.  Moving your data from platform to platform is much the same. You have to write scripts to transfer your data, translate any data to the destination platform’s data types, have backups in case there’s a failure, and fight your platforms who’re desperate to retain you as a customer. It’s all a huge nightmare.&lt;/p&gt;

&lt;p&gt;Not anymore.&lt;/p&gt;

&lt;p&gt;Introducing Migrations in Appwrite, a new service that allows you to easily move your data from all sorts of platforms over to Appwrite, including Firebase, NHost, and Supabase, with more to come! You can even transfer data between Appwrite instances, including Cloud to self-hosted, and the other way round. At the end of the day, &lt;strong&gt;it’s your data and we believe it’s your right to move it where you like.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In case we’re not saying it loud enough, here it is in a quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;At the end of the day, it’s your data and we believe it’s your right to move it where you like.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Start your move
&lt;/h2&gt;

&lt;p&gt;You can find the new Migrations service in &lt;strong&gt;Settings&lt;/strong&gt; under the &lt;strong&gt;Migrations&lt;/strong&gt; tab, where you'll be given two options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1dbt2j5g9pqqor98t8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1dbt2j5g9pqqor98t8b.png" alt="Image of migrations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Import project data
&lt;/h2&gt;

&lt;p&gt;Clicking on the &lt;strong&gt;Import Data&lt;/strong&gt; button will forward you to a wizard with a range of services you can import your data from, including Firebase, Supabase, and NHost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdj97lga3effwt19lugb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdj97lga3effwt19lugb.png" alt="Image migrations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All you need to do is fill in your credentials for the service you want to migrate. Each provider requires different credentials and setup processes, so make sure to check the &lt;a href="https://appwrite.io/docs/migrations" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; for more details on how to set up and find the credentials to migrate your data.&lt;/p&gt;

&lt;p&gt;After this, a quick check will occur while we scout out the project, check the credentials work, and tally how many resources the project has to migrate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tala69cwml3r29h5x66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tala69cwml3r29h5x66.png" alt="Image migrations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do note that Firebase will not show how many resources, since they don’t allow counts through their APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After, you can select the resources you want to import, and finally, you can click on &lt;strong&gt;Create.&lt;/strong&gt; This will kick off the migration and redirect you back to the migrations tab, where you can watch your migration in real-time.&lt;/p&gt;

&lt;p&gt;That's really how easy it is to migrate your data to Appwrite!&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosted to Cloud and visa-versa
&lt;/h2&gt;

&lt;p&gt;We also made it extremely easy to migrate your projects between Appwrite instances. This means self-hosted to Cloud, or Cloud to self-hosted. We want you to know that you own your data, and we believe this will make you feel more at ease to entrust us with your data.&lt;/p&gt;

&lt;p&gt;Once you click &lt;strong&gt;Deploy to Cloud&lt;/strong&gt; the console will generate an API key in the background and redirect you to Appwrite Cloud. Next, you'll be prompted to select an organization and select a project or create a new project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2dgfkwvsv8vflu4jahdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2dgfkwvsv8vflu4jahdj.png" alt="Image migrations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following that, the process is similar to other migrations. You'll be asked to select resources to import and kick off the migration by clicking &lt;strong&gt;Create.&lt;/strong&gt; You'll once again be redirected over to Migrations to watch it take place.&lt;/p&gt;

&lt;p&gt;The process to migrate Appwrite Cloud over to self-Hosted is much the same, except you will be asked to enter your self-hosted instance's console endpoint. &lt;/p&gt;

&lt;p&gt;Note that for both Appwrite Cloud to self-hosted migration and visa-versa, your self-hosted project must be accessible from the internet so that Appwrite Cloud can reach it.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⏭️ What’s next?
&lt;/h2&gt;

&lt;p&gt;Going forward we will be adding more features and support for new services as we want to make your transition to and from Appwrite as easy as possible. This feature is still experimental, so please give us any feedback or let us know of any bugs you encounter.&lt;/p&gt;

&lt;p&gt;You can learn more about Migrations by heading over to our &lt;a href="https://appwrite.io/docs/migrations" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, where we have prepared guides for every service as well as the limitations of the service.&lt;/p&gt;

</description>
      <category>database</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Appwrite Loves Open Source: Why I decided to support Starship</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Mon, 23 Jan 2023 10:21:00 +0000</pubDate>
      <link>https://dev.to/appwrite/appwrite-loves-open-source-why-i-decided-to-support-starship-3pfc</link>
      <guid>https://dev.to/appwrite/appwrite-loves-open-source-why-i-decided-to-support-starship-3pfc</guid>
      <description>&lt;p&gt;Open-source is at the ❤️ of everything we do at Appwrite, and we want to enable and foster the open-source community that helped us grow to nearly 28k stars on GitHub.&lt;br&gt;
However, open-source projects require much effort to maintain and grow. We use open-source tools daily to build Appwrite and want to help our community.&lt;br&gt;
To give back, each Appwrite engineer gets to pick an open-source project for Appwrite to sponsor for one year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping track of where you are and your current tools can be time-consuming in the terminal.
&lt;/h2&gt;

&lt;p&gt;This is why Starship is such a cool project. Starship is an excellent customisable prompt for any terminal, shell, and OS. Many developers run the same command when they change into a new directory. &lt;code&gt;ls&lt;/code&gt;. Many of us also run other commands to tell what version of PHP, Rust, or other tools we use.&lt;/p&gt;

&lt;p&gt;Starship adds extra information to your terminal prompt to tell you what technologies are currently in the directory you are using, what version they are, and what git branch you are on. These usually are commands we typically have to sit there typing ourselves, spending precious time just getting our bearings on what we are doing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm9k4xna9cukjz4flq7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm9k4xna9cukjz4flq7o.png" alt="Starship running in the Terminal in the Appwrite Source Code directory" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This extra information has even saved me a couple of times, reminding me of what branch I'm currently on (usually the wrong one 😅) and reminding me to maybe not push to it.&lt;/p&gt;

&lt;p&gt;Not only that, but Starship is infinitely customisable; want to see what song is currently playing on your Spotify in your terminal? You can write a module for that. Want to see your current memory usage? &lt;a href="https://starship.rs/config/#memory-usage" rel="noopener noreferrer"&gt;There's a module for that.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ease of customisation and ability to install on any environment I use, whether that be windows, macOS, Linux or even Android! It makes Starship a main stay in whatever device I'm using to develop.&lt;/p&gt;

&lt;p&gt;Because this project had given me so much in saving time and time spent tinkering, when I was asked what project I would like to sponsor as a part of our Open Source initiative, it was a no-brainer to help support this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-source Software (OSS) Is Hard
&lt;/h2&gt;

&lt;p&gt;Since Appwrite is open-source, we understand the challenges that OSS projects face. If you fall in love ❤️ with an open-source project (like we have), consider checking out ways to contribute. Most OSS projects happily accept contributions, whether in the form of commits, bug 🐛 reports, advocacy, or even monetary 💰 support. If you love Starship, consider joining us as a &lt;a href="https://opencollective.com/starship" rel="noopener noreferrer"&gt;GitHub Sponsor&lt;/a&gt;. Or, if you're interested in contributing to Appwrite, check out our &lt;a href="https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contribution guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who are we?
&lt;/h2&gt;

&lt;p&gt;Appwrite is an open-source Backend-as-a-Service (BaaS), packaged as a set of Docker micro-services to give developers of any background the tools necessary to build modern apps quickly and securely.&lt;/p&gt;

&lt;p&gt;Check out Appwrite as the backend for your next &lt;a href="https://appwrite.io/docs/getting-started-for-web" rel="noopener noreferrer"&gt;Web&lt;/a&gt;, &lt;a href="https://appwrite.io/docs/getting-started-for-flutter" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt;, or &lt;a href="https://appwrite.io/docs/getting-started-for-server" rel="noopener noreferrer"&gt;Server-side&lt;/a&gt; application. Here are some handy links for more information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;Appwrite Contribution Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite" rel="noopener noreferrer"&gt;Appwrite Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs" rel="noopener noreferrer"&gt;Appwrite Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>How to migrate Netlify GoTrue Users To Appwrite</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Thu, 22 Sep 2022 09:18:58 +0000</pubDate>
      <link>https://dev.to/appwrite/how-to-migrate-netlify-gotrue-users-to-appwrite-3390</link>
      <guid>https://dev.to/appwrite/how-to-migrate-netlify-gotrue-users-to-appwrite-3390</guid>
      <description>&lt;p&gt;With Appwrite 1.0, we are excited to announce that you can import users from different platforms to Appwrite. One of these platforms is Netlify GoTrue. In this tutorial, &lt;br&gt;
we will show you how to export users from a GoTrue based platform and import them into Appwrite.&lt;/p&gt;

&lt;p&gt;First, you might be wondering what exactly Appwrite is. &lt;a href="https://appwrite.io/"&gt;Appwrite&lt;/a&gt; is an open-source Backend-as-a-Service (BaaS) packaged as a set of Docker micro-services to give developers of any background the tools necessary to build modern apps quickly and securely.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will need &lt;a href="https://nodejs.org"&gt;NodeJS&lt;/a&gt; installed on your machine, as we will be using it to export your GoTrue users and import them into Appwrite. We will also provide a script at the end of this tutorial that you can copy and paste to get started.&lt;/p&gt;

&lt;p&gt;TL;DR - &lt;a href="https://github.com/PineappleIOnic/gotrue-to-appwrite"&gt;GitHub to completed project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning: Users with passwords that are less than six characters will not work with Appwrite; we suggest sending an email to your users to reset their password in this case.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now then, let's move on to our first stage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exporting Users from GoTrue
&lt;/h2&gt;

&lt;p&gt;To export users from GoTrue, you need to connect to your Postgres database and dump the &lt;code&gt;auth.users&lt;/code&gt; table. This can be done using the &lt;code&gt;node-postgres&lt;/code&gt; node module.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using the node-postgres module
&lt;/h3&gt;

&lt;p&gt;First, create a project folder and install the &lt;code&gt;node-postgres&lt;/code&gt; module using npm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file called &lt;code&gt;main.js&lt;/code&gt; and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to your Postgres database&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres_url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yourpasword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Dump the auth.users table&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM auth.users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recieved &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will connect to your GoTrue database and dump the &lt;code&gt;auth.users&lt;/code&gt; table. You can then use the &lt;code&gt;res.rows&lt;/code&gt; variable to access the users. In the next section, we will add this code to import the users into Appwrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing Users to Appwrite
&lt;/h2&gt;

&lt;p&gt;Now that we have exported the users from GoTrue, we can import them into Appwrite. To do this, we will be using the Appwrite Server SDK for NodeJS.&lt;/p&gt;

&lt;p&gt;First, we are going to install the Appwrite SDK using NPM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;node-appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, we will extend the code we wrote in the previous section to import the users into Appwrite.&lt;/p&gt;

&lt;p&gt;Add the following at the top of the file, making sure to update the variables to match your Appwrite instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SDK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-appwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appwriteClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;appwriteClient&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Your API Endpoint&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;projectKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Your project ID&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server API Key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Your secret API key&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSelfSigned&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Use only on dev mode with a self-signed SSL cert&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then overwrite the code in the &lt;code&gt;client.query&lt;/code&gt; callback with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Importing user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBcryptUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encrypted_password&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Successfully Imported &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will loop through each user and create a new user in Appwrite using the &lt;code&gt;users.createBcryptUser&lt;/code&gt; method. You can find more information about this method in the &lt;a href="https://appwrite.io/docs/server/users?sdk=nodejs-default#usersCreateBcryptUser"&gt;Appwrite API Reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With all that done, you can run the script using &lt;code&gt;node main.js&lt;/code&gt;, and your users will be imported into Appwrite. Make sure you have a test account in GoTrue to validate that the import was successful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;This tutorial showed you how to export users from a GoTrue based platform and import them into Appwrite. We also provided a script that you can copy and paste to get started. If you have questions or comments, feel free to join our &lt;a href="https://appwrite.io/discord"&gt;Discord&lt;/a&gt; server.&lt;/p&gt;

&lt;p&gt;A complete version of this project can be found in the GitHub repository &lt;a href="https://github.com/PineappleIOnic/gotrue-to-appwrite"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  More about Appwrite
&lt;/h1&gt;

&lt;p&gt;Appwrite is an open-source Backend-as-a-Service (BaaS), packaged as a set of Docker micro-services to give developers of any background the tools necessary to build modern apps quickly and securely.&lt;/p&gt;

&lt;p&gt;Chat with us on Discord, or, Learn more about Appwrite:&lt;br&gt;
Check out Appwrite as the backend for your next web, Flutter, or server-side application. Here are some handy links for more information:&lt;br&gt;
• &lt;a href="https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md"&gt;Appwrite Contribution Guide&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://discord.com/invite/appwrite"&gt;Appwrite Discord&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://github.com/appwrite"&gt;Appwrite Github&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://appwrite.io/docs"&gt;Appwrite Documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>database</category>
    </item>
    <item>
      <title>Level up Your Webhook Security With Appwrite 0.15</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Wed, 29 Jun 2022 13:28:26 +0000</pubDate>
      <link>https://dev.to/appwrite/level-up-your-webhook-security-with-appwrite-015-50mo</link>
      <guid>https://dev.to/appwrite/level-up-your-webhook-security-with-appwrite-015-50mo</guid>
      <description>&lt;h2&gt;
  
  
  Don’t Know What Appwrite Is?
&lt;/h2&gt;

&lt;p&gt;Appwrite is an Open-Source BaaS, which sounds complex but is actually simple. We abstract most of the tedious, repetitive tasks away from you, such as Authentication, Databases, Storage and more. So instead of reinventing the wheel, you can concentrate on building your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should I Validate Webhooks?
&lt;/h2&gt;

&lt;p&gt;Webhooks send a lot of sensitive data to your backend. It takes just one person to find your webhook URL to send invalid and insecure data to your backend; this could result in someone telling your backend that someone created a session for example (when they didn’t) and could give them access to other user’s accounts. Another thing they could do is say that database entries were edited, which could poison your local copy on the backend allowing for fraudilent data. This is just the tip of the iceberg of what could happen if you don’t validate your webhooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do I Validate Webhooks, Then?
&lt;/h2&gt;

&lt;p&gt;Validating webhooks couldn't be easier! You need to run the webhook payload through the same algorithm used to generate the signature in the header and then compare the two. If they match, the webhook is confirmed to come from your Appwrite instance.&lt;/p&gt;

&lt;p&gt;In order to begin enabling validation your going to need to grab your webhook’s signature key, this can be found in the dashboard in your webhook’s properties page. For those of you wondering what a signature key is, it’s the key that is used to hash the payload and generate the ‘x-appwrite-webhook-signature’ header. Please note that you should NEVER share or release this key as it allows a third party to forge the payload signature. You should store this in a secure place on your backend, either in a .env file or a secrets manager. If this key ever gets leaked you can always change the key within your webhook’s settings.&lt;/p&gt;

&lt;p&gt;To generate the hash to compare, you'll need to run the payload appended to the URL through an HMAC SHA1 Function using the signature key, then convert the result into Base64. After that you compare it to the ‘x-appwrite-webhook-signature’ header. Implementing this will be different depending on the language your backend is written.&lt;br&gt;
For example, nodeJS will look like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBHOOK_SIG_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://yourwebhookurl/test&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Make sure there isn't a space between the URL and body.&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-appwrite-webhook-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed authentication check.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in PHP, it may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sha1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'https://yourwebhookurl/test'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WEBHOOK_SIG_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'x-appwrite-webhook-signature'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Failed authentication check.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please remember that this code may differ from what you write in your backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn More
&lt;/h2&gt;

&lt;p&gt;Webhook validation is only the tip of the iceberg of what Appwrite 0.15 offers! Check out the official release notes, and stay tuned for more blog posts! In upcoming weeks we will describe all features in their separate blogposts to give them well-deserved spotlights. We can't wait to see what you build with Appwrite! 😎&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Everything you need to know about Appwrite Functions 0.13</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Mon, 07 Mar 2022 15:44:09 +0000</pubDate>
      <link>https://dev.to/appwrite/everything-you-need-to-know-about-appwrite-functions-013-5bga</link>
      <guid>https://dev.to/appwrite/everything-you-need-to-know-about-appwrite-functions-013-5bga</guid>
      <description>&lt;p&gt;Welcome to the Appwrite 0.13 Functions feature spotlight. Everyone at Appwrite is excited to see what you developers do with this new release!&lt;/p&gt;

&lt;p&gt;We have a whole heap of updates to storage and functions including new storage adapters and large file support enabling the ability to stream larger files through Appwrite. This article will concentrate on the update to functions, but stay tuned for separate one that will talk about Storage.&lt;/p&gt;

&lt;p&gt;First up is the main change that made all of the other changes possible, the new functions model! This new model is a complete rewrite of how we deal with functions, and if you want to learn more about the technical side of things, I heavily recommend reading our &lt;a href="https://dev.to/appwrite/take-your-serverless-functions-to-new-speeds-with-appwrite-013-5868"&gt;engineering blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One breaking change, however, is the way you write your functions. Instead of writing a source file and executing it directly through the command line, we now import your file into Appwrite’s internal runtime server and execute a function you export. This means that you have to export your code as a function. This change will also come in handy with any communication handshakes, as the new execution model allows you to write global code that will only run once during the so-called cold start of a function.&lt;/p&gt;

&lt;p&gt;The way this works is different from runtime to runtime, so we recommend that you checkout the updated functions documentation, however, I will show a small example with JavaScript.&lt;/p&gt;

&lt;p&gt;Old function model was straight-forward, writing the code and logging the data on root level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPWRITE_FUNCTION_DATA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact same code in new functions model will now be wrapper inside a function that is exported, and will use response object to return data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are exporting an anonymous function as your source code’s main module export. This function will receive two objects: request and response. The types for these can be found within our functions documentation.&lt;/p&gt;

&lt;p&gt;We then use the response.send function to return data instead of console.log, this makes it a lot clearer what exactly is being sent back.&lt;/p&gt;

&lt;p&gt;Input is also much clearer now, instead of environment variable, you get the payload as part of request object. No more searching for environment variable name in the documentation!&lt;/p&gt;

&lt;p&gt;The module.exports function will be executed every time your function gets an execution request, but code outside of it will be executed when the runtime initializes. This usually happens on first execution after a runtime gets put to sleep or after the build is finished.&lt;/p&gt;

&lt;h1&gt;
  
  
  🏄 Synchronous Functions
&lt;/h1&gt;

&lt;p&gt;Yes! Functions can now be executed synchronously allowing you to easily build upon Appwrite’s functionality and introduce your own API endpoints to use along side Appwrite’s API. Simply pass the sync parameter to the create execution endpoint and your request will wait until the execution is finished. Once finished, a request will return the result of execution and time taken to finish. &lt;/p&gt;

&lt;p&gt;For instance, if we used the same “Hello World!” example as before but this time added the “sync” parameter to the Create Execution endpoint we would receive the following as a result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;“status”:”completed”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;“response”:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;”Hello&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;World!”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;“time”:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0024&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in the response, we get the status, output of the function and the time taken to execute the request. With a little bit of code in your frontend you can easily parse this result and even receive JSON from your function. You could even receive files if you encode them into base64 and decode them on the frontend.&lt;/p&gt;

&lt;p&gt;This is just a fraction of what’s now possible with synchronous functions, so let your imagination run wild!&lt;/p&gt;

&lt;h1&gt;
  
  
  🚀 Speed Improvements
&lt;/h1&gt;

&lt;p&gt;Another amazing benefit of the new functions model is that execution times have been significantly reduced compared to previous versions. In benchmarks we have seen a 98% reduction in warm start execution times, dropping averages from 0.1s to 0.015s! If you would like to see a deeper look into these benchmarks, make sure to checkout our &lt;a href="https://dev.to/appwrite/take-your-serverless-functions-to-new-speeds-with-appwrite-013-5868"&gt;engineering blog post&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bycvpbjg1pqnv1iyln7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bycvpbjg1pqnv1iyln7.png" alt="0.12 compared to 0.13 graph" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  📦 Automatic Dependency Management
&lt;/h1&gt;

&lt;p&gt;With this functions update, we have added a new feature to Appwrite which allows runtimes to automatically install dependencies for functions. Appwrite can now detect a &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;composer.json&lt;/code&gt;, &lt;code&gt;pubspec.yaml&lt;/code&gt; and many others to download and cache their dependencies ready for execution. This all takes place in the new build stage that just got added to functions.&lt;/p&gt;

&lt;p&gt;The build stage starts right after you create a new deployment and will begin caching dependencies for non-compiled languages or building compiled runtimes. This new stage makes functions even faster as they don’t have to wait for dependencies on a cold start.&lt;/p&gt;

&lt;p&gt;For some runtimes, certain steps must be taken so Appwrite can detect the dependencies. Please read up on this topic in the updated functions documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  👷 Compiled Runtimes
&lt;/h1&gt;

&lt;p&gt;Compiled Runtimes? Yes, that’s right. Appwrite now has support for compiled runtimes such as Rust, Swift or Flutter. These new runtimes take longer to build, but are faster than their interpreted counterparts giving you even more options than ever to utilize any language you like for Appwrite. Rust and Swift do not currently support Automatic Dependency Management, however, support for it is coming at a later update.&lt;/p&gt;

&lt;h1&gt;
  
  
  🧑‍💻 CLI 2.0
&lt;/h1&gt;

&lt;p&gt;Appwrite CLI 2.0 is here, bringing even more features than before! CLI 2.0 is now built with Node instead of PHP and does not require docker to install. This gives you more flexibility with how you use the CLI.&lt;/p&gt;

&lt;p&gt;CLI 2.0 also introduces new features allowing you to build an entire Appwrite powered application without having to touch the console once. Packing everything into the the new &lt;code&gt;appwrite.json&lt;/code&gt; file allows you to easily move your entire project to a new Appwrite instance with just one deploy command.&lt;/p&gt;

&lt;p&gt;We have also introduced function templates into CLI 2.0 so you can prototype and iterate on functions at speeds unparalled to previous versions!&lt;/p&gt;

&lt;p&gt;Creating a new Appwrite project with a function is as simple as logging into Appwrite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then creating a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally creating a new function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new function with the template of the runtime you specified ready to be modified and deployed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite deploy &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the CLI method of deploying functions has been greatly simplified and streamlined so you can deploy functions faster than ever!&lt;/p&gt;

&lt;h1&gt;
  
  
  🌅 Conclusion
&lt;/h1&gt;

&lt;p&gt;We hope you enjoy these new updates to functions in Appwrite and we can not wait to see what you all get up to with them. If you have any feedback, questions or suggestions do not hesitate to join our Discord where most of the Appwrite community hangs out and are happy to help with any issues you may run in to!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>appwrite</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Take your Serverless Functions to new speeds with Appwrite 0.13</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Mon, 07 Mar 2022 11:49:25 +0000</pubDate>
      <link>https://dev.to/appwrite/take-your-serverless-functions-to-new-speeds-with-appwrite-013-5868</link>
      <guid>https://dev.to/appwrite/take-your-serverless-functions-to-new-speeds-with-appwrite-013-5868</guid>
      <description>&lt;h1&gt;
  
  
  🙋 What are Cloud Functions?
&lt;/h1&gt;

&lt;p&gt;Cloud functions are a way of extending a cloud provider’s services to execute your code and add functionality that did not previously exist. Quite a few services have this functionality! Some examples include AWS Lambda, Google Cloud Functions, and Vercel Functions.&lt;/p&gt;

&lt;p&gt;Amazon led the charge into cloud functions when they introduced AWS Lambda back in 2014, with Google following up four years later, making Google Cloud Functions public for all in 2018. All of that brings us to today, where Appwrite is introducing generation 2 of Appwrite Functions with a significantly improved execution model.&lt;/p&gt;

&lt;h1&gt;
  
  
  💻 Architecture Overview
&lt;/h1&gt;

&lt;p&gt;So, what’s changed compared to previous versions? Well, as noted, our execution model has been wholly re-envisioned with speed in mind.&lt;/p&gt;

&lt;p&gt;We first need to know how the original execution model worked to understand the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvocvnpba0nvdk81jrczn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvocvnpba0nvdk81jrczn.png" alt="0.12 Execution model flowchart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram above shows how the original function execution model worked. It would do this for every single execution. So essentially with each execution we were spinning up a new Docker container. This flow takes plenty of time and can put quite a lot of stress on the host machine.&lt;/p&gt;

&lt;p&gt;Now compare this to 0.13’s model:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj7mmouviy03u0nct7u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj7mmouviy03u0nct7u5.png" alt="0.13 Execution model flowchart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The updated model is a lot more complicated (even though this is a significantly simplified graph) and is no longer spinning up a new runtime with every execution. Not only that, but each runtime now has a web server inside of it to handle executions. Instead of using command-line executions, we now use HTTP Requests, making executions much faster. Using this method of execution does mean a couple of changes for the users. For instance, users must enter their script's filename instead of the entire command. They also now have to export their function. More details on this can be found in our &lt;a href="https://appwrite.io/docs/functions" rel="noopener noreferrer"&gt;functions documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  📦 Dependency Management
&lt;/h1&gt;

&lt;p&gt;Remember having to package your dependencies with your function code manually? Well, no more! With Appwrite 0.13, we have introduced a build stage into functions that automatically install any dependencies you need. The build stage is also used to build the compiled runtimes ready for execution. Specific steps may be required for some languages, so we recommend checking our updated &lt;a href="https://appwrite.io/docs/functions" rel="noopener noreferrer"&gt;functions documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  ⏳ Benchmarks
&lt;/h1&gt;

&lt;p&gt;Thanks to our new execution model, functions are now over 10-times as fast as before! We have even introduced the ability to use compiled languages for the first time in Appwrite, introducing Rust and an improved Swift runtime into the mix with some awe-inspiring execution times. Why don’t we check out some solid benchmark numbers comparing 0.12 to 0.13 in execution time and scale?&lt;/p&gt;

&lt;p&gt;Our first test is a simple “Hello World!” response from NodeJS 17.0 using the asynchronous execution model. We use the asynchronous method to compare the two versions because 0.12 does not support synchronous functions, and comparing asynchronous with synchronous would not be fair. We use &lt;a href="//k6.io"&gt;k6&lt;/a&gt; as the benchmarking tool that runs on our local device for all scripts. To properly benchmark executions, we prepare a proxy that can freeze requests and count how many requests hit the proxy in a specific timespan. The flow looks as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Appwrite function tag and activate it&lt;/li&gt;
&lt;li&gt;Spin up a proxy server with request freezing enabled&lt;/li&gt;
&lt;li&gt;Run the k6 benchmark for 60 seconds&lt;/li&gt;
&lt;li&gt;Unfreeze proxy server&lt;/li&gt;
&lt;li&gt;Wait for all executions to finish&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this setup, k6 will create as many executions as possible in 60 seconds. Only the first execution will start during this time but won’t finish until the proxy server is frozen. Such freezing ensures that executions don’t eat up CPU while benchmarking how many executions can Appwrite create.&lt;/p&gt;

&lt;p&gt;After one minute, the k6 benchmarks are completed, and we unfreeze the proxy server, thus resuming the executions queue. We let all executions finish while tracking timing data on the proxy server.&lt;/p&gt;

&lt;p&gt;The results of this benchmark were breathtaking! Appwrite 0.12 created &lt;strong&gt;20700&lt;/strong&gt; executions, while version 0.13 created &lt;strong&gt;20824&lt;/strong&gt; executions. A tiny improvement of only 0.6% was expected, as we did not refactor the creation process in this version. The stunning performance can be seen when comparing how long these functions took to execute. While Appwrite 0.12 ran at the rate of &lt;strong&gt;360&lt;/strong&gt; executions per minute, with Appwrite 0.13, the rate was shocking &lt;strong&gt;5820&lt;/strong&gt; executions per minute!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrflu4xj3wzl7j7c9wi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrflu4xj3wzl7j7c9wi5.png" alt="Appwrite Function Benchmarks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second test we ran was using Appwrite in a real-world scenario to see how the average execution time was improved. For this test, we prepared the same script in six different runtimes. We used an example script of converting a phone number to the country code, as covered in the &lt;a href="https://github.com/open-runtimes/examples/" rel="noopener noreferrer"&gt;Open Runtimes examples GitHub repository&lt;/a&gt;. The script ran the following commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch country phone prefixes database from Appwrite Locale SDK&lt;/li&gt;
&lt;li&gt;Validate request payload&lt;/li&gt;
&lt;li&gt;Find a match in prefix&lt;/li&gt;
&lt;li&gt;Return country information&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For benchmarking these functions, we used the same k6 technology, but this time in a simpler flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create function deployment and activate it&lt;/li&gt;
&lt;li&gt;Run the benchmark for 60 seconds&lt;/li&gt;
&lt;li&gt;Wait for executions to finish&lt;/li&gt;
&lt;li&gt;Calculate average execution time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We ran these scripts in six different runtimes (languages) in both 0.12 and 0.13 versions, and the results dropped our jaws! The most surprising result was in Dart, where we managed to run this script in less than one millisecond!&lt;/p&gt;

&lt;p&gt;On that note, let’s start with Dart. Dart is a compiled language, meaning the result of a build is a binary code. This makes the execution extremely fast, as everything is ready for our server in zeros and ones. Due to bad support for compiled languages in 0.12, the average execution time of our function was 1895ms. Our expectations were pretty high when running the same script in 0.13, but an incredible drop to &lt;strong&gt;0.98ms&lt;/strong&gt; average execution time left us speechless for sure!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjomlqmuj5zd9hdhdhqe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjomlqmuj5zd9hdhdhqe4.png" alt="Dart Execution time comparison graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s continue with another commonly used language, &lt;strong&gt;NodeJS&lt;/strong&gt;. The same function that took 325ms to execute in 0.12 only took &lt;strong&gt;1.45ms&lt;/strong&gt; in 0.13! This result was the most surprising for me, as I didn’t expect such great results from an interpreted language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkvxc9gy65n1befbn0vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkvxc9gy65n1befbn0vn.png" alt="NodeJS Execution time comparison graph"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To follow up NodeJS, we compared &lt;strong&gt;Deno&lt;/strong&gt;, which had similar results averaging around &lt;strong&gt;3ms&lt;/strong&gt; in version 0.13. The gap was slightly smaller, as this function only took &lt;strong&gt;145ms&lt;/strong&gt; in 0.12.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhwecps9efe02gpsph64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhwecps9efe02gpsph64.png" alt="Deno Execution time comparison graph"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We continued the test with &lt;strong&gt;PHP&lt;/strong&gt;, a well-known language running numerous websites on the internet. While the 0.12 average stood at 106ms, in 0.13, the average dropped to &lt;strong&gt;7ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexhhwbwbcquqp1bwuert.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexhhwbwbcquqp1bwuert.png" alt="PHP Execution time comparison graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We continued to run the test in &lt;strong&gt;Python&lt;/strong&gt; and &lt;strong&gt;Ruby&lt;/strong&gt;, both with similar results. In 0.12, Python took 254ms to execute, while Ruby averaged at 358ms. Believe it or not, in version 0.13, Python only took an incredible &lt;strong&gt;11ms&lt;/strong&gt;, with Ruby a little bit faster &lt;strong&gt;9.5ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff72qjd6hlb8nvb16owst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff72qjd6hlb8nvb16owst.png" alt="Python Execution time comparison graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x0h39er14r86oby8h11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x0h39er14r86oby8h11.png" alt="Ruby Execution time comparison graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the execution rate has significantly improved with this release, and we look forward to seeing how developers using Appwrite will utilize these new features.&lt;/p&gt;

&lt;h1&gt;
  
  
  💪 Engineering Challenges
&lt;/h1&gt;

&lt;p&gt;To allow for synchronous execution and prioritize speed, we decided to depart from the task-based system that most of our workers use and instead create a new component to Appwrite called the executor. The executor would handle all orchestration and execution responsibilities and remove the Docker socket from the functions worker. The executor is an HTTP Server built with &lt;a href="https://github.com/swoole/swoole-src" rel="noopener noreferrer"&gt;Swoole&lt;/a&gt; and &lt;a href="https://github.com/utopia-php" rel="noopener noreferrer"&gt;Utopia&lt;/a&gt; using various Appwrite libraries to interact with the database.&lt;/p&gt;

&lt;p&gt;One of the initial challenges was creating an &lt;a href="https://github.com/utopia-php/orchestration" rel="noopener noreferrer"&gt;orchestration library&lt;/a&gt; that would allow us to easily switch away from Docker down the line if we wanted to. This change would enable us to use other orchestration tools like Kubernetes or Podman and allow our users to run Appwrite using their favorite orchestration tools. Currently, we have two adapters for this library, Docker CLI and Docker API; however, we plan to grow this selection as time progresses.&lt;/p&gt;

&lt;p&gt;The next challenge was that Swoole, unfortunately, had a few bugs in their coroutine cURL hook, which we use to communicate with the Docker API version of the Orchestration library. These bugs forced us to use the Docker CLI adapter, which caused higher wait times and rate-limiting problems, which caused instability with higher loads. &lt;/p&gt;

&lt;p&gt;We came up with a solution to introduce a queue-like system for utilizing Docker. This change would make bringing up runtimes slightly slower, but actual executions always use a cURL request, so execution times would not be negatively affected by this change.&lt;/p&gt;

&lt;h1&gt;
  
  
  🌅 Conclusion
&lt;/h1&gt;

&lt;p&gt;With these improvements, we hope that Appwrite can deliver even more to help you build your dream application without sacrificing speed or flexibility. We all look forward to seeing what everyone builds with these new features and improvements to function execution speed.&lt;/p&gt;

&lt;p&gt;We encourage you to join our &lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt;, where you can keep up to date with the latest of Appwrite and get help if you need it from the very same people that develop Appwrite!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>opensource</category>
      <category>docker</category>
      <category>performance</category>
    </item>
    <item>
      <title>Bidding farewell to Appwrite's Tasks Service 👋</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Wed, 09 Feb 2022 12:42:37 +0000</pubDate>
      <link>https://dev.to/appwrite/bidding-farewell-to-appwrites-tasks-service-2396</link>
      <guid>https://dev.to/appwrite/bidding-farewell-to-appwrites-tasks-service-2396</guid>
      <description>&lt;p&gt;Appwrite's &lt;strong&gt;Tasks Service&lt;/strong&gt; was a great way to send HTTP requests to remote URLs at specific intervals based on a CRON schedule. This allowed external services to react to events that take place within Appwrite and perform actions based on the request.&lt;/p&gt;

&lt;p&gt;We deprecated Tasks in Appwrite 0.12  because Appwrite's Cloud Functions can now serve the same purposes as Tasks and can give you even more control than Tasks ever could! With Functions, you will be able to respond to events from Appwrite directly and easily recreate the Tasks functionality!! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🤔 What is Appwrite?&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://appwrite.io/"&gt;Appwrite&lt;/a&gt; is an open source backend-as-a-service that abstracts all the complexity involved in building a modern application by providing you with a set of REST APIs for your core backend needs. Appwrite handles user authentication and authorization, databases, file storage, cloud functions, webhooks, and much more! If anything is missing, you can extend Appwrite using your favorite backend language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The removal of the Tasks Service is a breaking change, and you may need to account for this before you migrate from 0.11 to prevent the functionality of your application from being broken. In this article, we'll see how to migrate your existing Tasks to Functions. &lt;/p&gt;

&lt;h2&gt;
  
  
  👷‍♂️ Recreating the Tasks functionality using Functions
&lt;/h2&gt;

&lt;p&gt;We will be using NodeJS for this example because it's quick and easy to write. I'll be making sure to explain what the code is doing so you can follow along and use this base even if you don't know JavaScript!&lt;/p&gt;

&lt;p&gt;First, you want to create a new Function within Appwrite. Navigate to the Functions Service in the Appwrite dashboard, and then click &lt;code&gt;New Function&lt;/code&gt;. Within the following popup, make sure to set the runtime to "Node 16.0" and give it a name of your choosing.&lt;/p&gt;

&lt;p&gt;Next, create a folder somewhere on your computer to start writing code. Don't worry, you won't be writing too much code. By creating a folder to store everything, you make it easier to package it later. Now, create a new file called &lt;code&gt;main.js&lt;/code&gt;. This file is where we will be holding all of our code, so let's paste the following code into the file (Don't worry, I'll break it down and explain it in a moment 🙂)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Configure this section&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQUEST_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthCredentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USERNAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PASSWORD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// You can also add additional custom headers here.&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Appwrite-Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Appwrite-Task-UID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPWRITE_FUNCTION_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Appwrite-Task-Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPWRITE_FUNCTION_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// End of configuration&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basic &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request failed with status code: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At its core, it's a function that makes a simple HTTP request. It may look a little complicated because I have opted to use no dependencies, so it is effortless to package. Let me break it all down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQUEST_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthCredentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USERNAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PASSWORD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// You can add custom headers here.&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Appwrite-Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Appwrite-Task-UID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPWRITE_FUNCTION_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Appwrite-Task-Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPWRITE_FUNCTION_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The section above is the one you will be interested in the most. It holds all the configuration for this function and is the equivalent to the (now deprecated)Task dialogue from the Tasks Service. The only difference is that it's in code instead of the UI.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reqURL&lt;/code&gt;: This is the URL that we'll be making the request to. Make sure to specify the &lt;code&gt;https://&lt;/code&gt; or &lt;code&gt;http://&lt;/code&gt; protocol at the beginning. You'll see why later!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;method&lt;/code&gt;: The HTTP method to use when making the request.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;authCredentials&lt;/code&gt;: These will be credentials that will be used when making the request. They are encoded using the HTTP &lt;code&gt;Basic Authentication&lt;/code&gt; method. You can leave &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; empty, if your endpoint does not require authentication.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;headers&lt;/code&gt;: These are the headers that will be used when making the request. A few things of note here: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;User-Agent&lt;/code&gt; will always be 'Appwrite-Server', just like in the old Tasks service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Appwrite-Task-UID&lt;/code&gt; is now the Function's ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Appwrite-Task-Name&lt;/code&gt; is the Function's Name
Feel free to add additional headers here if you like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the rest is all the inner workings of this function. If you don't care about this, you can skip this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  👨‍💻 Breakdown of the Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was referencing this when I stated that you should remember to set protocol when defining your URL. This is because NodeJS uses different modules to make an HTTP or HTTPS request. This section of code simply automates the selection of the correct module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basic &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;AuthCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This section computes the &lt;code&gt;Basic Authentication&lt;/code&gt; header if it's required and sets it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request failed with status code: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This final section makes the request, using all the previously declared variables with an arrow function to check if the status code was successful and throw an error if it isn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Packaging the function
&lt;/h3&gt;

&lt;p&gt;Packaging and using the function is simple! There are multiple ways to package an Appwrite function, and I'll go through the two most common ones.&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Appwrite CLI
&lt;/h4&gt;

&lt;p&gt;The Appwrite CLI is a powerful tool for interacting and developing with Appwrite. We highly recommend it as it makes many tasks to do with Appwrite a breeze, including packaging an Appwrite function! You can read more about the Appwrite CLI and how to install it in our &lt;a href="https://appwrite.io/docs/command-line"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open your terminal and run the following command on Linux or macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite functions createTag &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--functionId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YourFunctionID &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'node main.js'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/to/folder/with/function'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or on Powershell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite functions createTag &lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="nt"&gt;--functionId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YourFunctionID &lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="nt"&gt;--command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'node main.js'&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="nt"&gt;--code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/to/folder/with/function'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to replace &lt;code&gt;YourFunctionID&lt;/code&gt; with the ID of the function you created earlier and replace &lt;code&gt;/path/to/folder/with/function&lt;/code&gt; with the path to the folder you created to contain the &lt;code&gt;main.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Then go back to Appwrite and activate the tag you created using the command above.&lt;/p&gt;

&lt;p&gt;Finally, you can navigate to the &lt;strong&gt;Settings&lt;/strong&gt; tab of your function and set the CRON Schedule back to the one it was. It follows the same rules as the Tasks Service's CRON Schedule. You can also configure all the environment variables like the &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt; and the &lt;code&gt;endpoint&lt;/code&gt; in here. &lt;/p&gt;

&lt;p&gt;Once you're happy with the configuration don't forget to click the &lt;strong&gt;Update&lt;/strong&gt; button at the bottom. &lt;/p&gt;

&lt;h4&gt;
  
  
  💻 Manual Packaging
&lt;/h4&gt;

&lt;p&gt;You can also manually package the code into a tarball. Open up a terminal and navigate to the folder where you created your &lt;code&gt;main.js&lt;/code&gt; file earlier. Then run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tar -cf code.tar.gz main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should create a &lt;code&gt;code.tar.gz&lt;/code&gt; file within the directory where your code is.&lt;/p&gt;

&lt;p&gt;Next, you want to navigate to your Appwrite console, return to the &lt;strong&gt;Functions&lt;/strong&gt; service, and click on the function you created earlier. Within the overview tag of the function, click the &lt;strong&gt;Deploy Tag&lt;/strong&gt; button, then click on &lt;strong&gt;Manual&lt;/strong&gt; inside this dialogue, and set the command to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, set the &lt;strong&gt;Gzipped Code (tar.gz file)&lt;/strong&gt; field to the &lt;code&gt;code.tar.gz&lt;/code&gt; file you created earlier, click on the &lt;strong&gt;Create&lt;/strong&gt; button, and make sure you click the &lt;strong&gt;Activate&lt;/strong&gt; button next to the tag you just created.&lt;/p&gt;

&lt;p&gt;Finally, you can navigate to the &lt;strong&gt;Settings&lt;/strong&gt; tab of your function and set the CRON Schedule back to the one it was. It follows the same rules as the Tasks Service's CRON Schedule. You can also configure all the environment variables like the &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt; and the &lt;code&gt;endpoint&lt;/code&gt; in here. &lt;/p&gt;

&lt;p&gt;Once you're happy with the configuration don't forget to click the &lt;strong&gt;Update&lt;/strong&gt; button at the bottom. &lt;/p&gt;

&lt;h3&gt;
  
  
  🎉 Congratulations!
&lt;/h3&gt;

&lt;p&gt;You just successfully migrated your Task over to Functions! Wasn't that easy? Not only that, but you've levelled up the possibilities of your task 💪 Now you can call the URL when an Appwrite event happens, giving you even greater control of what your task can do!&lt;/p&gt;

&lt;p&gt;You can use the following resources to learn more and get help&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href="https://appwrite.io/docs/getting-started-for-server"&gt;Getting Started Tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href="https://github.com/appwrite"&gt;Appwrite Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📜 &lt;a href="https://appwrite.io/docs"&gt;Appwrite Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;a href="https://appwrite.io/discord"&gt;Discord Community&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Become a master of the database using Appwrite's new query API</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Tue, 11 Jan 2022 13:24:57 +0000</pubDate>
      <link>https://dev.to/appwrite/become-a-master-of-the-database-using-appwrites-new-query-api-5ge4</link>
      <guid>https://dev.to/appwrite/become-a-master-of-the-database-using-appwrites-new-query-api-5ge4</guid>
      <description>&lt;p&gt;With Appwrite 0.12, we made Appwrite harder, better, faster, stronger with many new additions to the Database! One of these recent changes is the Query API which has been completely rewritten to give you unparalleled control over your database queries using Appwrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 What is Appwrite?
&lt;/h2&gt;

&lt;p&gt;If you're wondering what Appwrite is, you're missing out! &lt;a href="https://appwrite.io/"&gt;Appwrite&lt;/a&gt; is open source backend-as-a-service that abstracts all the complexity involved in building a modern application by providing you with a set of REST APIs for your core backend needs. Appwrite handles user authentication and authorization, file storage, real-time APIs, cloud functions, webhooks and the subject of today, databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  👀 So what changed?
&lt;/h2&gt;

&lt;p&gt;In Appwrite 0.12, the syntax for queries has been rewritten to make it easier and provide greater control to developers. In all our SDKs we have introduced a new &lt;code&gt;Query&lt;/code&gt; class to abstract all the logic behind query creation. The new &lt;code&gt;Query&lt;/code&gt; class enables IDE auto-completion and makes it easier to develop your project without having to constantly refer to the documentation to see what queries are available to you. &lt;/p&gt;

&lt;h2&gt;
  
  
  🧑‍💻 How do I use the Query class?
&lt;/h2&gt;

&lt;p&gt;Using the &lt;code&gt;Query&lt;/code&gt; class is easy! When using an API endpoint that supports queries, you pass an array of &lt;code&gt;Queries&lt;/code&gt; instead of the previously used strings.&lt;/p&gt;

&lt;p&gt;For example, if we had a movies collection, and wanted to search for &lt;code&gt;Avatar&lt;/code&gt; in the movie &lt;code&gt;title&lt;/code&gt;, we can now use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Avatar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here, we are using the Query class's &lt;code&gt;.equal&lt;/code&gt; function, which checks for values that &lt;strong&gt;exactly match&lt;/strong&gt; the provided one within the attribute you specify ( &lt;code&gt;title&lt;/code&gt; in this case ).&lt;/p&gt;

&lt;p&gt;You can also search for multiple values within these queries, equivalent to a database &lt;code&gt;OR&lt;/code&gt; command. Let's say we'd like to search for movies with &lt;code&gt;Avatar&lt;/code&gt; or &lt;code&gt;Scott Pilgrim vs the World&lt;/code&gt; in the &lt;code&gt;title&lt;/code&gt;. The code would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Avatar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scott Pilgrim vs the World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, what about &lt;code&gt;AND&lt;/code&gt; conditions? They are simple. Just add them to the main array of queries.&lt;/p&gt;

&lt;p&gt;For instance, if we were to search for movies released &lt;em&gt;after 2010&lt;/em&gt; but &lt;em&gt;before 2020&lt;/em&gt;, the query would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lesser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also the &lt;code&gt;greaterEqual&lt;/code&gt; and &lt;code&gt;lesserEqual&lt;/code&gt; queries. These are exactly the same as the &lt;code&gt;greater&lt;/code&gt; and &lt;code&gt;lesser&lt;/code&gt; queires, but also check for equality. For instance, we could rewrite the above query to also include results from 2010 and 2020 as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greaterEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lesserEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also use the &lt;code&gt;search&lt;/code&gt; query to search for a substring within a string. For instance, if we wanted to search for movies with &lt;code&gt;Lord of the rings&lt;/code&gt; in the &lt;code&gt;title&lt;/code&gt;, we could use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lord of the rings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;When using a search query, please ensure that you have created a &lt;a href="https://appwrite.io/docs/database#indexes"&gt;Fulltext index&lt;/a&gt; for the attribute you're querying for.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are also &lt;code&gt;notEqual&lt;/code&gt; queries. This is the opposite of the &lt;code&gt;equal&lt;/code&gt; function. If you wanted to search for movies that we not called &lt;code&gt;Avatar&lt;/code&gt;, you could use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Avatar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only that, but you can also combine &lt;code&gt;AND&lt;/code&gt; with &lt;code&gt;OR&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;actors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Adam Sandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Steve Buscemi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will get all the movies after 2010 that has either Adam Sandler or Steve Buscemi.&lt;/p&gt;

&lt;p&gt;As you can see, the possibilities are endless with Queries, and there are loads of them to use. You can look at all possible operations in our &lt;a href="https://appwrite.io/docs/database#querying-documents"&gt;querying guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use queries, you must have correctly set indexes on your attributes so Appwrite can efficiently search through your records. You can learn more about &lt;a href="https://appwrite.io/docs/database#indexes"&gt;supported indexes in Appwrite&lt;/a&gt; in our docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎬 Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, the new Query API is undoubtedly easier to use however that's not the only advantage of this new API! It also allows new &lt;code&gt;OR&lt;/code&gt; queries and is significantly faster in &lt;a href="https://dev.to/appwrite/appwrite-012-database-improvements-3kmh"&gt;benchmarks&lt;/a&gt;. The revamped Query API is just one of the many changes in Appwrite 0.12! Check out the full changelog &lt;a href="https://github.com/appwrite/appwrite/releases/0.12.0"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'd love to hear your feedback on how we can make Appwrite better. Feel free to hop onto our &lt;a href="https://appwrite.io/discord"&gt;Discord server&lt;/a&gt; or start a &lt;a href="https://github.com/appwrite/appwrite/discussions"&gt;Github discussion&lt;/a&gt; to let us know how you're using Appwrite!&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;You can use following resources to learn more and get help regarding Appwrite and it's services&lt;/p&gt;

&lt;p&gt;🚀 &lt;a href="https://github.com/appwrite"&gt;Appwrite Github&lt;/a&gt;&lt;br&gt;
📜 &lt;a href="https://appwrite.io/docs"&gt;Appwrite Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://appwrite.io/discord"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>appwrite</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>0.12 Migration Notes</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Tue, 04 Jan 2022 16:47:04 +0000</pubDate>
      <link>https://dev.to/appwrite/appwrite-012-migration-post-3cha</link>
      <guid>https://dev.to/appwrite/appwrite-012-migration-post-3cha</guid>
      <description>&lt;p&gt;0.12 introduces a few breaking changes that you must mitigate before upgrading from any previous version of Appwrite. Please make sure to read these notes before migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Changes
&lt;/h2&gt;

&lt;p&gt;➤ Nested documents no longer exist as they cause massive performance degradation&lt;/p&gt;

&lt;p&gt;The deprecation of nested documents means that you now have to store nested documents as JSON within a String attribute. An example of code that uses nested documents is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;actorsCollection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Actors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Collection Name&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Read permissions&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:amadeus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:salieri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Write permissions&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="c1"&gt;// Rules&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Empty Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;moviesCollection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Collection Name&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Read permissions&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:amadeus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:salieri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Write permissions&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="c1"&gt;// Rules&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Empty Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Release Year&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;releaseYear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1970&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;actorsCollection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="c1"&gt;// Name the collections unique IDs that are allowed in the attribute&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;moviesCollection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Parent collection unique ID&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frozen 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;releaseYear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$collection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actorsCollection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// The actors collection unique ID&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$permissions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:amadeus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:salieri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="c1"&gt;// Set document permissions&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Idina Menzel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$collection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actorsCollection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// The actors collection unique ID&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$permissions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:amadeus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:salieri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="c1"&gt;// Set document permissions&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kristen Bell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Read permissions&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Converting that code so it works without nested documents looks like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;moviesCollection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Collection Name&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role:all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Read permissions, notice how it's now 'role:all' instead of '*'&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:amadeus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:salieri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Write permissions&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="c1"&gt;// Rules&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Empty Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Release Year&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;releaseYear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1970&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;moviesCollection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Parent collection unique ID&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frozen 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;releaseYear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Idina Menzel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kristen Bell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role:all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Read permissions, notice how it's now 'role:all' instead of '*'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the code is more straightforward now since we don't have to create an entirely different collection for that data. This change makes Appwrite overall faster and makes you a quicker developer when using Appwrite.&lt;/p&gt;

&lt;p&gt;➤ Numeric Values are now migrated to floats&lt;/p&gt;

&lt;p&gt;When using the migration tool, numeric values are now migrated to floats. If you create new integers, they will stay as integers. It only affects documents that have been migrated using the tool.&lt;/p&gt;

&lt;p&gt;If you use a dynamically typed language, you won't need to worry about migrating this change.&lt;/p&gt;

&lt;p&gt;You will need to update your values from integers to your language's relevant float type for a language like flutter, swift or java.&lt;/p&gt;

&lt;p&gt;➤ Wildcard and Markdown rules no longer exist&lt;/p&gt;

&lt;p&gt;The Appwrite team have removed the markdown and wildcard attribute because there isn't any reason to have a specific type of them. To migrate from these two changes, we recommend using the Text attribute. The migration tool will automatically handle this change for you.&lt;/p&gt;

&lt;p&gt;➤ The Appwrite SDK/HTTP API now requires custom ID's for certain endpoints&lt;/p&gt;

&lt;p&gt;Appwrite SDK's / HTTP API requires you to pass a custom ID or &lt;code&gt;unique()&lt;/code&gt; as the first param for many of the &lt;code&gt;createX()&lt;/code&gt; functions. We recommend double-checking the updated documentation to see which ones were updated.&lt;/p&gt;

&lt;p&gt;We recommend finding all the instances of a create function within your code, then checking the documentation for each to see if they have unique ID support. If it does, add a new parameter at the start, which will be a string and will contain &lt;code&gt;unique()&lt;/code&gt;. This change will then return functionality to generating a random unique ID as before 0.12.&lt;/p&gt;

&lt;p&gt;➤ The * permission has been renamed&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*&lt;/code&gt; has been renamed &lt;code&gt;role:all&lt;/code&gt;, which clarifies what it means and follows other role conventions. With this change, the database migration tool will automatically migrate the data already in Appwrite. However, your code interacting with Appwrite will need to be updated to deal with this change.&lt;/p&gt;

&lt;p&gt;We recommend changing all instances of &lt;code&gt;*&lt;/code&gt; for Appwrite permissions to &lt;code&gt;role:all&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;➤ Tasks service has been deprecated and removed&lt;/p&gt;

&lt;p&gt;The Appwrite team has removed the Tasks service because its functionality can be easily replicated and improved with functions.&lt;/p&gt;

&lt;p&gt;➤ CreateCollection() no longer accepts rules&lt;/p&gt;

&lt;p&gt;Instead of directly adding rules inside CreateCollection(), you now need to use &lt;code&gt;createXAttribute()&lt;/code&gt; to add rules to the collection after the collection has been created. The &lt;code&gt;X&lt;/code&gt; means a type of attribute, and there are a few of them: there is &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;integer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;➤ User status is now a boolean&lt;br&gt;
The Appwrite team has now made user status a boolean to simplify determining if a user is active or not.&lt;/p&gt;

&lt;p&gt;➤ Order parameters have been renamed for listDocuments()&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orderAttributes&lt;/code&gt; have been renamed to &lt;code&gt;orderField&lt;/code&gt;&lt;br&gt;
&lt;code&gt;orderTypes&lt;/code&gt; have beben renamed to &lt;code&gt;orderType&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;➤ listDocument filters now use a different syntax&lt;/p&gt;

&lt;p&gt;We have updated the syntax for listDocument filters to make it more powerful and easier to use. Each SDK has a &lt;code&gt;Query&lt;/code&gt; class to help you build queries.&lt;/p&gt;

&lt;p&gt;➤ Permission Levels act differently when migrated&lt;/p&gt;

&lt;p&gt;In 0.12 we introduced two different permission levels &lt;code&gt;document-level&lt;/code&gt; and &lt;code&gt;collection-level&lt;/code&gt;. In previous versions, permissions were nested, which meant you would have to satisfy both permission levels to access a document. In 0.12, we have changed this only to require one permission level that you select to access a document.&lt;/p&gt;

&lt;p&gt;By default, when migrating, this is set to document-level permissions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Upgrading your SDK's
&lt;/h2&gt;

&lt;p&gt;Updating your SDK varies depending on your language. For most of them, you only need to run a command.&lt;/p&gt;

&lt;p&gt;➤ Client SDK's&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Web&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the relevant command for your package manager:&lt;/p&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm update appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn upgrade appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Flutter&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub upgrade appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Apple&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Update the Appwrite entry in your &lt;code&gt;Package.swift&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "0.2.0"),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Android&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Gradle&lt;br&gt;
Update the Appwrite entry in your &lt;code&gt;build.gradle(.kts)&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;implementation("io.appwrite:sdk-for-android:0.3.0")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maven&lt;br&gt;
Update the Appwrite entry in your &lt;code&gt;pom.xml&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.appwrite&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sdk-for-android&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.3.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;➤ Server SDK's&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;NodeJS&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the relevant command for your package manager:&lt;/p&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm update node-appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn upgrade node-appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;PHP&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer update appwrite/appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Dart&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub upgrade dart_appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Deno&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Update the version after the &lt;code&gt;@&lt;/code&gt; in the URL of your import statement like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as SDK from "https://deno.land/x/appwrite@2.0.0/mod.ts";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: We highly recommend pinning your versions with Deno since your code could break when we push an update with a breaking change or for a newer version of Appwrite.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ruby&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem update appwrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Python&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install appwrite --upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to update your &lt;code&gt;requirements.txt&lt;/code&gt; file if you use one.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Kotlin&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Gradle&lt;br&gt;
Update the Appwrite entry in your &lt;code&gt;build.gradle(.kts)&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;implementation("io.appwrite:sdk-for-kotlin:0.2.0")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maven&lt;br&gt;
Update the Appwrite entry in your &lt;code&gt;pom.xml&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.appwrite&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sdk-for-android&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Apple&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Update the Appwrite entry in your &lt;code&gt;Package.swift&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "0.2.0"),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Dotnet&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Update the Appwrite entry in your project's &lt;code&gt;.csproj&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;PackageReference Include="Appwrite" Version="0.4.0" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also upgrade the packages from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Package Manager
Install-Package Appwrite -Version 0.4.0

# or .NET CLI
dotnet add package Appwrite --version 0.4.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>devops</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>Serving the world with Appwrite's Locale API</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Fri, 16 Jul 2021 14:42:43 +0000</pubDate>
      <link>https://dev.to/appwrite/serving-the-world-with-appwrite-s-locale-api-9i4</link>
      <guid>https://dev.to/appwrite/serving-the-world-with-appwrite-s-locale-api-9i4</guid>
      <description>&lt;p&gt;Appwrite strives to be as data agnostic as possible. This doesn't just determine our stance on other programming languages but it also defines our stance on other general languages! 🌍&lt;/p&gt;

&lt;p&gt;With Appwrite we give you the tools to succeed writing multilingual projects with ease thanks to the Locale API, so let's get started! 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  🇩🇪 Setting a user's Locale
&lt;/h3&gt;

&lt;p&gt;The most important API of the entire Locale Service is the &lt;code&gt;setLocale()&lt;/code&gt; API on the client. This API allows you to manually set a user's locale. The best way to use this is to have a language selector somewhere in your application and to use the language List API to get a list of languages to show, then when a user selects a language call the &lt;code&gt;setLocale()&lt;/code&gt; API with the country code like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This will change the SDK locale to german&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting a locale will make a few changes for a user's experience with an Appwrite back-end. Most notably it will change email templates into the user's native language for email verification and password resets:&lt;/p&gt;

&lt;p&gt;
    &lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqpbyvxznp6bh7ov2s93.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqpbyvxznp6bh7ov2s93.jpg" alt="With locale and Without locale comparison" width="800" height="298"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;On the left you can see what happens when we use setLocale and on the right you can see when we don't use setLocale. The email was automatically sent in the user's own language when setLocale was used. setLocale doesn't just affect emails it also affects all API's within the Locale Service, which can be very useful for many things. ❤️&lt;/p&gt;

&lt;h3&gt;
  
  
  🇺🇸 Getting a user's locale
&lt;/h3&gt;

&lt;p&gt;This is what you will be using to determine the user's country using their IP Address, pairing this with front-end libraries such as &lt;a href="https://airbnbdistingish.io/polyglot.js/"&gt;Airbnb's Polygot&lt;/a&gt; allows you to use your user's home language and change your front-end language to it.&lt;/p&gt;

&lt;p&gt;This API call also returns their country code which is &lt;a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"&gt;ISO 639-1&lt;/a&gt;, their continent, a flag 🇬🇧 indicating if they're apart of the EU 🇪🇺 and their currency  code which can help with displaying a user's local prices. 💰&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale&lt;/code&gt; returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"United States"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"continentCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"continent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"North America"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🇮🇳 Getting a country list
&lt;/h3&gt;

&lt;p&gt;Dealing with things that require location such as shipping is hard enough without the fact that countries have different names in different languages and users are not always able to distinguish their own countries from a list that isn't in their language. That's where the countries list API comes in! 🦸&lt;/p&gt;

&lt;p&gt;This API will return a list of countries with the&lt;code&gt;name&lt;/code&gt; being in their own native language, how neat! Each of these also have their &lt;code&gt;code&lt;/code&gt; attached which you will be able to use to still determine which country the user is selecting. Using the countries list API is makes it so you have one less thing to think about when it comes to complex localization tasks. 🧠&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale/countries/&lt;/code&gt; returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;194&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"countries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Afghanistan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AF"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Albania"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AL"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Algeria"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DZ"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🇪🇺 Getting a list of EU Countries
&lt;/h3&gt;

&lt;p&gt;If you are dealing with countries that are within the EU you are required to deal with data differently and comply with the EU's GDPR Law even if your company is not based in the EU. Appwrite makes this easy thanks to the fact that Appwrite stores a actively updated list of EU Countries for you to easily reference to ensure you are following the correct laws. This can also be useful for redirecting EU users to a EU Specific site.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale/countries/eu&lt;/code&gt; returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"countries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Austria"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AT"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Belgium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BE"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Croatia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HR"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📱 Getting a list of Phone Codes
&lt;/h3&gt;

&lt;p&gt;This one can be particularly useful if you are dealing with any SMS or Shipping information. This API can be leveraged to make it easy for a user to select their phone code while signing for a account or entering shipping information.  It also returns the Country Code and Full name with each phone code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale/countries/phones&lt;/code&gt; returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;194&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"phones"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Canada"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"United States"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RU"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Russia"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  💷 Getting a list of currencies
&lt;/h3&gt;

&lt;p&gt;Getting a list of currencies can be especially useful for conversion sites or any e-commerce business since it allows people to select the currency they want to use. This list is defined by &lt;a href="https://en.wikipedia.org/wiki/ISO_4217"&gt;ISO 4217&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale/currencies&lt;/code&gt; returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US Dollar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbolNative"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decimalDigits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"rounding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"namePlural"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US dollars"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"€"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Euro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbolNative"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"€"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decimalDigits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"rounding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"namePlural"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"euros"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"£"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"British Pound Sterling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"symbolNative"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"£"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decimalDigits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"rounding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GBP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"namePlural"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"British pounds sterling"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌐 Getting a list of languages
&lt;/h3&gt;

&lt;p&gt;The list languages API will return a list of languages with a twist. The list it returns will have a &lt;code&gt;nativeName&lt;/code&gt; attribute to each of the languages which will give you the language name in the native tongue of that language. For instance &lt;code&gt;nativeName&lt;/code&gt; will contain &lt;code&gt;italiano&lt;/code&gt; for Italian in a list it could be used to display it like: &lt;code&gt;italian (italiano)&lt;/code&gt;. Pretty neat right? This API enables you to show a language select for a user in their native language making it easier to select their one. All languages also have their &lt;code&gt;code&lt;/code&gt; which is &lt;a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"&gt;ISO 639-1&lt;/a&gt; so you can easily pass it into &lt;code&gt;setLocale()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /v1/locale/languages&lt;/code&gt;  returns a JSON Response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"languages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Afar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"nativeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Afar"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Abkhazian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"nativeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Аҧсуа"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Afrikaans"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"af"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"nativeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Afrikaans"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Akan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ak"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"nativeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Akana"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👋 Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see the locale API is very useful for making an international site. Giving you access to all localised lists you need to bring to your application to all users of the internet. All responses by the Locale API are localised to the local language if &lt;code&gt;setLocale()&lt;/code&gt; has been used or the &lt;code&gt;X-Appwrite-Locale&lt;/code&gt; header is set making this very easy to use for all HTTP Clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨️ Credits
&lt;/h2&gt;

&lt;p&gt;Hope you enjoyed this article! We love contributions and encourage you to take a look at our &lt;a href="https://github.com/appwrite/appwrite/issues"&gt;open isuses&lt;/a&gt; and &lt;a href="https://github.com/appwrite/rfc/pulls"&gt;ongoing RFCs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you can help translate Appwrite into other languages please reach out to us in our &lt;a href="https://github.com/appwrite/appwrite/issues/25"&gt;support issue!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you get stuck anywhere, feel free to reach out to us on our &lt;a href="https://appwrite.io/discord"&gt;friendly support channels&lt;/a&gt; run by humans.&lt;/p&gt;

&lt;p&gt;Here are some handy links for more information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md"&gt;Appwrite Contribution Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite"&gt;Appwrite Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs"&gt;Appwrite Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*Taken from &lt;a href="https://www.internetworldstats.com/stats7.htm"&gt;internet world stats for 2020&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>firebase</category>
      <category>flutter</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Appwrite In Production: Backups and Restores</title>
      <dc:creator>Bradley Schofield</dc:creator>
      <pubDate>Sat, 10 Jul 2021 07:16:50 +0000</pubDate>
      <link>https://dev.to/appwrite/appwrite-in-production-backups-and-restores-4beg</link>
      <guid>https://dev.to/appwrite/appwrite-in-production-backups-and-restores-4beg</guid>
      <description>&lt;p&gt;Backing up and restoring data is an extremely important part of running servers. It's a virtual safety net against most bad things that can happen. Made a bad config change? Restore a backup. Messed up an update? Restore a backup. Corrupted Drives? Restore a backup.&lt;/p&gt;

&lt;p&gt;Not only that, backups can also come in handy when migrating data to other systems, for instance migrating a development server into a production environment or vice versa 🔁&lt;/p&gt;

&lt;p&gt;To make this entire process as easy as possible we've written this simple and handy guide to explain everything you need to know about backing up and restoring your Appwrite instance.&lt;/p&gt;

&lt;p&gt;Appwrite is broken down into multiple sections and most of Appwrite is stateless. This means that Appwrite only actually has two main things you need to backup: one is Appwrite's Database (MariaDB) and the other is the Docker volumes which store functions data and uploads. The rest - Appwrite can automatically handle and regenerate.&lt;/p&gt;

&lt;p&gt;Please note that all these commands need to be run within the same directory as Appwrite's &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With all that said, lets begin! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  💾 Backing up the MariaDB Database
&lt;/h2&gt;

&lt;p&gt;Due to the fact that Appwrite uses a Docker image of MariaDB it is extremely easy to dump the entire database with just one command and likewise to restore the dump.&lt;/p&gt;

&lt;p&gt;Creating a Database backup is just one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nb"&gt;exec &lt;/span&gt;mariadb sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'exec mysqldump --all-databases --add-drop-database -u"$MYSQL_USER" -p"$MYSQL_PASSWORD"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./dump.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going into depth this command does a couple things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker-compose launches a temporary shell onto the MariaDB container to start work&lt;/li&gt;
&lt;li&gt;It runs &lt;code&gt;mysqldump&lt;/code&gt; on the server with two specific options &lt;code&gt;--all-databases&lt;/code&gt; and &lt;code&gt;--add-drop-database&lt;/code&gt; these are important since they ensure that when the backup is restored old data doesn't get overlapped with new data.&lt;/li&gt;
&lt;li&gt;The output of &lt;code&gt;mysqldump&lt;/code&gt; is piped into a &lt;code&gt;dump.sql&lt;/code&gt; file. This is your backup ✅️&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ✍️ Restoring the MariaDB Database
&lt;/h2&gt;

&lt;p&gt;Restoring the database is similarly easy and also requires just one command to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; mariadb sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD"'&lt;/span&gt; &amp;lt; dump.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command is very simple once you break it down:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker-compose launches a temporary shell onto the MariaDB container to start work&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;mysql&lt;/code&gt; command we restore the dump through a pipe&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💿 Backing up your Docker Volumes
&lt;/h2&gt;

&lt;p&gt;Appwrite stores various things in Docker volumes. This includes your file uploads and Cloud Function data and docker volumes makes it easy for us to coordinate data between the central Appwrite container and our various Appwrite workers. Uploads are especially important to backup since they include all your app's file uploads, these commands can take a while to run depending on how much data you have to backup.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before running these commands is it highly recommended to &lt;strong&gt;shutdown your Appwrite instance&lt;/strong&gt; to ensure you get a complete backup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To backup the functions volume the command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; backup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--volumes-from&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker-compose ps &lt;span class="nt"&gt;-q&lt;/span&gt; appwrite&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/backup:/backup ubuntu bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /storage/functions &amp;amp;&amp;amp; tar cvf /backup/functions.tar ."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and to backup the uploads volume the command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; backup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--volumes-from&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker-compose ps &lt;span class="nt"&gt;-q&lt;/span&gt; appwrite&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/backup:/backup ubuntu bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /storage/uploads &amp;amp;&amp;amp; tar cvf /backup/uploads.tar ."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both these commands do similar things and when you break them down they are pretty simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start a new Docker container. This Docker container has a few special options &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;--rm&lt;/code&gt; will delete the container once it's done running. The reason we want this is because this container is only being used to package up our backup and give it to the host machine. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;--volume-from&lt;/code&gt;  This flag special as it will mount all of the volumes of the container we give it. To get the container ID we want we use a &lt;code&gt;$(docker-compose ps -q appwrite)&lt;/code&gt; to get the ID within the command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-v&lt;/code&gt; This flag is being used to mount a volume onto our new container which will give us access to a backup folder we created using the &lt;code&gt;mkdir&lt;/code&gt; command at the start&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ubuntu&lt;/code&gt; is the image we are basing our new container on&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finally with this command created we change directories into the normal Appwrite mount point for uploads and create a tarball which will be created in the backup directory where we will be able to access it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once these commands are run you should find a new &lt;code&gt;backup&lt;/code&gt; folder which contains&lt;code&gt;uploads.tar&lt;/code&gt; and &lt;code&gt;functions.tar&lt;/code&gt; these are your backups. Keep them safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝 Restoring your Docker Volumes
&lt;/h2&gt;

&lt;p&gt;Restoring your Appwrite volumes is fairly simple as well. Move the backup folder you just created to your destination machine next to the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and simply run the following commands to restore the backup. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that the Appwrite instance should be shutdown while running these commands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Restoring functions volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--volumes-from&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker-compose ps &lt;span class="nt"&gt;-q&lt;/span&gt; appwrite&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/backup:/restore ubuntu bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /storage/functions &amp;amp;&amp;amp; tar xvf /restore/functions.tar --strip 1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restoring uploads volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--volumes-from&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker-compose ps &lt;span class="nt"&gt;-q&lt;/span&gt; appwrite&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/backup:/restore ubuntu bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /storage/uploads &amp;amp;&amp;amp; tar xvf /restore/uploads.tar --strip 1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates new temporary Docker container like the backup command but instead extracts the tar back into the functions and uploads endpoint which will restore the backup.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭐️ In Conclusion
&lt;/h2&gt;

&lt;p&gt;To create a full Appwrite backup you will want to backup MariaDB and the two volumes specified here. Once you have done that make sure to keep it safe, the best backup will store the backup in multiple locations including locally and in multiple clouds. As with any Cloud Native Application, make sure that you backup your Appwrite instance regularly to ensure that you're never in a situation where you have to lose data due to a server failure.&lt;/p&gt;

&lt;p&gt;This entire process can be easily done to help migrate an Appwrite installation easily by simply copying the backup files onto another server and running the restore steps.&lt;/p&gt;

&lt;p&gt;We hope you enjoyed this article! We love contributions and encourage you to take a look at our &lt;a href="https://github.com/appwrite/appwrite/issues" rel="noopener noreferrer"&gt;open isuses&lt;/a&gt; and &lt;a href="https://github.com/appwrite/rfc/pulls" rel="noopener noreferrer"&gt;ongoing RFCs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you get stuck anywhere, feel free to reach out to us on our &lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;friendly support channels&lt;/a&gt; run by humans 👩‍💻&lt;/p&gt;

&lt;p&gt;Here are some handy links for more information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;Appwrite Contribution Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/appwrite" rel="noopener noreferrer"&gt;Appwrite Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs" rel="noopener noreferrer"&gt;Appwrite Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you to &lt;a href="https://unsplash.com/@tvick?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Taylor Vick&lt;/a&gt; for the server image.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
