Build a Jamstack app with Tigris
Tags: jamstack, tutorial
Published: 2022-12-05 15:11:50



![Jamstack Tigris App](https://blog.logrocket.com/wp-content/uploads/2022/10/jamstack-tigris-app.png)


Building a web application can be especially challenging when the developer has to set up and configure multiple tools, which might include a database, server, building tools, and storage servers. Setting up all of these can take several hours of development time, dragging out the time it takes for the product to go live.

The Jamstack was created to relieve developers of this burden, allowing them to focus on their code or business logic while developing flexible, scalable, high-performance, and maintainable web applications. In this tutorial, we'll learn how to build a Jamstack app with Tigris.

To follow along with this article, you'll need Docker and Node.js *≥*v14 installed on your machine. Let's get started!

-   [What is Tigris?](https://blog.logrocket.com/build-jamstack-app-tigris/#what-tigris)
-   [Why use Tigris?](https://blog.logrocket.com/build-jamstack-app-tigris/#why-use-tigris)
-   [Getting started with Tigris](https://blog.logrocket.com/build-jamstack-app-tigris/#v)
-   [Starting Tigris with Docker](https://blog.logrocket.com/build-jamstack-app-tigris/#start-tigris-docker)
-   [Create a RESTful web app](https://blog.logrocket.com/build-jamstack-app-tigris/#create-restful-web-app)
    -   [Create the model](https://blog.logrocket.com/build-jamstack-app-tigris/#create-the-model)
    -   [Create the controllers](https://blog.logrocket.com/build-jamstack-app-tigris/#create-the-controller)
    -   [Configure the application](https://blog.logrocket.com/build-jamstack-app-tigris/#configure-application)
-   [Test the application](https://blog.logrocket.com/build-jamstack-app-tigris/#test-application)

What is Tigris
--------------

[Tigris](https://www.tigrisdata.com/) is an open source, modern, scalable backend for developing real-time websites and apps. With its zero-ops approach, Tigris frees developers to concentrate on their applications. Tigris is a data platform that allows developers to build real-time applications without having to deal with all of the tedious infrastructure management, allowing for more code-focused development and less data infrastructure.

It's important to keep in mind that at the time of writing, Tigris is in beta.

Why use Tigris?
---------------

Let's consider some of the reasons you might choose Tigris for your web applications. For one, it handles all deployment, configuration, security, monitoring, and maintenance tasks, as well as infrastructure components. It is an alternative to traditional data handling methods like query tuning, index management, and maintenance.

Every Tigris application includes a database by default, so there is no need to learn a new database language. Tigris maintains data control while avoiding vendor lock-in, and it eliminates data silos and sprawling data infrastructure.

Getting started with Tigris
---------------------------

With the above requirements met, let's get started by scaffolding a Tigris application with the command below:

```
mkdir tigris-app && cd tigris-app
npx create-tigris-app
```

The command above will create a `tigris-app` folder and scaffold a new Tigris application with the folder structure below:

```
tigris-app
┣ src
 ┃ ┣ lib
 ┃ ┃ ┗ config.ts
 ┃ ┣ models
 ┃ ┃ ┗ user.ts
 ┃ ┣ app.ts
 ┃ ┗ index.ts
 ┣ package-lock.json
 ┣ package.json
 ┗ tsconfig.json
```

-   `index.ts`: The entry-point for the generated application
-   `app.ts`: The application class that initializes the Tigris client
-   `models/user.ts`: Contains the data container and schema for the user collection. Here, all the schemas in the Tigris application are defined

You can modify the project structure however you prefer.

Starting Tigris with Docker
---------------------------

To run the Tigris server, run the command below to [run the Docker image](https://blog.logrocket.com/node-js-docker-improve-dx-docker-compose/) for Tigris:

```
docker run -d -p 8081:8081 tigrisdata/tigris-local
```

The command above will run Tigris on `localhost:8081`. Now, run the application with the command below:

```
npm run start
```

The command above will run the default operations configured in the project, but we'll change these later.

Create a RESTful web app
------------------------

With our application created and running, let's modify the project to create a RESTful web application for a blog website. To get started, [install Express](https://blog.logrocket.com/express-js-5-migration-guide/) with the command below:

```
npm install express @types/express
```

Then, create a `controllers` folder in the `src` directory.

### Create the model

Tigris allows you to declare data models as part of the application and then convert them to appropriate objects, like collections. We'll do that in the model's folder. Rename the `models/user.ts` file to `blog.ts` and replace the existing code with the code snippets below:

```shell
import {
    TigrisCollectionType,
    TigrisDataTypes,
    TigrisSchema
} from "@tigrisdata/core/dist/types";

export interface Blog extends TigrisCollectionType {
    id?: number;
    title: string;
    content: string;
    description: string
}

export const blogSchema: TigrisSchema<Blog> = {
    id: {
        type: TigrisDataTypes.INT32,
        primary_key: {
            order: 1,
            autoGenerate: true,
        },
    },
    title: {
        type: TigrisDataTypes.STRING,
    },
    content: {
        type: TigrisDataTypes.STRING,
    },
    description: {
        type: TigrisDataTypes.STRING,
    },
};
```

In the code snippet above, we imported `TigrisCollectionType` to define the interface type for the blogs we are creating, `TigrisDataTypes` to define the data types of the fields in our `blog` schema, and `TigrisSchema` to define the schema type.


Next, we created the `blog` schema and defined the fields. We have an `id` that is an auto-generated primary key, as well as a `title`, `content`, and a `description` for each blog.

### Create the controllers

With the schema created, let's create the controllers of our application. To get started, create `blog.ts` and `controller.ts` files in the `controllers` directory. In the code snippet below, we'll define an interface to set up the routes for this application in the `controller.ts` file:

```shell
import express from "express";

export interface Controller {
    setupRoutes(app: express.Application);
}
```

Then, in the `controller/blog.ts` file, we'll create the required imports, create a `BlogController` class, and define the required variables with the code below:

```shell
import express, { Request, Response, Router } from "express";
import { Collection, DB } from "@tigrisdata/core";
import { Blog } from "../models/blog";
import { Controller } from "./controller";

export class BlogController implements Controller {
   private readonly db: DB;
   private readonly blogs: Collection<Blog>;
   private readonly router: Router;
   private readonly path: string;

  constructor(db: DB, app: express.Application) {
    this.blogs = db.getCollection<Blog>("blogs");
    this.path = "/blogs";
    this.router = Router();
    this.db = db;
  }
}
```

In the code snippet above, we imported `Collection` and `DB` from Tigris, the `Blog` schema, and the `Controller` interface. Then, we defined the global variables and assigned the appropriate values and method to them in our constructor method.

Now, let's add CRUD methods to the class with the code snippets below:

```shell
//...
  public createBlog = async (req: Request, res: Response) => {
        try {
            const newBlog = await this.blogs.insert(req.body);

            res.status(200).json({
                data: newBlog,
                message: "Blog Created!",
            });
        } catch (e) {
            res.status(500).json({
                message: "An error occured:" + e,
            });
        }
    }
    public getBlogs = async (req: Request, res: Response) => {
        try {
            const blogs = await this.blogs.findMany(req.body);
            res.status(200).json({
                data: blogs
            });
        } catch (e) {
            res.status(500).json({
                message: "An error occured:" + e,
            });
        }
    }

    public getBlog = async (req: Request, res: Response) => {
        try {
            const blog = await this.blogs.findOne({
                id: Number.parseInt(req.params.id),
            });
            if (!blog) {
                return res.status(404).json({
                    data: blog,
                    message: "Blog not found!",
                });
            }
            return res.status(200).json({
                data: blog
            });
        } catch (e) {
            res.status(500).json({
                message: "An error occured:" + e,
            });
        }
    };

    public updateBlog = async (req: Request,
        res: Response,) => {
        try {
            await this.blogs.update({ id: parseInt(req.params.id) }, req.body);
            res.status(200).json({
                message: "Blog Updated"
            });

        } catch (e) {
            res.status(500).json({
                message: "An error occured:" + e,
            });
        }
    }
    public deleteBlog = async (
        req: Request,
        res: Response,
    ) => {
        try {
            await this.blogs.delete({
                id: Number.parseInt(req.params.id),
            });
            res.status(200).json({
                message: "Blog deleted",
            });
        } catch (e) {
            res.status(500).json({
                message: "An error occured:" + e,
            });
        }
    };
  //...
```

In the code snippet above, we used the blog's instance, which is the collection for our `Blog` schema we accessed through the `db.getCollection` function. This function provides us with the method we need to perform CRUD operations in our database.

Then, set up the routes for this method by adding the method below:

```shell
//...
   public setupRoutes(app: express.Application) {
        this.router.post(`${this.path}/`, this.createBlog);
        this.router.get(`${this.path}/`, this.getBlogs);
        this.router.get(`${this.path}/:id`, this.getBlog);
        this.router.put(`${this.path}/:id`, this.updateBlog);
        this.router.delete(`${this.path}/:id`, this.deleteBlog);
        app.use("/", this.router);
    }
//...
```


In the code snippet above, we used the Express router, which is accessible through the `router` instance, to define the route's endpoints for each method in our `BlogController`. Lastly, call the `setupRoutes` method in the constructor method:

```shell
constructor(db: DB, app: express.Application){
   // ...
   this.setupRoutes(app);
   //...
}
```

### Configure the application

With the controllers and routes set up, let's configure the application, initialize Tigris, create a database for the application, and create a blog collection. To get started, delete the code in the `app.ts` file and replace it with the code snippets below:

```shell
import { DB, Tigris } from "@tigrisdata/core";
import { Blog, blogSchema } from "./models/blog";
import express from "express";
import { BlogController } from "./controllers/blog";

export class Application {
    private readonly tigris: Tigris;
    private db: DB
    private readonly app: express.Application;
    private readonly PORT: string | number;
    private readonly dbName: string;

    constructor(tigris: Tigris) {
        this.tigris = tigris
        this.app = express()
        this.PORT = 3000;
        this.dbName = 'tigris_blog'
        this.setup();
    }

    public async setup() {
        this.app.use(express.json());
        await this.initTigris();
    }

    public async initTigris() {
        //create a database
        this.db = await this.tigris.createDatabaseIfNotExists(this.dbName);
        console.log('database created successfully')

        //register collections
        await this.db.createOrUpdateCollection<Blog>('blogs', blogSchema);

        //setup controllers
        new BlogController(this.db, this.app);
    }
    public start() {
        this.app.listen(this.PORT, () => {
            console.log(`Server is running at ${this.PORT}`)
        })
    }
}
```



In the code above, we imported and defined the modules and global variables we need in this class. We create a setup method where we create the middleware of the application and initialize Tigris by calling the `initTigris` method, which will create a database and our blog collection. We also create a start method to run the application on `port 3000`, as defined by the `PORT` variable.

Now, let's modify the `index.ts` file to call the `start` method in our `Application` class, which will start running the server:

```
//.. app.start();
```

Lastly, ensure that your Tigris client `serverUrl`, which was initialized in the `lib/config` file, is listening to `localhost:8081`, as shown in the code snippet below:

```shell
import {Tigris} from "@tigrisdata/core";

export class Config {
    public initializeTigrisClient(): Tigris {
        return new Tigris({
            serverUrl: "localhost:8081",
            insecureChannel: true,
        });
    }
}
```


Test the application
--------------------

Now, let's test the application using cURL. Run the command below to create a new blog:

```shell
curl http://localhost:4000/blogs \
    -X POST \
    -H 'Content-Type: application/json' \
    -d '{
        "title": "Build a web app with Node.js",
        "content": "Content goes here",
        "description":"Description goes here"
      }'
```

You should get a response as shown in the screenshot below:

![Test Application Curl Result](https://blog.logrocket.com/wp-content/uploads/2022/10/test-application-curl-result.png)

Conclusion
----------

In this tutorial, we've learned how to build a Jamstack application with Tigris. We started by introducing Tigris and discussing why you should consider using it. Then, as a demonstration, we built a RESTful web application to manage a blog.

Tigris is an exciting tool, and I recommend checking out the [Tigris documentation](https://www.tigrisdata.com/) to learn more. I hope you enjoyed this article, and happy coding!


Author: [Ekekenta Odionyenfe](https://blog.logrocket.com/author/ekekenteodionyenfe/)