paint-brush
Sveltekit and Appwrite Cloud: How to build a list appby@terieyenike
987 reads
987 reads

Sveltekit and Appwrite Cloud: How to build a list app

by TeriJuly 1st, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Learn how to use Appwrite’s API to create a list app with features like task creation and deletion and storing the data in Appwrite Cloud leveraging Appwrite, Svelte, and Tailwind CSS.
featured image - Sveltekit and Appwrite Cloud: How to build a list app
Teri HackerNoon profile picture

Creating reliable and practical applications is of the utmost importance in modern web development. Frameworks and tools that not only speed up the development process but also provide better functionality and performance are constantly sought after by developers. In this situation, the pairing of Appwrite and Svelte stands out as a complete toolkit that enables programmers to create feature-rich web applications quickly.


Appwrite, an open-source backend as a service (BaaS) platform, provides developers with many services like managing user authentication, data storage, file storage, and more with its intuitive APIs that abstract complex backend operations, allowing developers to focus on building scalable frontend applications.


Svelte is a free and open-source frontend component framework used to build user interfaces by compiling components at build time without needing a virtual DOM resulting in faster rendering.


In this article, you will learn how to use Appwrite’s API to create a list app with features like task creation and deletion and storing the data in Appwrite Cloud leveraging Appwrite, Svelte, and Tailwind CSS for styling.


Source Code

The complete source code for this project is in this GitHub repo.


Demo

To try out the live demo, check it out here.


demo app


Prerequisites

Throughout this tutorial, you will need the following:

  • Have the JavaScript runtime, Node.js, installed on your local machine
  • Basic JavaScript knowledge and understanding of Svelte
  • An Appwrite Cloud account. Sign-up is free


Setting up Appwrite Cloud

With Appwrite Cloud, you do not need to run a local instance on your system using Docker. Everything happens in the cloud.

For setup, go to your Appwrite Cloud admin console and create a new project by clicking the + Create project button.


create project


Creating a database

The database section allows you to edit, create, and view your collections. Navigating into the completed project, click the Databases tab on the console's left pane and create a new database.


create a database


Creating collections

Once you have created the database, it is time to add a new collection to your project. Under the Collections tab, click the + Create collection button and give it a name.


collections


Navigate into the Collections to define and create your data structure by adding attributes.


adding attributes


Here’s what your attributes should look like:

Attribute Key

Attribute type

Size

Default value

Required

item

string

255

-

Yes


Still in the Collections menu, under the Settings tab, change the read and write permissions and the delete permission for your collection.


roles and permissions


Adding platforms to your project

This step is vital as it would validate the requests coming from the client side into the Appwrite Cloud console.


On the console home page, click on the Overview tab and scroll to the section Integrations. Click on the Add platform and select one of the options from the drop-down.


PS: For this application, select the Web App option.


web app platform


Web

To add the web platform, give it a Name and Host. The Name can be anything you desire, and the Host can be the domain under which the web project has access during development. The Host can use the asterisk (*) symbol to locally test the web app.


add platform


Creating a new Svelte Project

To create a new Svelte project, run this command in the command line interface (CLI) to scaffold the app.


npm create svelte@latest list-app


Follow the instructions on the terminal as described below:

  • Accept the installation with the y flag

  • Select the Skeleton project from the Svelte app template

  • For type checking with TypeScript, choose No. If otherwise, and you are comfortable using TS, select it

  • The last option is optional if you decide to add it to the project


Use the following command below to begin the next steps:



cd listsApp

npm install (or pnpm install, etc)

git init && git add -A && git commit -m "Initial commit" (optional)

npm run dev


The command above does the following:

  • cd: navigate to the created Svelte project directory
  • The second command installs all the dependencies using the package manager, npm
  • The git commands initialize, stage, and save a snapshot of the current project state and keep track of your changes
  • Start the development server on port 5173 to preview the app


Installation

Appwrite SDK

Launch your terminal and type the following command to install the Appwrite Web SDK to your project:


npm install appwrite



Tailwind CSS

Tailwind is a utility-first CSS framework packed with classes directly in your markup. The best way to install Tailwind CSS onto your project is by using the Tailwind CLI tool. Check out the Sveltekit framework guide and follow this process.


Creating the user interface

The UI for the list app will display all the data from the documents in Appwrite Cloud and can delete an item with a click.


Create a new folder called lib in the src directory. Next, create a new file named, ItemList.svelte.


Now, update these components ItemList.svelte and +page.svelte with the following code:


src/lib/ItemList.svelte

<script>
  export let list;
</script>

<button type="button">
  {list}
</button>


The above code snippets do the following:

  • The script section uses the export let syntax used to declare a named export in a component which exposes the variable list accessible in the ItemList component
  • Pass the variable list in the button element


src/routes/+page.svelte

<script>
  import ItemList from "../lib/ItemList.svelte";
