FIRESTORE REST API DIRECT INTEGRATION

AppGyver Tutorial

Firestore is a non relational (NoSQL) database. As such, it is ideal for data that in someway, or for some reason, needs redundancy or the redundancy is inherent to it, be it structured or not (ie. documents).

As stated by Google:

“Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud Platform. It keeps your data in sync across client apps through realtime listeners and offers offline support for mobile and web so you can build responsive apps that work regardless of network latency or Internet connectivity. Cloud Firestore also offers seamless integration with other Firebase and Google Cloud Platform products, including Cloud Functions”

Besides the aforementioned and it being easy to setup, it has a free usage policy for low traffic use (as of july 1, 2020, it’s free up to 50.000 reads/day, 20.000 writes/day and 20.000 deletes/day) that allows its free use for many applications and, if needed, growth is not a problem.

The following web resources are of interest to users of Firestore with AppGyver:

Since this tutorial is about using Firestore as a data resource for AppGyver REST API direct integration, not Firestore itself, it will assume a basic knowledge of the Firestore setup.

Basics

Firestore REST API methods

Firestore uses the following methods, not all of which are implemented in AppGyver at the present time:

(1) It was not tried since the GET COLLECTION method of AppGyver does it nicely

(2) It might be possible, but not tried until now

(3) It is not a direct implementation, but a use of some characteristics of AppGyver data resources

While all Firestore methods are usable through an HTTP direct call, only those using the REST API direct integration will be presented. Additionally a workaround for querying collections based on field contents in the client side will also be shown.

AppGyver REST API direct integration methods

The following actions can be executed using the available methods in the AppGyver REST API direct integration:

(4) The use of CREATE RECORD (POST) to query the database is not a direct implementation of the method but a work-around that works nicely.

FIRESTORE data types

The following are the data types allowed by Firestore as they should be referenced in the schemas (taken from Firestore REST API)

