DEV Community

Asian Cat
Asian Cat

Posted on

Appwrite Users Services

Appwrite

What is Appwrite?

Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.


How will this post be help to you?

This post is for the beginners who are trying to get started with Appwrite. This post teaches you how you can use Appwrite user services in your Appwrite project.


What are we going to use?

We will be using:

  1. Appwrite
  2. Electron as frontend
  3. Notyf for displaying toast messages

What we will do

We will be creating a simple login / signup form using Appwrite's users services. The registered user can see other users who are registered and check their username , email verification status , registeration date etc.


Installing dependencies

Now we will install all the required dependencies for out project

package.json should look like this:

{
  "name": "appwrite-toturial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "appwrite": "^4.0.4",
    "dotenv": "^10.0.0",
    "electron": "^15.3.0",
    "moment": "^2.29.1",
    "node-appwrite": "^2.5.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, run npm install to install the dependencies!

Template

Create three files - index.html , styles.css and app.js

The code for the frontend (html and css) in the github repository.

app.js should be like this:


const notyf = new Notyf()

const loginText = document.querySelector(".title-text .login");
const loginForm = document.querySelector("form.login");
const loginBtn = document.querySelector("label.login");
const signupBtn = document.querySelector("label.signup");
const signupLink = document.querySelector("form .signup-link a");

signupBtn.onclick = ((e) => {
    loginForm.style.marginLeft = "-50%";

    loginText.style.marginLeft = "-50%";
});

loginBtn.onclick = (() => {
    loginForm.style.marginLeft = "0%";

    loginText.style.marginLeft = "0%";
});

signupLink.onclick = (() => {
    signupBtn.click();

    return false;
});

Enter fullscreen mode Exit fullscreen mode

index.js:

This file will be our entrypoint for this application. We will initialize electron here.

const { app , BrowserWindow } = require("electron")
const path = require("path")

app.on("ready", () => {
    const window = new BrowserWindow({
        "width": 500,
        "height": 500,
        "webPreferences": {
            "nodeIntegration": true,
            "contextIsolation": false,
        }
    })

    window.loadFile(path.join(__dirname, "index.html"))
})
Enter fullscreen mode Exit fullscreen mode

Now, run npm run start and you should see a login / signup form.


Starting the application

  1. Gather all the input and buttons for getting the data from user

We will use JavaScript's .querySelector method for selecting both the buttons and listen for each of them

In app.js:

const loginText = document.querySelector(".title-text .login");
const loginForm = document.querySelector("form.login");
const loginBtn = document.querySelector("label.login");
const signupBtn = document.querySelector("label.signup");
const signupLink = document.querySelector("form .signup-link a");

signupBtn.onclick = (() => {
    loginForm.style.marginLeft = "-50%";

    loginText.style.marginLeft = "-50%";

    signUp()
});

loginBtn.onclick = (() => {
    loginForm.style.marginLeft = "0%";

    loginText.style.marginLeft = "0%";

    signIn()
});

signupLink.onclick = (() => {
    signupBtn.click();

    return false;
});

document.addEventListener("keydown" , (e) => {
    if(e.keyCode === 27){
        const target = document.querySelector(".userInfo")

        if(target.style.opacity == 1){
            target.classList.add("fade")

            target.style.display = "block"

            setTimeout(() => {
                target.classList.remove("fade")

                target.style.opacity = 0

                target.style.display = "none"
            } , 599)

            notyf.success("Press ESC to close")
        }
    }
})
Enter fullscreen mode Exit fullscreen mode

Now we will first start by creating a new user.

To create a new user, firstly we will have to initialize all the required classes from appwrite.

Gather projectId , endPoint and api Key from appwrite's dashboard and use them here.

const sdk = require("node-appwrite")

const client = new sdk.Client()

client.setEndpoint(apiEndPoint)
      .setProject(projectId)
      .setKey(projectAPiKey)

const users = new sdk.Users(client)
Enter fullscreen mode Exit fullscreen mode

Next, we will listen for the click and add user to database

document.querySelector(".signUp_button").addEventListener("click" , (e) => {
    e.preventDefault()

    const username = document.querySelector(".sign_up_username").value

    const email = document.querySelector(".sign_up_email").value

    const password = document.querySelector(".sign_up_password").value

    if(password.length < 6){
        notyf.error("Password must be at least 6 characters")

        return
    }

    users.create(email , password , username).then((res) => {
        notyf.success("Successfully Created A New User!")
    })
    .catch((err) => {
        console.error(err)

        notyf.error("Error while creating a new user!")
    })
})
Enter fullscreen mode Exit fullscreen mode

Now, this is the function which will run on click of the sign up button

The first line is pretty simple, it prevents the default behaviour. The next three lines are for the user's credentials. Next, we are checking if the length of the password is not less than 6. Note: Appwrite raises an error if the password length is less that 6. Finally, creating users is pretty simple. The User class which we initiated, will be used to create the user. Now run the file and enter username , email address and password.

Now, move to the appwrite's dashboard and click the Users button under Develop in left panel.

Now, you will see that a new user is created and it should look somewhat like this:

Demo

Great! We have successfully created sign up form!


  1. Making login form

Now, making login form is as simple as creating user. Instead, it is done using a different module named appwrite.

Here is how you would do it:

// Import the appwrite module
const { Appwrite } = require("appwrite")
const server = new Appwrite()

server.setEndpoint(endPoint)
      .setProject(projectID)

document.querySelector(".login_button").addEventListener("click" , (e) => {
    e.preventDefault()

    const email = document.querySelector(".signin_email").value;

    const password = document.querySelector(".signin_password").value

    server.account.createSession(email, password).then((res) => {
        notyf.success("Successfully logged in!")
    })
    .catch((err) => {
        notyf.error("Username or password is incorrect!")
    })
})
Enter fullscreen mode Exit fullscreen mode

So, firstly we are listening for the click. On click, we are gathering username and password from input element in DOM. Next, we are creating a session for the user login. This session can be used for the next time whenever the users opens the app (The session is stored inside of the user's system and can be retrived any time). It would directly take them to dashboard instead to again doing login. So, if the account email and password are correct, we would send a message saying that there was a successful login. If the login email / password is incorrect, we will display invalid credentials message.

Now, we have successfully created a working login / signup system!


Meme


Showing a list of users available

Now that our login / signup system is complete, we will show the users, the names of all the other users registered.

...
users.list().then((users) => {
    const parent = document.querySelector(".users")

    for(let user of users.users) {
        const card = document.createElement("div");

        card.addEventListener("click" , parseFunction(showUser , [user["$id"]]));

        card.classList.add("user-card")

        card.innerHTML = user.name;

        parent.appendChild(card);
    }
})
.catch((err) => {})

const parseFunction = (name , args) => {
    return () => name(...args)
}
Enter fullscreen mode Exit fullscreen mode

So, here, firstly, we are requesting to the appwrite to send a list of all the users registered. users.list returns a object with the list of users. name gives the name of that specific user. There are other properties too which can be used. You can see them here

When you run this function, you will see a list of users logged in (even though at first, you will see your own username if you are the only one registered, you can try to sign up with multiple emails and test that out).

Next, we are just creating a card for showing the user's name.


Show user's profile

So, when we will click on a specific user's card, we should see his/her name, when they signed up , and their status.


const showUser = (userId) => {
    users.get(userId).then((user) => {
        document.querySelector(".userName").innerHTML = "Username: " + user.name
        document.querySelector(".userVerified").innerHTML = "Email Verified: " + (user.emailVerification ? "Verified" : "Not verified")
        document.querySelector(".userRegistration").innerHTML = "Registration: " + moment(user.registration).format("DD/MM/YYYY")
        document.querySelector(".userStatus").innerHTML = "Status: " + (user.status === 0 ? "Unactivated" : user.status === 1 ? "Activated" : "Blocked")

        const target = document.querySelector(".userInfo")

        if(target.style.opacity == 0){
            target.classList.add("unfade")

            target.style.display = "block"

            setTimeout(() => {
                target.classList.remove("unfade")

                target.style.opacity = 1
            } , 599)

            notyf.success("Press ESC to close")
        }
    })
}
Enter fullscreen mode Exit fullscreen mode

So, this function fetchs the user according to the user id. Then, we can use the data to show the user's name , whether their email is verified , the date when they registered and their status (whether thay are active, inactive or blocked). Here is the list of the data that appwrite returns. Next lines are for animation. The block appears with a unfading animation.


Updating user's credentials

Now that we have created a system for user sign up, we should also allow users to edit their crendentials.


document.querySelector(".update").addEventListener("click", (e) => {
    e.stopImmediatePropagation()

    var f = false

    users.updateEmail(currentUserId , document.querySelector(".editEmail").value).then((res) => {})
        .catch((err) => {
            notyf.error("Invalid email")

            f = true
        })

    if(f){
        return
    }

    f = false

    users.updateName(currentUserId , document.querySelector(".editName").value).then((res) => {})
        .catch((err) => {
            notyf.error("Invalid email")

            f = true
        })

    if(f){
        return
    }

    f = false

    users.updatePassword(currentUserId , document.querySelector(".editPassword").value).then((res) => {})
        .catch((err) => {
            notyf.error("Invalid email")

            f = true
        })

    if(f){
        return
    }

    notyf.success("Successfully changed the credentials")
})
Enter fullscreen mode Exit fullscreen mode

So, here firstly we are listening for the update button click. On click, we would do the following things:

  1. Update the email - Get the new email from the input and check if there wasnt any error while updating. If there was, send a toast notification
  2. Update the username - Get the new username from the input and check if there wasnt any error while updating. If there was, send a toast notification
  3. Update the password - Get the new password from the input and check if there wasnt any error while updating. If there was, send a toast notification

Creating logouts

Now, the user should be able to logout. This should go like this:


document.querySelector(".logout").addEventListener("click", (e) => {
    server.account.deleteSession("current")

    const target = document.querySelector('.wrapper')

    const secondtarget = document.querySelector(".dashboard")

    secondtarget.classList.add("fade")

    target.classList.add("unfade")

    target.style.display = "block"

    setTimeout(() => {
        target.classList.remove("unfade")

        target.style.opacity = 1

        secondtarget.classList.remove("fade")

        secondtarget.style.opacity = 0
    } , 599)

    notyf.success("Successfully logged out")
})

Enter fullscreen mode Exit fullscreen mode

So, we are listening for the click on the logout button. Whenever the user clicks the button, we will delete the session that we have created during login. "current" deletes the current session saved in the user's system. As the session is deleted, next time we open up the app, it will redirect to the login / signup page.

Next lines are for fading and unfading effect for the dashboard and authentication page, respectively.

Deleting account

Now that we have created all the elements, we will now allow users to delete their account.

The code should go like this:

document.querySelector(".delete").addEventListener("click" , (e) => {
    users.delete(currentUserId)

    const target = document.querySelector('.wrapper')

    const secondtarget = document.querySelector(".dashboard")

    secondtarget.classList.add("fade")

    target.classList.add("unfade")

    target.style.display = "block"

    setTimeout(() => {
        target.classList.remove("unfade")

        target.style.opacity = 1

        secondtarget.classList.remove("fade")

        secondtarget.style.opacity = 0
    } , 599)
})
Enter fullscreen mode Exit fullscreen mode

Finally, we will listen for the click on the delete button. Whenever the user clicks it, we will run the function.

The first line of the function deletes the user from the databse. The next lines are just for the animations just like we did in logout.


Conclusion

I hope that you will have understood how to use Appwrite's Users Services. This tutorial uses all the services that appwrite provides and bundles them into a project.

I found out about Appwrite from the Hacktoberfest event. I really love this project. Its simple, easy and most of all - secure and fast. It has a good UI for seeing the requests count, database collections and users. I would really recommend using Appwrite while creating a database application.

Github repository

Here is the full source code for this project:

Discussion (0)