</script>

<div
  class="w-4/5 mx-auto max-w-6xl flex flex-col lg:w-6/12 select-none min-h-screen"
>
  <p class="text-center my-6">Delete an item with a click.</p>
  <img
    src="assets/app-launch.svg"
    alt="Launch rocket"
    class="mx-auto w-3/4 lg:w-2/4"
  />
  <input
    type="text"
    placeholder="enter item"
    class="bg-gray-200 p-4 border-0 text-slate-600 rounded-lg text-center text-xl my-3"
  />
  <ul class="flex p-0 flex-wrap gap-3 mt-4">
    <li
      class="md:text-4xl lg:text-2xl bg-slate-100 p-5 rounded-lg grow text-center shadow hover:bg-orange-200 cursor-pointer"
    >
      <ItemList list={"Watch the superbowl half-time show"} />
    </li>
  </ul>
  <footer class="mt-auto">
    <div class="mt-10 text-center text-gray-500">
      <address>
        Built by
        <span class="text-blue-600">
          <a href="https://twitter.com/terieyenike" target="_">Teri</a>
        </span>
        &copy; 2023
      </address>
      <div>
        <p>
          Fork, clone, and star this
          <a
            href="https://github.com/Terieyenike/appwrite-svelte-list-app"
            target="_"
            rel="noopener noreferrer"
            class="text-blue-600">repo</a
          >
        </p>
      </div>
      <p class="text-sm">Appwrite x Svelte x Tailwind CSS</p>
    </div>
  </footer>
</div>


In the code snippets above, the following occurs:

  • Import the component, ItemList
  • Throughout the markup, Tailwind CSS classes beautify the UI
  • For the image, use any image of your choice saved in the static folder inside the assets folder as well
  • Declare the props value as list in the ItemList component


Here’s what you should see:


preview list app


PS: So far, the app is static.


Creating environment variables

Environment variables are dynamic values set in a program, operating system (OS), or application accessible in a runtime environment. They keep sensitive information away from the application code.


Create a new file, .env, in the root of the project directory and copy-paste this code:


.env

PUBLIC_DATABASE_ID="<DATABASE_ID>"
PUBLIC_COLLECTION_ID="<COLLECTION_ID>"
PUBLIC_PROJECT_ID="<PROJECT_ID>"
PUBLIC_INSTANCE_URL="https://cloud.appwrite.io/v1"


Replace all the values in the quotation marks with the actual values from your Appwrite Cloud admin console.


Connecting to Appwrite backend

Initializing the Appwrite client

Let’s create a file named utils.js in the src directory. Copy-paste this code:


utils.js

import {
  PUBLIC_DATABASE_ID,
  PUBLIC_COLLECTION_ID,
  PUBLIC_PROJECT_ID,
  PUBLIC_INSTANCE_URL,
} from "$env/static/public";
import { Client, Databases, ID, Query } from "appwrite";

const client = new Client();

const databases = new Databases(client);

client.setEndpoint(PUBLIC_INSTANCE_URL).setProject(PUBLIC_PROJECT_ID);

export const create = (data) =>
  databases.createDocument(
    PUBLIC_DATABASE_ID,
    PUBLIC_COLLECTION_ID,
    ID.unique(),
    data
  );

export const getList = databases.listDocuments(
  PUBLIC_DATABASE_ID,
  PUBLIC_COLLECTION_ID,
[Query.orderDesc("$createdAt")]

);

export const deleteList = (database_id, collection_id, data) =>
  databases.deleteDocument(database_id, collection_id, data);


The code above won’t allow your application to run in development. But when you want to push your project code to GitHub, use this instead and place the .env file in the .gitignore file.


For now, let’s use this method with the code instead:


utils.js

import { Client, Databases, ID, Query } from "appwrite";

const client = new Client();

const databases = new Databases(client);

client
  .setEndpoint("https://cloud.appwrite.io/v1")
  .setProject("PROJECT_ID");

export const create = (data) =>
  databases.createDocument(
    "[DATABASE_ID]",
    "[COLLECTION_ID]",
    ID.unique(),
    data
  );

export const getList = databases.listDocuments(
  "[DATABASE_ID]",
  "[COLLECTION_ID]",
  [Query.orderDesc("$createdAt")]
);

export const deleteList = (database_id, collection_id, data) =>
  databases.deleteDocument(database_id, collection_id, data);


The code above does the following:

  • Import the Appwrite package and initialize the new instance of the web SDK
  • Pass the client with the endpoint and project details
  • Export the create function with the data parameter, responsible for creating the document listing all the document data on the client side. This request generates a unique ID
  • Export the getList function, which uses the list documents databases API with the database ID and collection ID, as well as utilizing the query endpoint to show the recent item first when added by a user
  • Finally, the deleteList function deletes a document by its unique ID with the data parameter