Tips

  • Remember that Firestore, AppGyver and Javascript are case sensitive (orderby is not the same as orderBy)

  • Since Firestore has a rather unique structure it is very important to pay attention to have an exact match on the schemes of the document and those in the AppGyver REST API:Every document in Firestore has always the following keys: name, fields, createTime, updateTime. Never omit them in your schemas, except as noted in the [CREATE RECORD (POST)](#Create Record (POST)) method.

    • The "fields" key is an object with properties that have your actual data in objects with the name of your fields with a pair key:value, where key will denote the data type.

    • If your fields are composite, you will have also mapValues.

  • Although you can have schemas to match any data structure you create on your Firestore database, it will be a lot easier if you keep the structure as simple as possible. This means to try to avoid composite fields as much as possible.

  • The document id is part of the name of each document. It is the string after the last slash as shown:

  • To get the id assigned by Firestore:

where pageVars.id is the name of the document, and the value "20" is the length of the string that Firestore assigns to document id's.

  • Since free use of Firestore caps at 50.000 reads/day, it is advisable to delete the recursive read in the data variable set up, or the cuota will be reached in a few hours:

Caveats and work-arounds

As shown in the Firestore REST API Methods section:

  • AppGyver doesn't have a PATCH method so the only way to change the content of a field is to GET the full document, DELETE the original document, change the data of the specific field and CREATE a new document. Care should be taken if the documentid can not be changed, in which case the new document should be created with the old id (Creating document with custom id).

  • Since the POST method is set in AppGyver to create a new record but, as shown in the Query document by field section, can be set for other uses with some tinkering, maybe all Firestore uses for the method can be set. Be aware of the limitation for the structured query response as noted in the server side query.

Data Resource Setup

Base

All AppGyver methods use a common base for each resource. In order to have flexibility and following the rules of Firestore, the following applies:

The remainder of the URL will be set up for each method and will have the following mask:

​ /projects/{your database}/databases/(default)/documents/./{additional_info}

Note: The text in italics in the above mask can be explicitly typed or be a variable (in which case you type the variable name inside the curly brackets and pass its value as a URL placeholder).

Get Collection (GET)

The following image shows the config setup:

Once you setup the Relative path and the Response key path, run a test to check if you get the data, and if so, set schema from response.

The response will be an array with all documents in your database, ordered by default (document id). If you want the response ordered by the contents of a specific field, add:

?orderBy=your_field_name

to the Relative path. By default, the order will be lexical, ascending, but can be set to descending order by adding "desc" to the Relative path after the field name, separated by a space:

?orderBy=your_field_namedesc

Get Record (GET) and Delete Record(DELETE)

Both methods use the same configuration strings. The following image shows the config setup in tab GET RECORD (GET):

Use the same strings and URL placeholder setup in the DELETE RECORD (DELETE) tab.

Create Record (POST)

The following image shows the config setup:

The setup shown in the above image will create a document with a documentid set by Firestore, 20 characters long.

The Create record (POST) request schema has to be manually created by adding properties starting with fields as the example shows:

This has to match the data schema in Firestore. Note that the schema starts with the fields object and does not include the name, createTime and updateTime fields.

Creating document with custom id

If you want to set your own id, you should add the following to the Relative path after the collection name:

?documentId={id}

and set a URL placeholder as show in the following image:

Also, you have to pay attention to the URL placeholder properties as needed for your application.

Query document collection by field

Firestore uses the HTTP method POST with a very powerful structured query payload in the body of the call. However, since the POST method implemented in AppGyver is, up to now, designed to create a new document (record), if you want to process the query server side, the CREATE RECORD (POST) AppGyver method can be used, but will need some twisting.

So there are two possible alternatives to query the database: Server side and Client side.

Server side

For the use of the structured query, you have to set a new resource with the base set up with a :runQuery required by Firestore. The CREATE RECORD (POST) base configuration should be set up as shown:

Note that there is no collection id but instead ":runQuery", which needs an structured query in the body payload of the POST call. For help setting the query, it is strongly suggested that you use the Firestore API explorer (https://cloud.google.com/firestore/docs/reference/rest/v1/projects.databases.documents).

In order to set the structured query in the body payload of the method call, a CREATE RECORD (POST) request schema has to be set. In the simplest form, it will be as follows:

Note that "from" and "fields" are lists of objects

which is equivalent to a body

{ "structuredQuery": { "from": [ { "collectionId": "" } ], "select": { "fields": [ { "fieldPath": "" } ] }, "where": { "fieldFilter": { "field": { "fieldPath": "" }, "op": "", "value": { "stringValue": "" } } } }

Since the POST method is being used for an AppGyver non-intended use you can not include more fields in the "fields" array of the "select" clause of the query, so only the contents of one field will be returned. If the "select" clause is ommited, the query will return all fields, and as noted below, their key has to be included in the response schema.

Every empty values ("") have to be set with a variable or a static string in the method call as will be shown ahead.

Also a Create record (POST) response schema that matches the Firebase response has to be set. For the example above, it will be:

In the image, the object "nombInmueble" is the name of the field that is to be retrieved with the query.

The property "fields" has to have as objects the keys of the fields you will get in the response dependent on the way the structured query was set up in the request schema (either one field or all of them).

The properties "document", "createTime", "fields", "name" and "readTime" are mandatory.

Also, you have to set a data variable to get the response of the query. For the example, it will be:

And a page variable to use the data, as show for the example:

Note that "datos" is a list of objects

As can be seen above, the variable named "datos" its a list that has an schema that exactly matches the Create record (POST) response schema that was set above.

Then, the flow logic will be as shown, with a Create Record function followed by a Set page variable to assign the response to the variable (in this example "datos") using a formula.

The flow logic will look like this:

The binding (assignment) has to be done with a formula

The Create Record function bindings will look like this:

Values have to be set with variables or static values as required. Note that the arrays (Custom list) have to be set too. See the following example which sets the collection id (first Custom list on the image above):

The operators ("op") can be any of:

The variable ("datos" in the example) is assigned the values of the POST response with a formula as shown:

Although the validation of the formula shows an error, the value returned by POST is actually a list and will be bound to the variable and usable.

The data will then be available as usual.

Client side

To have the query processed on the client side, first get the document collection, and then process the query with javascript and assign the response to an appropiately configured page variable. The logic flow is as shown in the following image:

As an example, in order to get all documents in which the contents of a field (idProy) is a specific value passed with a page variable (idProyecto), the javascript needed is simple:

The data variable of input1 (listaProyectoTramite in the image) is the one set by the GET COLLECTION method.

The page variable (PTF in the image) and the Output schemas should be configured as the Firestore document schema (note that the variable type is array of objects). For the example above:

Then, the data will be available using the Page variable.

Last updated