Skip to content

Getting Started with FB4D

Christoph Schneider edited this page Nov 4, 2024 · 80 revisions

For your first steps with the Firebase for Delphi Library this document contains the necessary information.

Be familiar with Firebase

For a quick introduction, we recommend this video, which was first shown at the “Dev Days of Summer 24” by Embarcadero. It gives a good overview of the library within 45 minutes.

Video about Connect the Firestore Cloud database and other Firebase services from Delphi applications by the FB4D open-source library.

The Firebase documentation from Google is also recommended: https://firebase.google.com/docs.

Before you can use this library, you need your Firebase project. For this purpose create a test project in the Firebase Console at https://console.firebase.google.com. For a quick overview to create your first Firebase project, check also this video.

For the access of the Firebase REST API you need your Project ID and the Web API Key from the project settings. You get this information from the Firebase Console from Settings/General/Your Project.

Hint

If the Web API Key is not yet available in the project settings, an authentication method must first be selected and the "Users and authorizations" tab must be displayed once under project settings so that the WebAPI key is created.

Setup Authentication Methods

To allow users to access the Firebase cloud database, you have to set up the authentication methods. For this purpose set up in the Firebase Console in the area of Authentication the Sign-in method. The current version of the library FB4D supports the following sign-in providers only:

  • Email/Password
  • Anonymous

For the first tests in the next chapter enable at least the Email/Password provider in the Firebase Console.

Hint

Since version 1.6 of FB4D, you can access both database (RTDB and Firestore), the storage and the ML Kit without using the authentication. This may be a good idea for a quick test. Just keep in mind that your data will be freely accessible. The project ID does not protect against unauthorized access, as it is far too short and easy to access.

Start with the Delphi Project DemoFB4D

This chapter describes the functionalities of the tab Authentication but first, you have to build the application and install the OpenSSL library. For a quick overview of the Authentication, check also this video Authentication Demo.

Clone the GIT Repository

After cloning the git hub repository you have to initialize the JOSE submodule.

For this purpose you can use the following git bash commands:

$ git clone https://github.com/SchneiderInfosystems/FB4D.git
$ cd FB4D
$ git submodule update --init --recursive

For a quick overview of starting with the FB4D, check also this video Clone FB4D from GitHub.

Build the Application DemoFB4B.exe

Open the project Samples/Intro/DemoFB4D.dproj in your Delphi IDE. As a default, the project will be built as a Windows 32 application in the Debug configuration.

Install OpenSSL

The FB4D library uses the JOSE sub-library for JWT token analysis. You do not need to use this option as long you do not need to evaluate the content of the Firebase Authorisation Token. For this purpose, the usage of JOSE is controlled by the conditional compiler switch TOKENJWT. When the method ITokenJWT.VerifySignature is called, the OpenSSL crypto library will be loaded for asymmetrical decryption for the token verification. For the installation of OpenSSL you have to consider the platform-specific installation. The following chapters contain information in addition to the official Delphi wiki: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/OpenSSL.

Win32 Platform

If you do not have installed the OpenSSL library on your development PC, you need to download the files libeay32.dll and ssleay32.dll from an official source of OpenSLL https://github.com/IndySockets/OpenSSL-Binaries for Win32. Before you can start the application the first time, add both OpenSSL dlls into the created folder FB4D\Samples\Intro\Win32\Debug or Release.

Win64 Platform

You get the files libeay32.dll and ssleay32.dll as 64-bit executables also from https://github.com/IndySockets/OpenSSL-Binaries. Copy both files into FB4D\Samples\Intro\Win64\Debug or Release.

MacOS64 Platform

Since Mac OS version Catalina, the preinstalled newer version of OpenSSL does no longer matches the requested version in the Indy library. That is why you have to deploy the files libcrypto.dylib and libssl.dylib within the application package by using the Delphi deployment manager. You can get the files from here https://github.com/DelphiWorlds/KastriFree/tree/master/Lib/OpenSSL/1.0.2s/macOS but you need to remove the versions number before adding the files into the deployment list. Unfortunately, you must also sign the embedded dynlibs before adding it to the deployment list.

