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. - An Appwrite instance running on our computer; check this documentation 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 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:
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:
cd <name of our project>
npm run dev
To see our app, we then go to 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 that can help us with this. Let’s install it.
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 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.
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 or as specified during Appwrite's installation.
On the console, there is a Create Project button. Click on it to start a new project.
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.
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:
// 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.
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.
Creating the Blog Application
We create this blog application with the GitHub gist 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.
In the index.js
, we have the following:
- Import required dependencies and components
- Passed
posts
as props from thePost.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 theexcerpt
of the blog post
Our application should look like this by now:
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.
import sdk from '../utils/web-init';
Next, we create an anonymous user session once our app is mounted in the components/Post.js
file.
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.
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.
<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.
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.
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.
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.
Our Blog bookmark should look like this:
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: