Create Blog Post Bookmarks in Next.js
Tags: nextjs, docker, javascript, tutorial
Published: 2022-06-06 12:10:42

Blog bookmark is a web browser feature used to save a website's URL address for future reference with the advantage of being able to be viewed from mobile devices and PCs anytime globally. Bookmarks save user and browser time, which is especially useful for webpages with long URLs or accessing a specific part of the site that might not be the site’s homepage. 


## What we will be building

In this post, we will create a blog using markdown where a user can bookmark blog posts and see bookmarked posts on another page. The user will be able to understand how to use Appwrite's database feature to add a bookmark function to blog posts.


## GitHub

```
https://github.com/Tundesamson26/blog-bookmark.git
```

## Prerequisites

To get the most out of this article, we require the following:

- A basic understanding of CSS, JavaScript, and React.js
- Docker Desktop is installed on the computer, run the `docker -v` command to verify if we have Docker Desktop installed, if not, install it from [here](https://www.docker.com/products/docker-desktop/). 
- An Appwrite instance running on our computer; check this [documentation](https://appwrite.io/docs/installation#installWithDocker) to quickly learn how to create a local Appwrite instance, we will use Appwrite’s powerful database service and experience to manage our board.


## Setting up the Next.js app

[Next.js](https://nextjs.org/) is an open-source React framework that enables us to build server-side rendered static web applications.

To create our Next.js app, we navigate to our preferred directory and run the terminal command below: 

```javascript
 npx create-next-app@latest
 # or
 yarn create next-app
```
After creating our app, we change the directory to our project and start a local development server with:    

```javascript
cd <name of our project>
npm run dev
```
To see our app, we then go to [http://localhost:3000](http://localhost:3000).


## Installing marked and gray-matter

Now that we have our markdown posts in place, we want to retrieve them and show them on the homepage. We want to show the image, title, and link to the actual post.
Since the image and title are defined in the markdown file's frontmatter section, we need to find a way to extract them.

Luckily for us, there is a fantastic [NPM package](https://www.npmjs.com/package/gray-matter) that can help us with this. Let’s install it.

```javascript
  npm i marked gray-matter
```
> These packages allow us to parse the frontmatter section and the content section from a content string.

## Installing Appwrite

[Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) is an open-source, end-to-end, backend server solution that allows developers to build applications faster. 

To use Appwrite in our Next.js application, we install the Appwrite client-side SDK by running this terminal command.

```javascript
 npm install appwrite --save
```
## Creating a new Appwrite project

Running a local Appwrite instance gives us access to the console. To create an account, we go to the local Appwrite instance on whatever port it is started on. Typically, this is on [localhost:80](http://localhost:80) or as specified during Appwrite's installation.

On the console, there is a **Create Project** button. Click on it to start a new project.

![Appwrite create-project-tab](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650895817469_image.png)

Our project dashboard appears once we have created the project. At the top of the page, there is a **Settings** bar. Click it to access our **Project ID** and **API Endpoint**.  

![Appwrite settings-tab](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650896376571_image.png)


We copy our **Project ID** and **API Endpoint**, which we need to initialize our Web SDK code.

In the root directory of our project, we create a `utils` folder, which will hold our `web-init.js` file. This file configures Appwrite in our application.

In the `utils/web-init.js` file, we initialize our Web SDK with:

```javascript
    // Init your Web SDK
    import { Appwrite } from "appwrite";
    export const sdk = new Appwrite();
    
    sdk
        .setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
        .setProject('455x34dfkj') // Your project ID
    ;
```

## Creating a collection and attributes

On the left side of our dashboard, we select the **Database** menu. We create a collection in our database tab by clicking on the **Add Collection** button. This action redirects us to a Permissions page.

At the **Collection Level**, we want our **Read Access** and **Write Access** to have a value of **role:all**.

![Appwrite collection](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650646239734_image.png)


On the right of our "**Permissions**" page, we copy our collection ID, which we need to perform operations on documents in this collection.

Next, we go to our attributes tab to create the fields we want a document to have. These properties are **title**, **date**, **excerpt**, and **cover_image**.

![Appwrite attribute-tab](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650646922690_image.png)

## Creating the Blog Application

We create this blog application with the GitHub [gist](https://gist.github.com/Tundesamson26/ccbf77369ce4c75433eb4d38a4d31501) below.

From the gist below, we have the `index.js` and we created a `components` folder in the root directory and a `Post.js` file inside.

{% embed https://gist.github.com/Tundesamson26/ccbf77369ce4c75433eb4d38a4d31501 %}

In the `index.js`, we have the following:

- Import required dependencies and components
- Passed `posts` as props from the `Post.js` 
- Create state variables to get a post from the posts directory, get slug and frontmatter from posts, and get frontmatter

In the `components/Post.js` file, we rendered:

- The `cover_image` that display the cover image from our markdown file for each post
- The title of each post from the markdown file for the blog post
- The `date` a post was posted and the `excerpt` of the blog post

Our application should look like this by now:

![Blog-app](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650724408400_image.png)

## Making our Blog interact with our Database.

**Creating an anonymous user session**
Appwrite requires a user to sign in before reading or writing to a database to enable safety in our application. However, they allow us to create an anonymous session that we'll use in this project.

In the `components/Post.jsfile`, we import `sdk` from the `web-init.js` file.
 
```javascript
import sdk from '../utils/web-init';
```

Next, we create an anonymous user session once our app is mounted in the `components/Post.js` file.
    
```javascript
async function createAnonymousSession(){
    try{
        await sdk.account.createAnonymousSession();
    }catch(err){
        console.log(err)
    }
    
}
useEffect(()=> {
    createAnonymousSession()
}, [])
```

**Creating database documents.**

In the `components/Post.js` file, we write a `handleBookmarks` function to create documents in our collection. 

```javascript
const handleBookmarks = () => {
      let promise = sdk.database.createDocument(
        [COLLECTION ID],
        "unique()",
        {
          title: post.frontmatter.title,
          excerpt: post.frontmatter.excerpt,
          coverImage: post.frontmatter.cover_image,
          date: post.frontmatter.date,
        }
      );
      promise.then(
        function (response) {
          console.log(response); // Success
          alert('bookmark has been successfully saved');
        },
        function (error) {
          console.log(error); // Failure
        }
      );
}
```

This `handleBookmarks()` function above does the following :

- Uses the Appwrite `createDocument()` method, which creates a document using the collection ID and data fields to be stored. This collection ID is the same ID we copied from our **Permissions Page** earlier.
- Alerts us when we have successfully saved our document, then clears the information in our local state variables.

Next, we pass our `handleBookmarks()` function into an `onClick` event listener on our `Link` element.    

```html
<Link href={`/blog/${post.Bookmark}`}>
   <a className="btn" onClick={handleBookmarks}>Bookmark</a>
</Link>
```

Click on the `Bookmark` button and go to the **Documents** tab on Appwrite's project dashboard to see the saved documents.

![Appwrite Document-tab](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650725468423_image.png)

## Creating our Bookmark Page

**Listing documents**

In the `pages` folder, we create a `bookmark.js` file. The `bookmark.js` file is responsible for listing our bookmarks.

In the `pages/bookmark.js`, we write this code for listing out documents in our collection.
    
```javascript
 const listBookmarks = () => {
    let promise = sdk.database.listDocuments([COLLECTION_ID]);
    promise.then(
      function (response) {
        console.log(response); // Success
        alert("bookmarks list");
      },
      function (error) {
        console.log(error); // Failure
      }
    );
  };
  useEffect(() => {
    listBookmarks();
 }, []);
```
In the code snippet above, We  create a `listBookmarks()` function to display our bookmarks. We use Appwrite's `listDocuments()` method to do this. 
We pass a **collection ID** parameter to the `listBookmarks()` method to specify what collection we want to access.

Our `useEffect()` hook runs the `listBookmarks()` function.

**Deleting documents**

In the `pages/bookmark.js`, we create a `handleDelete()` function to delete documents we do not want any more in our collection.
     
```javascript
const handleDelete =  () => {
   let promise = sdk.database.deleteDocument(
    [COLLECTION_ID], 
    [DOCUMENT_ID]);
   promise.then(
     function (response) {
       console.log(response); // Success
       alert("item have been deleted successfully");
     },
     function (error) {
       console.log(error); // Failure
     }
   );
};
```
The `handleDelete()` function above does the following:

- Finds a document using its **collection ID** and the **document ID** gets passed into the function.
- Deletes that document using Appwrite’s `deleteDocument()` method
- Alerts us if we delete an item

Our blog page is incomplete without the styling. We add these styles in our `global.css` file.

{% embed https://gist.github.com/Tundesamson26/0f09b2ca313fe9d2cfeb99e6adceb238 %}

Our Blog bookmark should look like this: 

![Bookmark Blog-app](https://paper-attachments.dropbox.com/s_C222CF637E4B0001231B121EFEAD7AA1169030C2C822DCB84AC1C01B10D9C496_1650776952758_image.png)

## Conclusion

This article discussed using Appwrite to quickly create, retrieve, and delete data on our database. With this, we created a bookmarked post in a Next.js application.

## Resources 

Here are some resources that might be helpful:
- [Getting started with Appwrite for web](https://appwrite.io/docs/getting-started-for-web)
- [Database API](https://appwrite.io/docs/client/database)
- [What is Appwrite and How to use it Efficiently](https://appwrite.io/docs/getting-started-for-web)