Supa-Fast API (Supabase FastAPI) : Building the API

aunicorndev

Yashasvi Singh

Posted on January 12, 2022

Supa-Fast API (Supabase FastAPI) : Building the API

In this is the second part of the series, we will be looking at building the API using FastAPI and Supabase python client.


Prerequisites

  • Have a database set up on Supabase(can match the database set up in the last tutorial)
  • Comfortable with Python (including Virtual Environments)
  • An Idea of what Environment Variables are
  • JSON format

Setting up FastAPI

 

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.

 

Installing python 3.7.5

To get started , make sure you have python > 3.7 as the latest supabase client uses that.

Download python 3.7.5 from here.

Install it with the Add to path flag checkbox enabled.

Install Python 3.7.5

To list all the installed python on your system use the below command

 

> py -0  

Installed Pythons found by C:\Windows\py.exe Launcher for Windows
 -3.7-32 *
 -3.6-32


Enter fullscreen mode Exit fullscreen mode

Creating test FastAPI

Navigate to the folder where you want to create your project and run the following commands

mkdir supafast-api

cd .\supafast-api\


Enter fullscreen mode Exit fullscreen mode

Create and activate a Virtual Environment with the latest installed python using the given commands

virtualenv venv-supaFastApi --python=python3.7

.\venv-supaFastApi\Scripts\activate


Enter fullscreen mode Exit fullscreen mode

Create an api folder in which the main login for the API will reside.. Name the file as main.py

Note: Do not name the file other than main.py as it is required for deployment.

mkdir api

cd .\api

cd. >main.py
Enter fullscreen mode Exit fullscreen mode
pip install fastapi

pip install "uvicorn[standard]"
Enter fullscreen mode Exit fullscreen mode

 

In the main.py file, add the code below and run the API using uvicorn to test if everything works properly.

#main.py

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    return {"message": "Hello World Test"}
Enter fullscreen mode Exit fullscreen mode
uvicorn main:app --reload

http://127.0.0.1:8000/

Enter fullscreen mode Exit fullscreen mode

A response similar to this should appear on the screen at http://127.0.0.1:8000/

// 20211127160738
// http://127.0.0.1:8000/

{
  "message": "Hello World Test"
}
Enter fullscreen mode Exit fullscreen mode

TIP : use JSON Viewer Chrome Extension to view prettified JSON in the browser.

Now that the test FastAPI is working, let's get started and add the Supabase Python client
to get data in the API.


Using Data from Supabase

GitHub logo supabase-community / supabase-py

Python Client for Supabase

pip install supabase
Enter fullscreen mode Exit fullscreen mode

We need to use the SUPABASE_URL as well as SUPABASE_KEY which will be present in the settings of the Supabase project that we created in the first part of this series.

Supabase Keys

#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()


url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

supabase: Client = create_client(url, key)
Enter fullscreen mode Exit fullscreen mode

Getting Data from Database

This was the structure of the database in the Supabase and for the API ,we are going to add two endpoints in FastAPI...

  • To list down all the themes - /themes
  • To list down the monsters of a particular theme - /monsters/?theme={theme_name}
#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()
    return themes

@app.get("/monsters/")
def monsters(theme : str = "demo-theme-1"):
    monsters = supabase.table('monsters').select('*').eq('monsterTheme',theme).execute()
    return monsters 


Enter fullscreen mode Exit fullscreen mode

For the URL http://127.0.0.1:8000/themes , the result would be

// 20211127163945
// http://127.0.0.1:8000/themes

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-26T15:28:21+00:00",
      "monsterTheme": "demo-theme-1"
    },
    {
      "id": 2,
      "created_at": "2021-11-26T15:29:45+00:00",
      "monsterTheme": "demo-theme-2"
    },
    {
      "id": 3,
      "created_at": "2021-11-26T15:30:04+00:00",
      "monsterTheme": "demo-theme-3"
    },
    {
      "id": 4,
      "created_at": "2021-11-26T15:30:12+00:00",
      "monsterTheme": "demo-theme-4"
    },
    {
      "id": 6,
      "created_at": "2021-11-26T15:30:21+00:00",
      "monsterTheme": "demo-theme-5"
    }
  ],
  "status_code": 200
}
Enter fullscreen mode Exit fullscreen mode

For the "monsters" endpoint, we need a query parameter, but in case we don't send a query parameter, we will have a default value set so that a response is available at the endpoint.

In the main.py above , we have a default set to demo-theme-1.. So in case the API call is to the endpoint http://127.0.0.1:8000/monsters/ we will get the result as follows

