Airtable: a low-code solution for building modern apps
Tags: javascript, webdev, airtable
Published: 2022-07-26 23:43:33

by [Osah Peter](https://blog.openreplay.com/authors/osah-peter)

In building applications, developers consider the hassle of setting up the server and database of an application, as well as constructing and documenting the API that enables the transfer of data between the client-side and the server-side of the application. This hassle led to the advent of [low-code database applications](https://en.wikipedia.org/wiki/Low-code_development_platform). These applications enable developers to easily set up a database. They also provide intuitive and visual tools that make the setup process and database management easier and require little code for their usage. Also, one unique advantage of utilizing them is the provision of the created database as an API that can easily be used on a client.

In this tutorial, we will look into the concept of "low-code database" applications, particularly Airtable, an easy-to-use low-code database application for creating and sharing relational databases, and the React framework to build a simple blog application.

## Low-code Database Applications

Low-code databases can be seen as tools designed with simple user interfaces that can be used successfully by users with little or no knowledge of code/programming. With a low-code database, a user can easily create databases and tables and store records. Most of the time, it only requires simple controls like dragging and dropping some icons, filling out a few forms, or clicking some items on the interface to initiate an action. This isn't new as many users are very familiar with these types of applications and use them all the time. Microsoft Access, Google sheets, Drupal, and Joomla, are examples of low-code solutions.

The advantages of using low-code solutions include:

- Ease of Operation — Users can easily operate these applications without needing developers.
- Ease of Record keeping — Users can create databases and tables to store records with little or no assistance from developers.
- Integration to third-party services — Developers could easily integrate these solutions into many third-party cloud services and applications.

In this article, our focus will be on Airtable, a low-code database application.



## Airtable

Airtable is a simple cloud database platform with features of a database implemented as spreadsheets. It is a low-code application that provides a simple user interface to create and share relational databases. It helps users manage and portray their data with an aesthetically pleasing user interface. It also provides a simple-to-use dashboard for users to effectively manage these created databases.

Airtable provides many features as follows:

- Airtable provides pre-made templates that enable users to easily create a database.
- Airtable provides Document Storage, meaning users can attach files as records to the database.
- On Airtable, a user can integrate third-party applications, i.e., project management applications like Slack, Asana, Basecamp, Box, and file storage applications like Dropbox, Google Drive, and many more. To see the list of third-party applications supported by Airtable, visit [here](https://www.airtable.com/integrations).

- With Airtable, there are provisions for custom views. a user can view his database in various view types: grid view, gallery view, Kanban view, and Calendar view.

![1](https://blog.openreplay.com/static/e5364f81c6895d83ad3f31a1761064fa/1a152/image01.png)

![2](https://blog.openreplay.com/static/f7b0f1c411819c3ad01695e51fbc8ea5/1a152/image02.png)

![3](https://blog.openreplay.com/static/d82b90d6248391b60e0eb6b3d87ac95b/1a152/image03.png)

![4](https://blog.openreplay.com/static/f14cc18c513c4359a360a4675a9279ab/1a152/image04.png)

## Components of Airtable

There are five basic components of an Airtable database:

- A *base* is a singular database containing a project's essentials. A base contains the records that a project needs. You can start with a blank base and give it a naming convention you desire. Airtable offers a robust library of templates pre-populated with relevant sample data, which you can view and modify if you are experiencing difficulty creating a blank base or knowing how a base is structured internally. There are templates for creating various bases, which can be accessed [here](https://www.airtable.com/templates).

![5.  A sample of a base](https://blog.openreplay.com/static/cd6257397ad9edc9f969366f8c2911bd/1a152/image05.png)

- A *table* contains data about a particular type of item. A base can possess one or more tables, and a table could hold a specific type of information. For example, if we build a simple content calendar, the table will hold data like name, status, headline, sub-headline, creator, and image. The table shows the data in a spreadsheet format.

![6. the highlighted section is an example of a table](https://blog.openreplay.com/static/8c6d42531ef1e1c06b1c488332e3d4fe/1a152/image06.png)

- A *field* is a column in a table. A field has a name and can be customized to contain an array of content, like photos, phone numbers, attachments, dates, checkboxes, and more.

![7. the highlighted section is a sample of a field](https://blog.openreplay.com/static/1d86d97c91ada9e02706bec34bad5ac8/1a152/image07.png)

- A *record* is the database equivalent of spreadsheet rows and cells. Each record is an item on your list. In a table of content, each record is content, with data in each field to detail their name, status, headline, and more.

![8. the highlighted section is an example of a record](https://blog.openreplay.com/static/441334996afa38170fda9f5f999a2386/1a152/image08.png)

- A *view* enables a user to see all of the records at once in a specific format specified by Airtable. You can create multiple views for each table in a base. A view is helpful when you only want to view records that fit certain criteria.

## Airtable setup

To get started, we have to signup to Airtable. to signup to Airtable, visit [here](https://airtable.com/signup).
    
![9. signup to airtable](https://blog.openreplay.com/static/fa2b0b48e81639cde4c88f4f8e2e7f89/1a152/image09.png)

On signup,  you will be directed to the dashboard. On the dashboard, you can create a base.

![10](https://blog.openreplay.com/static/bcd1844af8086c3ca3100ae70edc0a39/1a152/image10.png)

On clicking "Add a base", you will be directed to screens that enable you to create a base, a table, create sample data to add to the table in the base. 

![11 The “get started” page](https://blog.openreplay.com/static/819850a173bc5794d943d80715dbc081/a1287/image11.png)

You have to name the base.

![12 The page to name base](https://blog.openreplay.com/static/35f07b9c23db8a91020f4caab1bf4902/1a152/image12.png)

You can populate the base with test data.

![13 The page to populate the base with test data.](https://blog.openreplay.com/static/9068e6b2fdc14cff142460412645f059/1a152/image13.png)

A sample of a created and populated base.

![14 An example of the created base with populated data](https://blog.openreplay.com/static/bf4eb98aa05f25ff030f5cbfc47c9b40/1a152/image14.png)



## Base as an API feature

A spectacular feature of Airtable makes every created Base on Airtable available as an API that can be integrated into a client application. After you've created and configured the tables and schema of an Airtable base from the user interface, your Airtable base will provide its API to create, read, update, and destroy records in it. To access this API, you must be logged in and visit [here](https://airtable.com/api). After accessing the link, you will see the bases. You can select a base to view its API documentation. 

![15 The API page shows a list of bases to view API documentation](https://blog.openreplay.com/static/f45d010f8ec1c4b69b61c25c86695323/1a152/image15.png)

This is a sample API documentation.

![16 The page of sample API Documentation for a selected base(test base)](https://blog.openreplay.com/static/7d008fef71ec85400b40f6e00f05f045/1a152/image16.png)



## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://static.openreplay.com/images/banner-blog.png)

_Start enjoying your debugging experience - [start using OpenReplay for free](https://github.com/openreplay/openreplay)._




## A case study

For this tutorial, we will use a sample blog application to illustrate how to use an Airtable base as an API.

![17 the base for the sample blog](https://blog.openreplay.com/static/774690daddd758222d06c8a5898ba97c/1a152/image17.png)

As shown, the blog base will hold fields like the Name of the blog post, the post itself, createdAt, and updatedAt fields, respectively.

We will need the API key and base id to connect to the base API. To get it, navigate to your [account page](https://airtable.com/account). On your account overview page, under the API heading, click a button that says "Generate API key." to generate an API key if there is none already.

![18](https://blog.openreplay.com/static/88deba5642be98f4d12b83777e94ccce/1a152/image18.png)

To obtain the ID of your Airtable base, open the Airtable API page and select the Airtable base that you want to use. This will open the API page of the base. The base ID is located at the URL of the API page of the base. In the URL, the base ID is immediately after https://airtable.com/ and starts with the app.

![19](https://blog.openreplay.com/static/7d8e680735ca752ff1eec4a6ead152b3/1a152/image19.png)

You can also get the base ID from the URL of the base on viewing a base.

### Connect Our Application To An Airtable Base

We will be using the React framework for the blog application. After creating the blog base, we need to connect the React application to the base. We can do this using the Airtable JavaScript library. You can install the Airtable library using NPM or Yarn:

```
npm install airtable
# or 
yarn add airtable 
```

### Create And Retrieve Data From An Airtable Base

As expected from a blog application, it should be able to create, retrieve/get, update, and delete posts from the blog base. The Airtable documentation provides sample queries on implementing the creation, retrieval, and deletion of data from the base. 

On the React app, we will create an airtable.ts file and add the block of code shown below:

```javascript
import Airtable from "airtable";

class AirtableClass {
  base: any;
  constructor(apiKey: string, base: string) {
    this.base = new Airtable({ apiKey }).base(base);
  }
  async getAllBlogPosts(callback: Function, error: Function) {
    try {
      let eachPageRecords = await this.base("blog")
        .select({ view: "Grid view" })
        .eachPage(
          callback && typeof callback === "function" ? callback : () => {}
        );
      return eachPageRecords;
    } catch (err) {
      error && typeof error === "function" && error(err);
      throw new Error("unable to get all records");
    }
  }
  async getSingleBlogPost(id: string, callback: Function) {
    try {
      const record = await this.base("blog").find(id);
      console.log("single record", record);
      callback(record, null);
    } catch (err) {
      callback(null, err);
      throw new Error("error getting a single blog");
    }
  }
  async createBlog(post: any, callback: Function) {
    try {
      let record = await this.base("blog").create(post);
      console.log("created blog");
      callback(record, null);
    } catch (err) {
      callback(null, err);
      throw new Error("error creating blog");
    }
  }
  async updateBlog(post: any, callback: Function) {
    try {
      let record = await this.base("blog").update(post);
      console.log("successfully updated blog");
      callback(record, null);
    } catch (err) {
      callback(null, err);
      throw new Error("error creating blog");
    }
  }
  async deleteBlog(postId: any, callback: Function) {
    try {
      let record = await this.base("blog").destroy(postId);
      callback(record, null);
    } catch (err) {
      callback(null, err);
      throw new Error("error deleting a blog");
    }
  }
}

export default new AirtableClass(
  process.env.REACT_APP_AIRTABLE_KEY,
  process.env.REACT_APP_BASE_KEY
);
```

The code above is simply an Airtable class with the methods to implement these queries.

- the class contains a base constructor. This constructor instantiates a new Airtable Object from the library using the API key and the base id.
```javascript
this.base = new Airtable({apiKey}).base(base);
```

- the method below gets all blog posts from the base. This method contains a success callback(callback) function and an error callback function.

- on the success of fetching the blog posts from the base, the callback function returns two(2) parameters: records, the fetched blog records, and fetchNextPage - a function that lets us fetch more contents from Airtable if there is any. Airtable, by default, supports pagination. Therefore, this is a function to call the next page of the paginated records from Airtable.

- if an error is encountered on fetching the blog posts, it is passed to the error callback function, which can show on the UI that an error occurred.

```javascript
async getAllBlogPosts(callback: Function, error: Function) {
  try {
    let eachPageRecords = await this.base("blog")
      .select({ view: "Grid view" })
      .eachPage(
        callback && typeof callback === "function" ? callback : () => {}
      );
    return eachPageRecords;
  } catch (err) {
    error && typeof error === "function" && error(err);
    throw new Error("unable to get all records");
  }
}
```

- the method below fetches a blog post. this method also contains a callback function that returns two(2) parameters: records, the fetched blog record, and error, the error value in case the blog record was not obtained. 

```javascript      
async getSingleBlogPost(id: string, callback: Function) {
  try {
    const record = await this.base("blog").find(id);
    console.log("single record", record);
    callback(record, null);
  } catch (err) {
    callback(null, err);
    throw new Error("error getting a single blog");
  }
}
```

- the method below adds a blog post.

```javascript
async createBlog(post: any, callback: Function) {
  try {
    let record = await this.base("blog").create(post);
    console.log("created blog");
    callback(record, null);
  } catch (err) {
    callback(null, err);
    throw new Error("error creating blog");
  }
}
```

- the method below updates a blog post.

```javascript
async updateBlog(post:any, callback:Function){
  try {
    let record = await this.base('blog').update(post)
    console.log('successfully updated blog')
    callback(record, null)
  } catch (err) {
    callback(null, err)
    throw new Error('error creating blog')
  }
}
```

- the method below deletes a single blog post. 

```javascript
async deleteBlog(postId:any, callback:Function){
  try {
    let record = await this.base('blog').destroy(postId)
    callback(record, null)
  } catch (err) {
    callback(null, err)
    throw new Error('error deleting a blog')
  }
}
```

### Display Blog posts

On the app, we will create a component for listing all blog posts and add the block of code shown below:

```javascript
import React, { useEffect, useState } from "react";
import airtable from "../../airtable";

const Home = () => {
  const nextPage = (): void => {
    setPageNumber(pageNumber + 1);
  };
  useEffect(() => {
    setLoading(true);
    airtable.getAllBlogPosts(
      function page(records: any, fetchNextPage: any) {
        let recordsArray: Array<any> = [];
        recordsArray = [...recordsArray, ...records];
        setAllPosts(recordsArray);
        fetchNextPage();
        setLoading(false);
      },
      (error: any) => {
        error && setLoading(false);
      }
    );
  }, []);
  return <div>The UI goes in here....</div>;
};
export default Home;
```

In the code above, the method for fetching all blog post records is called on the component, after which the results of the fetched records are then mapped into the component's view. The picture below shows the records rendered on the component view.

![20 The component for viewing all blog posts](https://blog.openreplay.com/static/ec05c57aef74a9f3688c06d1ab43b263/1a152/image20.png)

### Create posts

We will also create a component for creating a blog post and add the block of code shown below:

```javascript
import React, { useState } from "react";
import airtable from "../../airtable";

const CreatePost = () => {
  const [loading, setLoading] = useState < boolean > false;
  const [placeholder, setPlaceholder] = useState("type your text");
  const [form, setForm] =
    React.useState <
    any >
    {
      Name: null,
      post: null,
    };
  const { id } = useParams();
  let navigate = useNavigate();

  const createPost = async () => {
    setLoading(true);
    airtable.createBlog(form, (records: any, error: any) => {
      if (records) {
        navigate("/");
      }
      if (error) {
        alert("unable to create post");
      }
      setLoading(false);
    });
  };

  return <div>The UI goes in here.....</div>;
};
export default CreatePost;
```    

In the code above, the method for creating a blog post is called when a user inputs the details required to create a blog post, like the name of the post and the content, respectively. The picture below shows the component with the inputs.

![21 the component for creating a blog post](https://blog.openreplay.com/static/344803850fb5f8f5ba87d55724efaf22/1a152/image21.png)

### Updating posts

We will also create a component for updating a blog post and add the block of code shown below:

```javascript
import React, { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import airtable from "../../airtable";

const UpdatePost = () => {
  const [loading, setLoading] = useState < boolean > false;
  const [loadingApiState, setloadingApiState] = useState < boolean > false;
  const [singlePost, setSinglePost] =
    useState <
    any >
    {
      id: null,
      fields: {
        Name: "",
        post: "",
      },
    };
  const { id } = useParams();
  let navigate = useNavigate();
  const updatePost = async () => {
    const post = [];
    post.push(singlePost);
    setloadingApiState(true);
    airtable.updateBlog(post, () => {
      setloadingApiState(false);
      navigate(`/posts/${id}/view`);
    });
    setLoading(false);
  };
  useEffect(() => {
    setLoading(true);
    airtable.getSingleBlogPost(id, (records: any, error: any) => {
      if (records) {
        setSinglePost({
          id: records.id,
          fields: {
            Name: records.fields.Name,
            post: records.fields.post,
          },
        });
      }
      if (error) {
      }
      setLoading(false);
    });
  }, []);
  return <div>The UI goes in here.....</div>;
};
export default UpdatePost;
```    

In the code above, we render the blog post after the method for fetching the blog post is called. The component also provides inputs so that we can update a blog post. On submission of the updates, it calls the method that updates the blog record on Airtable.

![22 the component for updating a blog post](https://blog.openreplay.com/static/d4f9e508b2b3a2555c6974ee0134c7dd/1a152/image22.png)

### Viewing a post

We will also create a component for viewing a blog post and add the block of code shown below:

```javascript
import React, { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import airtable from "../../airtable";

const PostView = () => {
  const [loading, setLoading] = useState < boolean > false;
  const [singlePost, setSinglePost] = useState < any > null;
  const [loadingApiState, setloadingApiState] = useState < boolean > false;
  const { id } = useParams();
  let navigate = useNavigate();
  const deletePost = async () => {
    const postId = [];
    postId.push(id);
    setloadingApiState(true);
    airtable.deleteBlog(postId, (record: any, error: any) => {
      if (record) {
        navigate(`/`);
      }
      if (error) {
      }
      setloadingApiState(false);
    });
    setLoading(false);
  };
  useEffect(() => {
    setLoading(true);
    airtable.getSingleBlogPost(id, (records: any, error: any) => {
      if (records) {
        setSinglePost(records);
      }
      if (error) {
      }
      setLoading(false);
    });
  }, []);
  return <div>The UI goes in here .....</div>;
};
export default PostView;
```    

In the code above, we render the blog post after the method for fetching the blog post is called. 

### Deleting posts

The code also contains the method to delete a blog post, which is fired on clicking the "Delete Post" button on the component.

![23 the component for viewing and deleting a blog post](https://blog.openreplay.com/static/067514de82e4fcdcde821fd979e80dc8/1a152/image23.png)

To see more of the translated user interface code on the respective components, you can check the Github repository [here](https://github.com/Gitarackur/Airtable-Blog).
 

## Conclusion

In this tutorial, we looked into the concept of "low-code database" applications and their advantages. We also talked about our low-code database of interest-- "Airtable," and its features. Lastly, we built a simple blog application with react and used Airtable as the database thanks to the Airtable base API.



## RESOURCES
- https://github.com/Gitarackur/Airtable-Blog
- https://www.airtable.com
- https://airtable.com/api
- https://clickup.com/blog/airtable-review/
- https://venturebeat.com/2021/02/15/what-are-low-code-databases/
- https://www.airtable.com/integrations


[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)