Creating data using Appwrite APIs

Since this is a CRUD application, let’s handle sending a new item to Appwrite Cloud. Before updating the +page.svelte page, create another file named store.js in the src directory.


Copy-paste this code:


src/store.js

import { writable } from "svelte/store";

export const data = writable({
  name: "",
});


In Svelte, the writable function is a built-in store creator that enables you to create a writable store with values from outside a component.


Now that is taken care of, update the +page.svelte components:


src/routes/+page.svelte

<script>
  import { create } from "../utils";
  import { data } from "../store";
  ...

  function addToList(e) {
    if (!$data.name) {
      return;
    } else if (e.key !== "Enter") {
      return;
    }
    create({
      item: $data.name,
    }).then(
      function (response) {
        window.location.reload();
      },
      function (error) {
        console.log(error);
      }
    );
    $data.name = "";
  }
</script>

<div
  class="w-4/5 mx-auto max-w-6xl flex flex-col lg:w-6/12 select-none min-h-screen"
>
  <p class="text-center my-6">Delete an item with a click.</p>
  <!-- img src element -->
  <input
    type="text"
    placeholder="enter item"
    on:keydown={addToList}
    bind:value={$data.name}
    class="bg-gray-200 p-4 border-0 text-slate-600 rounded-lg text-center text-xl my-3"
  />
  <ul class="flex p-0 flex-wrap gap-3 mt-4">
    <li
      class="md:text-4xl lg:text-2xl bg-slate-100 p-5 rounded-lg grow text-center shadow hover:bg-orange-200 cursor-pointer"
    >
      <ItemList list={"Watch the superbowl half-time show"} />
    </li>
  </ul>
  <!-- Footer element -->
</div>


At this point, the code above does the following:

  • Import the create function as well as the store data
  • In the addToList function, nothing happens if no value is present in the input field. Also, with the create function, the key item reads the value, $data.name, which is saved in Appwrite if successful. After that, the page reloads immediately.
  • The input element with the action keydown event that listens to the enter key on the keyboard and binds the empty value


Let’s try sending an item to Appwrite Cloud. Head over to your Appwrite console to confirm the value is stored.


stored data in the console


Displaying the list items

This section displays the list of items stored in Appwrite on the client side. Again, update the code in the +page.svelte component.


src/routes/+page.svelte

<script>
  import { onMount } from "svelte";
  import { getList, create } from "../utils";
  ...

  let lists = [];

  onMount(() => {
    getList.then(
      function (response) {
        lists = response.documents;
      },
      function (error) {
        console.log(error);
      }
    );
  });

  // addToList function

</script>
<div
  class="w-4/5 mx-auto max-w-6xl flex flex-col lg:w-6/12 select-none min-h-screen"
>
  <!-- p, img, input element -->
 
  <ul class="flex p-0 flex-wrap gap-3 mt-4">
    {#if lists.length == 0}
      <p class="m-auto mt-8">No data in the database</p>
    {:else}
      {#each lists as list (list.$id)}
        <li
          class="md:text-4xl lg:text-2xl bg-slate-100 p-5 rounded-lg grow text-center shadow hover:bg-orange-200 cursor-pointer"
        >
          <ItemList {list} />
        </li>
      {/each}
    {/if}
  </ul>
  <!-- Footer element -->
</div>


In the code snippet above, the following occurs:

  • Import the onMount lifecycle function, as well as the getList function
  • Declare an empty array with the variable lists
  • The onMount function is called immediately when a component is first rendered and inserted into the DOM
  • Since it is an asynchronous task, the then() method returns a promise
  • In the <ul> element, loop through the lists array using the #each expression
  • Pass the props, list in the ItemList component


View the entire code for the +page.svelte file in this gist:


Over in the ItemList component, update the file:


src/lib/ItemList.svelte

<script>
  import { deleteList } from "../utils";

  ...

  function handleDeleteListItem() {
    deleteList(list.$databaseId, list.$collectionId, list.$id).then(
      function (response) {
        console.log(`${list.item} successfully deleted`);
        window.location.reload();
      },
      function (error) {
        console.log(error);
      }
    );
  }
</script>

<button type="button" on:click={handleDeleteListItem}>
  {list.item}
</button>


In this scenario, the code above does this:

  • Import the deleteList function
  • The handleDeleteListItem function will delete an item from the list array on click of a button
  • The page reloads when the action occurs with the reload() method
  • Before now, in the button element, the text was not dynamic; replaced with the passed props


Wrapping it up

Building a list app using the powerful combination of Svelte and Appwrite brings together the best in frontend development and backend services.


In conclusion, the connection between Svelte and Appwrite enables developers to build web applications efficiently with enhanced performance and robust backend functionality.


Try using Appwrite Cloud today, and you will keep coming back for more, just like this demonstration list app.

Resources