// 20211129131036
// http://127.0.0.1:8000/monsters/

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-27T02:47:11+00:00",
      "monsterName": "demo-monster-1",
      "monsterQuote": "demo-quote-1",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 5
    },
    {
      "id": 2,
      "created_at": "2021-11-27T02:49:03+00:00",
      "monsterName": "demo-monster-2",
      "monsterQuote": "demo-quote-2",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 10
    },
    {
      "id": 4,
      "created_at": "2021-11-27T02:50:21+00:00",
      "monsterName": "demo-monster-3",
      "monsterQuote": "demo-quote-3",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 20
    }
  ],
  "status_code": 200
}
Enter fullscreen mode Exit fullscreen mode

Getting Images from Storage

The Supabase Python Client also provides various methods to interact with the Supabase Storage and we are going to get the public URL for the stored images.

For that we need to have the exact location of the file in the Bucket as well as the correct name for the images.

image.png

From the last blog of the series, we had the above structure of files in the Bucket supafast-api

#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

supabase: Client = create_client(url, key)

@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()

    for theme in themes['data']:
#theme['monsterThemeBg'] = supabase.storage().StorageFileAPI(BUCKET_NAME).get_public_url(FILE_LOCATION)
        theme['monsterThemeBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url('themes/'+ theme['monsterTheme'].replace(' ','-') + '.png')

    return themes


Enter fullscreen mode Exit fullscreen mode

Here, the FILE_LOCATION is easier to construct because the way these files are stored. The response we receive after adding the monsterThemeBg is like

// 20211129184109
// http://127.0.0.1:8000/themes

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-26T15:28:21+00:00",
      "monsterTheme": "demo-theme-1",
      "monsterThemeBg": "https://jtpcokcjjqbizziufohl.supabase.co/storage/v1/object/public/supafast-api/themes/demo-theme-1.png"
    },
    {
      "id": 2,
      "created_at": "2021-11-26T15:29:45+00:00",
      "monsterTheme": "demo-theme-2",
      "monsterThemeBg": "https://jtpcokcjjqbizziufohl.supabase.co/storage/v1/object/public/supafast-api/themes/demo-theme-2.png"
    },

    ...


  ],
  "status_code": 200
}
Enter fullscreen mode Exit fullscreen mode

The final main.py file will look something like this..

#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY
supabase: Client = create_client(url, key)


@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()
    print(themes['data'])
    for theme in themes['data']:
        theme['monsterThemeBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url('themes/'+ theme['monsterTheme'] + '.png')

    return themes

@app.get("/monsters/")
def monsters(theme : str = "demo-theme-1"):
    monsters = supabase.table('monsters').select('*').eq('monsterTheme',theme).execute()
    for monster in monsters['data']:
        monster['monsterBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url(monster['monsterTheme']+'/'+ monster['monsterName'].replace(' ','-') + '.png')

    return monsters


Enter fullscreen mode Exit fullscreen mode

Setting Up Environment Variables

As you can see in the main.py , SENSITIVE properties like the url and key are directly defined in the file. Such sensitive data should never be in a file and to overcome it, we use environment variables.

I found this really good article on dev.to to use environment variables from a .env file.

To do that,

//Stop the uvicorn server

cd. >.env 
Enter fullscreen mode Exit fullscreen mode

Now in the newly created .env file, add your variables in the format

#.env

SUPABASE_SUPAFAST_URL=your-supabase-url
SUPABASE_SUPAFAST_KEY=you-supabase-key

#make sure you don't have spaces before/after the equal sign
Enter fullscreen mode Exit fullscreen mode

In main.py file,

import os
from fastapi import FastAPI
from supabase import create_client, Client
from dotenv import load_dotenv

load_dotenv()
app = FastAPI()

url = os.getenv('SUPABASE_SUPAFAST_URL')
key = os.getenv('SUPABASE_SUPAFAST_KEY')
supabase: Client = create_client(url, key)

'''
Rest of the code for the routes of the API
'''



Enter fullscreen mode Exit fullscreen mode

Here, we additionally import the os and the load_dotenv packages, run the load_dotenv() function which loads the KEY=VALUE pairs into the environment so that os.getenv('KEY') can retrieve the value from the environment.

We didn't need to install a package for load_dotenv because the python-dotenv gets automatically installed when running pip install "uvicorn[standard] "


In case you use git(or some other VCS), make sure to put the .env in the .gitignore file, so that it is not visible to the general public.


Next Steps

Now that we have our API fully working on our local environment, in the next tutorial will deploy it on DETA and make it available publicly.

In case you have any doubts or suggestions regarding the article, feel free to contact me on my email aunicorndeveloper@gmail.com or on Twitter at @aUnicornDev.

The API built in this series is used in the tabsMonster project. Everyone is more than welcome to checkout and contribute in this Open Source Project.

GitHub logo aUnicornDev / tabsMonster

A Chrome extension to keep a tab on your Browser Tabs

Important Links

Below are the links for docs and products if you are more interesed.


Thank you for reading this far

image.png

💖 💪 🙅 🚩
aunicorndev
Yashasvi Singh

Posted on January 12, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related