Linux64 Platform

Depending on the based Linux System, you need to build the OpenSSL library file libcrpto.so and libssl.so in version 1.0.2 by yourself. I recommend also to deploy this library within the application package.

Android32/64 Platform

The OpenSSL is preinstalled and can by used from FB4D without additional actions.

iOS32/64 Platform

The library files libcrypto.a and libssl.a must be deployed within the package and will be statically linked from Indy.

Start the Application and Register your first User

You can either register your first user in the Firebase Console (Authentication/Users) or you can do this step within the DemoFB4D application from the folder Samples/Intro. Firstly, enter your Project ID and the Web API Key of your Firebase project in the edit fields at the top bar of the DemoFB4D application. Afterward, enter an email address into the field User Email Address and write a new constructed password with a size of at least 6 characters into the field Password. The button Sign-up New User sends both information via the REST API to the Firebase Authentication interface. As a result, you get the data of the new created Firebase user back. In the field UID you get the new created Firebase User ID. The Token field contains a crypto string of 872 length which expires in an hour after fetching. The memo field in the tab Information contains all returned details of the new user. The information in JWT.Header and JWT.Claims are obtained from the decryption of the Token.

It is recommended to keep the Firebase Console open while you do your first steps because you should see the newly created user in the table Authentication/Users after pressing the reload button.

Second run of the Application

In a second run of the DemoFB4D application, you can sign-in with the previously created user by pressing the button Login. For your convenience the test application stores your credentials in clear text (unsafe) together with other settings like the project ID and the web API key in the ini-file C:\Users\<UserName>\AppData\Roaming\DemoFB4D.ini. Store never the credentials in clear text in a real application and never encrypt a customer password in an application. Use for this purpose the platform crypto services. Keep also your project ID and the web API key confidential and use strong encryption for such data.

The button Reset Password advises Firebase to send an email to the entered email address to renew the password by a Google service.

The button User Data retrieves detailed information of the signed-in user (e.g. the photo URL). On the tab Change User Profile, you can enter and edit additional user information like Display Name and Photo URL or you can change the email address of a registered user or change the password.

If you have enabled the sign-in method Anonymous in the Firebase Console you can log in without credentials for application without sensitive personal data. For this purpose delete the content of the field User EMail Address and the Login button changes automatically to Anonymous Login. Please note that with the anonymous authentication, the UserID changes every time you log in. That means that the UserID can not be linked to a device for storing persistent data. The idea of ​​Anonymous Authentication is that a user can start the application without entered an email address nevertheless to use the first simple functions of your applications. If the user decides later to remain his entered data for future use your application can offer a function to convert the account to a persistent account with the email of the user and a password. For this purpose, the button Link EMail/Pwd allows upgrading the user account after login as anonymous.

The First Steps in the Real-Time Database

The description assumes that your real-time database is empty and the access rules for write and read are unrestricted. This is always the case for a new created Firebase project. Data in the Firebase Realtime Database is stored as JSON objects. For more information see Firebase Documentation: Structure Your Database.

Write your first JSON Node

In the tab Real-Time DB, the field Database Path addresses the top node for all operations on this tab. The path delimiter / can be used as usual for nested structures.

Before you can write the first JSON node change to subtab Put. Enter a first key-value pair by filling the field Key and Value and press Add or Update Node. Secondly, press the button Put Node Synchronous to store this JSON node into the database. Check the written node in the Firebase Console in the section database. After selecting the Real-Time Database you should see the first tree for the stored TestNode.

Now add a subnode by changing the Database Path to TestNode/2nd Node and press the button Clear Node and enter a fresh node. Change the content in the fields Key and Value and press Add or Update Node. To store this subnode press again Put Node Synchronous or Put Node Asynchronous. For more information see also Synchronous vs Asynchronous Method Calls.

Now the Firebase Console shows the nested JSON nodes.

