Supabase CRUDQ + RealtimeDatabase

Hi everyone :partying_face:,

Today I want to share with you SupabaseCRUDQ, a project I’ve been meaning to finish for a long time.

Since Supabase Docs aren’t always very clear, I had set it aside for more interesting projects :grin:.

Here we will cover Create, Read, Update, Delete, and Query with email authentication through Web component, and at the end of the guide there’s also an attempt at implementing a realtime database.

:orange_square: Variables

:small_orange_diamond: authDetails: In response to our successful login, we’ll receive a JSON containing various user information,

{
	"id": "",
	"aud": "",
	"role": "",
	"email": "",
	"phone": "",
	"confirmation_sent_at": "",
	"app_metadata": {
		"provider": "",
		"providers": []
	},
	"user_metadata": {},
	"identities": [],
	"created_at": "",
	"updated_at": "",
	"is_anonymous": 
}

and we’ll save it in this variable.


:small_orange_diamond: filters: It was created solely to simplify selecting the logical operator from the project’s dropdown menu in delete section.

For example,

  • =eq
  • >gt
  • !is.null

…and many others.


:small_orange_diamond: function: It is used to keep track of the last function called, so that we know what a Supabase response refers to.
(There’s probably a smarter way to do it, but this is how I did it)


:small_orange_diamond: SupabaseURL: URL of the Supabase project.

https://YOUR_SUPABASE_ID.supabase.co


:small_orange_diamond: tokenDetails: Right after logging in, in Web.GotText we run the supabaseFetchToken function, which will request a token(access_token) from Supabase to perform operations securely.
The response will contain:

{
	"access_token": "",
	"token_type": "",
	"expires_in": ,
	"expires_at": ,
	"refresh_token": "",
	"user": {
		"id": "",
		"aud": "",
		"role": "",
		"email": "",
		"email_confirmed_at": "",
		"phone": "",
		"confirmation_sent_at": "",
		"confirmed_at": "",
		"last_sign_in_at": "",
		"app_metadata": {
			"provider": ,
			"providers": []
		},
		"user_metadata": {
			"email": "",
			"email_verified": ,
			"phone_verified": ,
			"sub": ""
		},
		"identities": [
			{
				"identity_id": "",
				"id": "",
				"user_id": "",
				"identity_data": {
					"email": "",
					"email_verified": ,
					"phone_verified": ,
					"sub": ""
				},
				"provider": "",
				"last_sign_in_at": "",
				"created_at": "",
				"updated_at": "",
				"email": ""
			}
		],
		"created_at": "",
		"updated_at": "",
		"is_anonymous": 
	}
}

As can be seen from the JSON "expires_in" and "expires_at", the token has a duration (1 hour).
To refresh the token, I added a ClockToken that runs the supabaseRefreshToken function every hour.

:green_square: Headers

In this project, the headers of the requests we make will be managed with a function called supabaseRequestHeaders.

Inside it, there’s a “fixed” variable requestHeaders containing apikey and accessToken, which are required for every request.

It’s possible to pass a dictionary to the function if we want to add additional headers.

blocks(45)

:warning: Remember to set the apikey to ANON_KEY or PUBLISHABLE_KEY


:purple_square: CRUQD

All functions follow the same block schema:

  1. Setting up the function variable
  2. Configuring the headers
  3. Setting the URL
  4. Sending the request with an HTTP method

Since there’s not much to explain beyond using these blocks, I won’t add many details to the images but feel free to ask in the comments for more explanations.

Signup

Parameter Description
email user email
password user password

Logout

FetchToken

Parameter Description
email user email
password user password

RefreshToken

Create


If you need to add multiple rows, you’ll have to create a list containing dictionaries.
Use the encodeListToJsonList function to encode the list into JSON.

example

Parameter Description
table table on which to perform the operation
data data to be sent

ReadColumn & ReadTable

