If you have never heard of IndexDb before, do not worry, you are not going to be the first. IndexDb is a low level api that provide a non relational database, directly in your browser. This browser feature can support development in writing fully featured PWA ( progressive web app), with offline support.
In today’s article, we are going to build a service that will allow us to provide offline support for our blog. The article is going to cover the following:
- IndexDb introduction
- Introduction to IDB – IndexDb with Promises
- Database setup
- CRUD methods (Create, read, update, delete)
- Debugging
IndexDb introduction
As briefly mentioned above, IndexDb API is not widely used from many developers, but it has actually been around for quite some time.
The use of this browser feature is usually associated with development of PWA, and more precisely to provide offline support. For my personal opinion, the main features of this API are the ability to be used within the Service worker and the possibility to store BLOB – files within its store ( tables).
Support and Space limits
If you are worried about support and or the maximum size of this database, you are going to be reassured quickly.
IndexDb browser support is quite extensive, in fact it covers over 95% of the global browser usage, as shown on caniuse.com. These statistics are very reassuring, as they are as extensive as any current framework ( vue, react, angular).
Even if I would suggest you all to always try to keep its usage and size to a minimum, the API comes with a considerable space quota. The avaialble amount of space that can be used by the IndexDb ( and other low level api), is browser dependent. These amounts has changed quite a few times in the last few years, but the table below, shows the current quota ( as of november 2019), gathered from the official google developer site.
Non relational database
If you have just used relational database, such as Sql or MySql, then the use of this feature, may take some time to being fully understood.
The main different is the “loose” definition of tables column and type, but a full article explaining the differences and its usage can be found on pluralsight.
Basic features
In this section we are going to introduce some of the vocabulary that will be used later in the course of this article.
Store
If you have ever worked with any sort of database, you have surely heard of Tables. When using IndexDb this are called Stores.
versions
Due to the great flexibility provided by non relational database ( ability to save different data structure ), it is vital to use its versioning feature.
Async
This is not actually a feature and/or a feature name. But just a warning to remind you that ALL features offered by IndexDb are asyncronous, and currently natively set using callbacks and events (we are going to use a library to help us with this).
Index
This low level API has the ability to create indexes within their stores. If you have never heard of indexes, in simple words, they allow you to “quickly” find entries within your store.
Introduction to IDB
IndexDb is a fantastic feature, and I really suggest you all to get your hand upon it and start using it. Unfortunately, it has a very big disadvantage, it is event driven, and it does not fit current development methodology (promises and async/await).
To help us in that, we are going to use a simple library called idb (
https://github.com/jakearchibald/idb ). There are many library out there that provide greater support, but I am faithful that the actual API is going to develop overtime, and starting to use a “fully featured framework”, may not be necessary in the near future.
This library can either be installed by NPM
npm install idb
import { openDB, deleteDB, wrap, unwrap } from 'idb';
async function doDatabaseStuff() {
const db = await openDB(…);
}
or use it directly from unpkg
<script type="module">
import { openDB, deleteDB, wrap, unwrap } from 'https://unpkg.com/idb?module';
async function doDatabaseStuff() {
const db = await openDB(…);
}
</script>
Database Setup
It is now time to start and code our application. We are going to build a simple service that can be used to store and fetch out posts ( and as mentioned above), be used to provide content for our site in case of offline usage.
In our first step, we are going to create a database. With IndexDb we can create as many database as we want ( in fact, you may already have a few created by packages and libraries).
To create a database we need to use the openDB method. This method is going to try and open the DB, and in the case in which the database or its current version is currently available, it will “create an instance of it”.
async function _init(DB_NAME, VERSION_NUMBER) {
_db = await openDB(DB_NAME, VERSION_NUMBER, {
updated(){ //callback used to define the new database instance }
});
}
_init("Blog", 1)
The above code would work as intended, as indexDB does not you to set up individual tables and column as other conventional databases.
But there may be time, when you may need to define more control to the store (table) of your database.
As I previously mentioned, the upgrade callback is the method called to support us in creating and or upgrading existing database.
For example, with the following snippets, we are going to create a couple of store (blogs, authors), and set an auto increment column called ID.
upgrade(db) {
const storeName = ["blogs", "authors"];
tableNames.map(storeName =>{
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName, { keyPath: "id", autoIncrement:true });
}
});
}
Due to the nature of a JSON based database, this is all that is needed, and we do not need to go in details for each of the columns. The above code would be enough to run CRUD operations on the store created.
CRUD operations
It is not time to fill our database with data, and luckily this is quite simple with IDB. We are going to complete the following actions:
- Create
- GetAll
- GetOne
- Delete
- Count
Create
In our first action, we are going to insert some data into our database. To achieve such an action, we are going to use the PUT method.
const entry = {
"title": "my blog title",
"content": "# my content markdown"
}
_db.put("blog", data);
GetAll and GetOne
Now that our table is starting to be filled with data, it is time to have a way to “retrieve” the data. To fetch the full content of a table, we can use the GetAll method, otherwise we would be able to retrieve a specific entry with the use of the Get method and an unique ID, and we have previously specify as the ID column with the use of the keypath method during our store creation.
IndexDB action are asynchronous, and for this reason, we are going to use the async / await methodology to wait for the promise issued by our wrapper IDB.
//get all entry
const blogs = await _db.getAll("blogs");
get a specific entry
const blog = await _db.get("blogs", 1)
Delete
There would be time when we need to remove some of the entry within our database.
Luckily, this is going to be as easy as create it. The use of the Delete method, with a specific ID would be sufficient to achieve our needs:
//delete a specific entry
_db.delete("blogs", 1);
Count
IndexDb provides us with some out of the box functionality such as the count method. This is going to return the number of entry within a specific store.
const storeEntryCount = await _db.count("blogs");
Debugging
Debugging, for me, is one of the most important feature of any new technologies I ever try out.
I am personally the kind of developer, that need to make “mistakes” to fully learn, but I also need a way to “see” this mistakes to fully learn from them.
As it turned out, IndexDb is extremely simple to debug, as you will surely already have the debugging tools needed to improve your skills: Google Chrome.
By being a developer, I assume that you are already familiar with the Chrome debugger.
IndexDb feature can be found within the Application tab of the debugging tool. If you have ever worked with “Local Storage” and/or “Session storage”, then introducing yourself to indexDb is going to be extremely simple.
Chrome provides us with everything we need to really make the most of this Database, with the simple UI that only google can provide.
Conclusion
IndexDb is a very powerful resource, but it lacks the resources necessary for every developer to start and use it.
If you are willing to have a little struggle with not enough resources, but are eager to get ahead on the “offline support” development, than I really hope that this blog post will provide you with enough information to get you started.
If you have any question about this article, and/or about the technology above mentioned, please do not hesitate to get in touch.