Read the written Nodes by using the Get Method

On the tab Get press the button Get Synchronous 3 times by changing the database path. For the path TestNode/2nd Node, you get just a key-value pair. For the upper path TestNode, you shall receive two key-value pairs: The first key 2nd Node has as value a JSON object for the subnode while the second key contains your first entered node. For the root database path (empty path) you will get one JSON object with the nested structure.

Delete Nodes by using the Delete Method

Use the Delete Synchronous button on the tab Delete for the database path TestNode/2nd Node and inspect in the Firebase Console the result. To delete the entire content of the real-time database, you can use an empty database path field.

Patch a Node

The put method does not allow to change the content of the value of a node that contains sub-nodes without lost of the sub-nodes. For this purpose, the method patch can be used. The tab Patch allows testing this method.

Prepare your database as follow:

Test Node

Now you can change the content of the TestKey in the database path TestNode by using the patch method without losing the sub-node 2nd Node.

Post a Node

The post method is comparable to an auto-increment index in relational databases. It creates a subnode with a unique ID. To test this method on the tab Post enter a key and value and press the button Post Synchronous. Before pressing this button a second time change the value for other data. The Firebase Console or the get method shows the resulting structure.

Get Server Timestamp

With this method, a server variable (the server timestamp which is number as Unix formatted timestamp) can be written into a node of the given database path. As a result, the server time will be returned.

Hint: If you need the server time without writing it into the database you can use the GetServerTime method of the interface IFirebaseResponse.

Listen to Changes in the Real-Time Database

The tab Scan Real-Time DB Event allows installing a listener for a database path. For this purpose, a REST API long-running call will be used which prevents expensive polling of the real-time database.

The button Notify Event Handler installs a handler and the button Stop Event Handler stops again the listing. For more details about the method StopListening of the interface IFirebaseEvent see the description in the interface reference.

Security in Firebase: Setup the Access Rules

To limit read and write access to nodes in the real-time database, you need to understand the concept of Firebase Access Rules. For a good starting point, see the Firebase Documentation: firebase.google.com/docs/database/security

A typical system requirement would be to restrict access to nodes based on the logged-in user ID. This solution is recommended and explained in the second sample project CloudClipboard. Before you can run this project, you must set up the access rules for your Real-time Database in the Firebase Console.

Each user writes and reads his node underneath the root node by using a path that includes the own user ID (uid). E.g. for the project CloudClipboard the path for the user nodes is /cb/<$uid> by using the following rules:

{
  "rules": {
    "cb": {
       "$uid": {
         ".read": "(auth != null) && (auth.uid == $uid)",
         ".write": "(auth != null) && (auth.uid == $uid)" 
      }
    }
  }
}

These rules match the following Firebase Realtime Database structure:

Data structure of CloudClipboard project

For more details see also CloudClipboard/MainFmx.pas.

First steps with the Firestore Database

The newer Firestore Database allows queries comparable to SQL databases. Also for the Firestore Database, there is a listener, which notifies your application in case of changed documents or collection. A good introduction to this possibility is given in the sample application Firestore Chat.

For a quick overview of using the Firestore in the Intro Sample Application, check also this video Firestore Demo

With the help of the DemoFB4D application, you can start your first steps with Firestore. It is also recommended to inspect a Firebase console parallel to your first steps in Firestore. After the sign-in change to the tab Firestore, enter a collection name in the edit field (e.g. Test) while you can let the document ID field empty. After clicking the button Create Document you should see the first instance of a document in the collection Test. This document is addressed by an automatically created document ID which you find now in the edit field. The document itself is empty but contains some attributes like creation date and time and document ID. If you fill in an ID into the document ID field either a new document will be created (if the ID does not exist before) or an existing document will be overwritten.

In a second step, you can add a field into this document by clicking the button Insert/Update Doc while you leave the combo box on option Simple Document.

The first document created with DemoFB4D viewed in the Firebase Console

As next change the combo box to the option Complex Document and click the button Insert/Update Doc again. Inspect in the console the same document again. It contains now all field types of the Firestore and some nested structures.

The updated document creates a more complex document that contains all field types of the Firestore

List documents of a collection

The Get Document function allows not only the retrieval of a single document but the retrieval of all documents in a collection. For do this, the input field Document must be left empty before the Get Document button is pressed.

The Firestore limits the resulting number to 20 documents by default. The query parameter allows to adjust the page size e.g. 50 to documents:

TQueryParams.CreateQueryParams.AddPageSize(50)

For larger collections, you can repeatedly call IFirestoreDatabase.Get by overtaking the PageToken from the last Get in order to fetch the next series (page) of documents. If the property IFirestoreDocuments.MorePagesToLoad becomes false, you have fetched all documents.

Query := TQueryParams.CreateQueryParams.AddPageToken(LastDocs.PageToken)

In the Firebase Lib Demo app, the check box Get next page is shown as long there are more pages to load. To fetch the documents on the next page, press the Get Document button again.

List documents of an entire collection

To understand the read access to documents it is recommended to inspect the method TfmxFirebaseDemo.ShowDocument(Doc: IFirestoreDocument) which is called too when clicking on the button Get Document. This method calls recursively the sub-function GetFieldVal to print nested structured data like arrays and maps.

Change parts of a document

In cases, only one field or few fields of a larger document shall be mutated the button and its underlying method Patch Document is the right approach for this task. In the end, you can delete the entire document again by the click on the button Delete Document.

Run Query

The Firestore Database offers a structured query that is comparable to an SQL-Select statement with the RunQuery method. Before you can start the Run Query demonstration you need some structured data in a collection. For this purpose, a 3rd option was added in the combo box Docs for Run Query. For playing with the query you firstly need to enter several documents (acts as records) into a collection (acts as a table). For this purpose add the desired collection name, select the option Docs for Run Query and press several times Create Document followed by Insert/Update Doc. In the firebase console you can see under your collection node several documents with their automatical created ID with the following document (record) structure:

  • documentCreated: Timestamp
  • hint: string
  • info: string
  • testInt: integer (a random number between 0 and 100)

If you click on Run Query you get all documents that have a testInt value greater than the selected value in the trackbar Min test val.

The Run Query demo function works also for first-level child documents. For this purpose select the option Use Child Document and add again some documents. In this mode, the Run Query does not longer return the entire document but a subset of the field defined in the select clause: testInt, documentCreated and info. Also, this example shows the usage of a two-level sort order (first level: testInt ascending, second-level documentCreated descending). If you call this button with ticked child document the first time you will see an error from Firebase because two-level sort order execution requires an index on this collection. To create this index, you can use the delivered URL which is attached to the error message from Firebase.

The Firestore requires an index on the collection to execute two-level sort orders

Furthermore, this second RunQuery demonstrates also the limit method (the result contains not more than this number of documents) and the offset method (how many documents shall be skipped before the first document is added to the result). For testing also the methods StartAt and EndAt you have to uncomment some lines of code and insert real values for the testInt field from your Firestore Database.

Using Database Listener

The listener makes it possible to be informed about all changes in the database. The demo application allows you to set up two destinations:

  • Target-1 is used to specify a collection to be monitored, whereby a flag is used to specify whether the subfolders should also be monitored.
  • Target-2 is used to monitor only one defined document for changes.

The listener is started for a monitor a collection in the Firestore

The green status icon shows whether the listener is running and writing its messages to the log even if you are on a different tab (e.g Insert/Update).

Using Transactions

In a further step, it is advisable to familiarize yourself with the possibilities of the Write and Read Transaction. In the read transaction, documents from the same point in time are read. With the write transaction, several documents can be changed atomically to ensure consistency in the data. The write transaction also offers the possibility of using simple server-side decisions and calculations. Start a Write Transaction and use the function Insert/Update Doc for more than one document. To write the documents by commiting the transaction, press the Commit button. This transaction shows how to set a time-date field with the server time when choosing the document type Complex. It is also possible to increment numeric fields with a value or decrement them with a negative value. Max and Min functions are also available, which allow a numeric field to be kept within definable limits.

The write transaction is started for atomic write access into the Firestore

First steps with the Firebase Storage

The Storage can be used to store files in a directory structure. There is currently no possibility to query the directory structure contents. That is why an application needs to write the file references into a structure in the Firestore or the Real Time Database for later retrieving.

For a quick overview of using the Storage in the Intro Sample Application, check also this video Storage Demo

First, you need to enter the field Storage Bucket that you received from the Storage tab using the Firebase Console. It is the link URL without the prefix "gs://". If you have already uploaded a file into the root of the bucket using the Firebase Console, you can enter in the field Object the file name only. For a file uploaded into a subfolder enter the file name and its folder path separated by a "/" in the field Object. Now you can press Get Synchronous or Get Asynchronous to retrieve the metadata of this object.

For a stored file in the Firebase Storage you get information with the method Get

First steps with Firebase Functions: Calling a back end function from an application

Before a server-side function can be started, a function that can be called via HTTP must be uploaded to Firebase. For this purpose pleaseread the Firebase documentation firebase.google.com/docs/functions.

On the functions tab you can then call this function client-side and supply the arguments expected in the function.

First steps with Vision ML: Analyze images to locate objects, recognize text and more

For getting familary with the possibilities of Vision ML, it is recommended to read the introductions to ML Kit: firebase.google.com/docs/ml-kit. Note, however, that FB4D offers only the cloud side image processing capabilities and does not include a local machine learning engine (Tensor Flow). Therefore, barcode scanning for example is not available.

This video Vision ML Intro Demo demonstrates the VisionML functionality integrated in the Intro Sample application.

For the first steps, the function Annotate from file is recommended, which you can find in the VisionML tab in second line. First you have to provide a file in GIF, TIFF or PDF format as Base64. For this purpose use the "Upload File" button. Note that ML Vision does not support other file image formats.

Then select the desired image processing functions under Feature. Press "Annotate from file" and check the results.

First steps with Gemini AI

On the Gemini AI tab, the first step is to enter your private Gemini AI API key within the Gemini Configuration. You will receive this API key after logging in to Google AI Studio. This key will save the Demo App unencrypted in a local inifile and insert it again the next time it is started. Follow this link to open the Google AI Studio and press the button Get API key.

Hint: For windows platform you need to install the WebView2 SDK to enable Edge in the TWebBrowser instead of IE. This is required to display PDF as a document file and for modern HTML notation in the result, e.g. to view SVG vector drawings.

Gemini AI in the Demo App

Start with a simple question for Gemini AI by entering your question in the prompt memo field and press the button Ask Gemini AI. The answer is output in various formats. On the one hand, the resulting JSON object from the Gemini AI web service is displayed in the Raw JSON Result tab. In the meta data tab, all meta information is extracted from the result. The processed prompt tokens and the number of tokens of the result are listed in the section Usage. The result state and the finish reason are displayed here. Safety ratings of the generated code are also output here. The tab Markdown formated result shows the created text which is extracted from the JSON object and is available in markdown format. The tab HTML formated result contains a web browser where the markdown text has been converted to HTML. FB4D uses for this purpose the submodule delphi-markdown from the Australian Delphi developer Grahame Grieve.

Within the request to provide a document or an image to which the question refers, a media file can be specified by using the Load PDF and Load Image buttons.

The button Next Question in Chat allows to send the last question and answer pair together with a new question. If you press this button several times in a row, you enable a chat conversation with Gemini AI.

The Calc Token of Prompt button allows you to calculate the cost of the currently entered question. The Calc Token of Chat button calculates the token of the entire request including all answers and questions within the chat history. The cost of the output can only be limited by the model parameter Max Output Token.

In Gemini Configuration, you can specify alternative model parameters to influence the output of the Gemini AI if required. Safty settings can be used to specify own security requirements when making a request in the AI.

Clone this wiki locally