Parameter Description
table table on which to perform the operation
columnName column that needs to be read

Parameter Description
table table on which to perform the operation

Update


The variable finalData automatically adds a pair of primaryColumnName and primaryKey to our data by copying them from the function’s parameters (required to execute the operation correctly).

Parameter Description
table table on which to perform the operation
pkColumnName primary key column name
primaryKey primary key value
Data the data that will replace the selected ones

Delete

Parameter Description
table table on which to perform the operation
whereColumn column name
operator an operator to select the data
value the data that will replace the selected ones

Query

Parameter Description
table table on which to perform the operation
query PostgREST query

GetUUID


Returns the user’s ID

Upload file

Delete file

Download file


:globe_with_meridians: Web.GotText

Here we handle all the responses we get from Supabase.
The responses are first filtered through responseCode and then further filtered using the value of the function variable.

  • In case of a positive response from read/query, we use CSVResponseConverter function, if you noticed, in these two functions the header included Accept:text/csv, which asks Supabase to return a response in CSV (the JSON caused issues).
    I created a guide explaining how CSVToDictionary works, this one is a slightly modified version to get a list in the case of readColumn(here too, Supabase caused issues with the JSON :grinning_face_with_smiling_eyes:) and a dictionary in the case of readTable.

:stopwatch: Realtime Database

First of all, we thank :folded_hands: imwsummit for the WebSocketConnector extension, which allow us to receive realtime messages from the database.
[FREE] WebSocket Connector - An Extension for connecting and communicating with web sockets


Here you can clearly see why I called it an attempt, this is what I managed to do, it works, but I feel it’s not perfect…

As with the rest of the project, I’ll only explain the essential blocks.

:warning: Remember to enable realtime for the table.


First, we connect to the RTDB.

wss://YOUR_SUPABASE_ID.supabase.co/realtime/v1/websocket?apikey=PUBLISHABLE_KEY/ANON_KEY

Next, we send a join message with the table we want to monitor, in this case, all tables realtime:*.
(The ref should be incremented with each message, but in this guide we’ll keep it fixed at 1 since we don’t need it).

After performing these operations, any change made in the database will return a message indicating what happened.

:warning:Very important:warning:
The socket is kept alive through a heartbeat, a message sent every 30 seconds to tell Supabase that we don’t want to close the connection.


Test AIA

This project is for testing your own database, just enter your Supabase project URL and immediately see if everything works correctly.
I created simple layouts to test all the functions.

SupabaseCRUD.aia (437.6 KB)

Essential AIA

This project contains only the essential blocks to make everything work, without any graphics.
SupabaseCRUD.aia (427.2 KB)


To avoid a wall of text, I wrote only what seemed most important, but there’s really much more to say.
Don’t hesitate to ask for further explanations.

Happy :kodular:oding!

8 Likes

A well-explained guide :+1:

3 Likes

Flawless Job Master ..Thanks You

1 Like

Why not also implement file upload? :partying_face:

Upload file

Parameter Description
bucket supabase storage bucket
fileName file name without extension
filePath absolute path to the file
overwrite overwrite file true/false

It will also be necessary to have a dictionary containing the mimeTypes,
here I’ve added the main ones.

Hello everyone :partying_face:,

Today we are adding more useful functions

  • supabaseFileDelete
  • supabaseFileDownload

In this version, I have modified the supabaseRequestHeaders function so that you can choose whether to use the access token or not with a simple true/false, since we can choose to be anonymous or logged in.

I have also added the saveResponse parameter to all functions, as we will be saving a file with supabaseFileDownload.

Delete file

Parameter Description
bucket supabase storage bucket
fileName file name with extension

Download file

Parameter Description
bucket supabase storage bucket
fileName file name (on supabase) with extension
saveAs the path + filename.extension where we want to save the file

AIA

Given the various changes made, I am leaving the updated project.

SupabaseCRUD.aia (432.5 KB)

1 Like