Node.js – API With SQLite Database

Table of Contents
Overview
This article will go through the steps needed to create an API with Node.js. The back end will use the lightweight, portable, and feature rich SQLite. The API will create the database file if it doesn’t exist and insert four records to get things started. The API will also have actions for create, read, update, and delete.
Download the Example
Source CodeSQLite
The API should be able to run without SQLite installed. The sqlite3 library should be able to perform CRUD operations on a sqlite3 database file.
At the time this post was written version 3.36.0 was available.
Install SQL Lite https://www.sqlite.org/download.html.
For a quick how to article on installing SQLite please read this article.
Prerequisites
If you don’t already have Node.js installed then you can get the download and install information from their website at https://nodejs.org/.
Install Express
Create a folder for your project and go into that directory and run the following commands.
npm init
npm install express
Install Nodemon
Nodemon restarts the node.js application when changes are made.
npm install nodemon
Update the “scripts” section of the “package.json” file with the following:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon app.js"
},
To start the application use npm start instead of node app.js
Install the SQL Lite Driver.
npm install sqlite3
Handling CORS
Cross Origin Resource Sharing is needed if you want to use the API with an external application.
npm i cors
Building The API
App.js
Create a file labeled “./app.js” in the root folder of the API.
All of the imports needed to run the API. This includes the SQLite3 library and Cross Origins. The port is set to 3004.
const express = require('express');
const app = express();
const port = 3004;
var sqlite3 = require('sqlite3').verbose()
const cors = require('cors');
The following will connect to a database labeled productsdb.sqlite. If the database doesn’t exist it will create it and insert four records.
const DBSOURCE = "productsdb.sqlite";
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
// Cannot open database
console.error(err.message)
throw err
}else{
// ** EXAMPLE **
// ** For a column with unique values **
// email TEXT UNIQUE,
// with CONSTRAINT email_unique UNIQUE (email)
db.run(`CREATE TABLE Products (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Title TEXT,
Quantity INTEGER,
DateModified DATE,
DateCreated DATE
)`,
(err) => {
if (err) {
// Table already created
}else{
// Table just created, creating some rows
var insert = 'INSERT INTO Products (Title, Quantity, DateCreated) VALUES (?,?,?)'
db.run(insert, ["Baseball", 3, Date('now')])
db.run(insert, ["Football", 5, Date('now')])
db.run(insert, ["Apple", 6, Date('now')])
db.run(insert, ["Orange", 7, Date('now')])
}
});
}
});
The app.use() will need the “express.urlencoded()” to read the incoming packets and the CORS for API calls made from a JavaScript web application.
app.use(
express.urlencoded(),
cors({
origin: 'http://localhost:3000'
})
);
API CRUD Operations
The following are the API actions for Get All records.
app.get("/api/products", (req, res, next) => {
var sql = "SELECT * FROM Products"
var params = []
db.all(sql, params, (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
res.json({
"message":"success",
"data":rows
})
});
});
Get Single Product
app.get("/api/product/:id", (req, res, next) => {
var sql = "SELECT * FROM Products WHERE Id = ?"
db.all(sql, req.params.id, (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
res.json({
"message":"success",
"data":rows
})
});
})
Insert a new record
app.post("/api/product", (req, res) => {
var errors=[]
if (!req.body.Title){
errors.push("Title is missing");
}
if (!req.body.Quantity){
errors.push("Quantity is missing");
}
if (errors.length){
res.status(400).json({"error":errors.join(",")});
return;
}
var data = {
Title: req.body.Title,
Quantity: req.body.Quantity,
DateCreated: Date('now')
}
var sql ='INSERT INTO Products (Title, Quantity, DateCreated) VALUES (?,?,?)'
var params =[data.Title, data.Quantity, Date('now')]
db.run(sql, params, function (err, result) {
if (err){
res.status(400).json({"error": err.message})
return;
}
res.json({
"message": "success",
"data": data,
"id" : this.lastID
})
});
})
Update an existing record
app.patch("/api/product/:id", (req, res, next) => {
var data = [req.body.Title, req.body.Quantity, Date('now'), req.params.id];
let sql = `UPDATE Products SET
Title = ?,
Quantity = ?,
DateModified = ?
WHERE Id = ?`;
db.run(sql, data, function(err) {
if (err) {
return console.error(err.message);
}
console.log(`Row(s) updated: ${this.changes}`);
});
res.json({
message: "success",
data: data,
changes: this.changes
})
})
Delete a record by ID.
app.delete("/api/product/:id", (req, res, next) => {
db.run(
'DELETE FROM Products WHERE id = ?',
req.params.id,
function (err, result) {
if (err){
res.status(400).json({"error": res.message})
return;
}
res.json({"message":"Deleted", changes: this.changes})
});
})
Last but not least add the listener for the port
app.listen(port, () => console.log(`API listening on port ${port}!`));
All Together
const express = require('express');
const app = express();
const port = 3004;
var sqlite3 = require('sqlite3').verbose()
const cors = require('cors');
const DBSOURCE = "productsdb.sqlite";
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
// Cannot open database
console.error(err.message)
throw err
}else{
// ** EXAMPLE **
// ** For a column with unique values **
// email TEXT UNIQUE,
// with CONSTRAINT email_unique UNIQUE (email)
db.run(`CREATE TABLE Products (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Title TEXT,
Quantity INTEGER,
DateModified DATE,
DateCreated DATE
)`,
(err) => {
if (err) {
// Table already created
}else{
// Table just created, creating some rows
var insert = 'INSERT INTO Products (Title, Quantity, DateCreated) VALUES (?,?,?)'
db.run(insert, ["Baseball", 3, Date('now')])
db.run(insert, ["Football", 5, Date('now')])
db.run(insert, ["Apple", 6, Date('now')])
db.run(insert, ["Orange", 7, Date('now')])
}
});
}
});
module.exports = db
app.use(
express.urlencoded(),
cors({
origin: 'http://localhost:3000'
})
);
app.get('/', (req, res) => res.send('API Root'));
// GET ALL
app.get("/api/products", (req, res, next) => {
var sql = "SELECT * FROM Products"
var params = []
db.all(sql, params, (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
res.json({
"message":"success",
"data":rows
})
});
});
// GET SINGLE USER
app.get("/api/product/:id", (req, res, next) => {
var sql = "SELECT * FROM Products WHERE Id = ?"
db.all(sql, req.params.id, (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
res.json({
"message":"success",
"data":rows
})
});
})
// CREATE
app.post("/api/product", (req, res) => {
var errors=[]
if (!req.body.Title){
errors.push("Title is missing");
}
if (!req.body.Quantity){
errors.push("Quantity is missing");
}
if (errors.length){
res.status(400).json({"error":errors.join(",")});
return;
}
var data = {
Title: req.body.Title,
Quantity: req.body.Quantity,
DateCreated: Date('now')
}
var sql ='INSERT INTO Products (Title, Quantity, DateCreated) VALUES (?,?,?)'
var params =[data.Title, data.Quantity, Date('now')]
db.run(sql, params, function (err, result) {
if (err){
res.status(400).json({"error": err.message})
return;
}
res.json({
"message": "success",
"data": data,
"id" : this.lastID
})
});
})
// UPDATE
app.patch("/api/product/:id", (req, res, next) => {
var data = [req.body.Title, req.body.Quantity, Date('now'), req.params.id];
let sql = `UPDATE Products SET
Title = ?,
Quantity = ?,
DateModified = ?
WHERE Id = ?`;
db.run(sql, data, function(err) {
if (err) {
return console.error(err.message);
}
console.log(`Row(s) updated: ${this.changes}`);
});
res.json({
message: "success",
data: data,
changes: this.changes
})
})
app.delete("/api/product/:id", (req, res, next) => {
db.run(
'DELETE FROM Products WHERE id = ?',
req.params.id,
function (err, result) {
if (err){
res.status(400).json({"error": res.message})
return;
}
res.json({"message":"Deleted", changes: this.changes})
});
})
app.listen(port, () => console.log(`API listening on port ${port}!`));
Try It
Run the application
If you installed nodemon and updated the package.json file then use npm start instead of node app.js
npm start
Without nodemon installed
node app.js
Try calling the API actions in something like PostMan or Insomnia.
Examples with Postman
GET – Gets all records
http://localhost:3004/api/products

GET – Gets a single record
http://localhost:3004/api/product/4

Post
http://localhost:3004/api/product
Click on Body and x-www-form-urlencoded and input the Title and Quantity fields.

DELETE
http://localhost:3004/api/product

Troubleshooting
If the API Cannot Read the Request Data
If the API cannot read the request data for Inserts and Updates you may need the body-parser library.
Some of the versions of Node.js before version 4.16 needed the body-parser library to get the contents of an API request.
npm install body-parser
In the top of the app.js file add the following
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
You must be logged in to post a comment.