Create a bookmark functionality with remote actions and device ID with Xano

In this tutorial, we'll show you how you can allow app users to create bookmarks with a list of items, using Xano as the backend.

We're using the app case created in the World Cities with Xano tutorial. So if you want to build this app, you should follow that tutorial first. If you are interested in building a bookmark functionality for your app, but not in building this particular app case, you can still continue reading and adapt your app case to the following steps.

The bookmark functionality will allow an app user to bookmark some cities among the ones displayed in the app. This will be achieved by implementing a remote action, bound to a "bookmark" icon next to each city. This remote action will trigger a PATCH request, containing the device ID, which will be stored in the database, in the row that corresponds to the city the user bookmarked. Finally, we'll have a screen where the user can see the list of cities that were previously bookmarked.

🎨 Design file

🚧 Create the backend functionality for bookmarks in Xano

In order to build the World Cities app backend, follow the steps here to create the database and first API endpoints. After following those steps, you'll have a database with information about several cities, together with the world region they belong to. Also, you'll have some endpoints to get information about those cities and regions. Bravo will connect to those endpoints to feed the mobile app with the necessary data.

Adding bookmarks column to the database

Now, we'll need to add an extra column to the Cities table shown in the tutorial. This column, called Bookmarks, will store the device ID of all the users that choose to bookmark a particular city.

  1. Go to the Cities table on Xano, and click on the + sign to add a new column.

  2. In the field types step, choose Text and call it "bookmarks".

  3. Choose list in the Structure dropdown, and make sure Required has the no value.

  4. Hit Save to add this field to the table.

Creating the API endpoints and data processing functionality

Now that the table is ready to store the device ID of the users that bookmarked a particular city, we'll create two endpoints.

One of them will return the cities that have been bookmarked by a particular device, and the 2nd one will accept data, in form of a PATCH request, containing a new device ID for one of the cities. This second endpoint will be the one targeted by the remote action we'll later add in Bravo.

GET Cities by device

First, we'll create the endpoint that will return a list of cities containing a particular device ID in the bookmarks field. We'll use this data later for the screen containing the list of cities a user bookmarked. This endpoint will accept a GET request, with the device ID passed as a query string parameter (we'll show later how the URL should be constructed).

1. In the World Cities API group, click on Add API endpoint on the top right of the dashboard.

2. Select CRUD Database Operations, then the Cities table

3. Select the GET request, and put citiesByDevice as the name.

4. Hit Save. This will automatically create an endpoint that will accept the GET request.

Now, click on the endpoint just created. We'll add an input variable, which will be the device ID received by the endpoint as a query string parameter.

1. In the 1. Inputs section, we'll click on the + sign at the top right. Select Text.

2. Put deviceId as the input name, and specify Yes in the Required dropdown.

3. Leave the rest as is, and click Save.

Now, we'll use this input value to filter the data in the Cities table and return only the cities that contain the device ID provided by the user.

1. Click on the Query all Records item

2. In the Filter tab, add a filter by custom query by clicking on the pencil icon, and set the parameters as shown in the image below.

3. After doing this, click Save. Now, our citiesByDevice endpoint is ready!

You can test it by clicking on Run & Debug at the top of the dashboard. If you introduce a deviceId parameter already present in the bookmarks field of any of the cities, the data for these cities will be returned in the API response. If none of the cities contains this device ID, the response will be empty.

PATCH Cities

Now, we'll create a PATCH endpoint that will receive a new device ID for a specific city, every time a user bookmarks a city. This endpoint will be a bit more complex than the previous one, as several steps need to be completed to add the device ID information.

As we did for the previous endpoint:

  1. We'll click on Add API endpoint > CRUD Database Operations > select the Cities table

  2. Select the EDIT operation > change the verb to PATCH

Now, we'll click on the endpoint we just created, and access the endpoint dashboard. We'll have two inputs in our endpoint:

  1. One integer called cities_id (already created for us)

  2. One text called device_id (we'll need to add this one, setting it as required).

These values will be sent in the API request: the cities_id as part of the URL, and the device_id inside the JSON body of the request.

We'll hide all the other inputs, by clicking on them and disabling the Visible to the API toggle switch.

Now comes the most complex part: adding steps to the Function stack to be able to add the device ID to the bookmarks field of the corresponding city. Remember that this field is a list of text elements, which correspond to the device IDs.

We'll add the following functions to the stack:

1️⃣ Get Record from Cities

  1. Click on the + icon on the top right to add a stack item.

  2. Click on Database Requests, select Get Record (we only want to retrieve a single row from the table), and choose Cities.

  3. You'll see the Get Record operation has been added to the stack. Click on it, as we need to specify that the record we want to retrieve is the one having the cities_id input as ID. For that, configure the Inputs panel as shown below.

  1. Also, we need to make some changes to the Output panel. We are only interested in returning the bookmarks list from the table item, as we'll later add to this array the device ID input, and store it again in the table. Customize the response as shown below.

  2. Change the Variable name to bookmarks_array. (remember to click Save).

2️⃣ Create Variable

In the previous step, we got the bookmarks list from the table item we selected (using the input cities_id provided in the PATCH request). This was stored in a variable called bookmarks_array (see screenshot above). This variable is an object containing the bookmarks list.

To add the device ID to that list, we want to select that list inside of the object, so we're able to add a new item to the list.

  1. We'll create a new variable by clicking on the blue + icon on the top right of the Function stack, then choosing Data Manipulation, and then Create Variable.

  2. Click on the variable we just created. On the right panel, input bookmarks_array.bookmarks as the value of the variable, and bookmarks as the name (see screenshot below). Hit Save.

3️⃣ Array: Has Any Element

Now we have the bookmark list in the form of an array. We can perform operations with this array, such as searching elements, or adding new ones.

We'll first add a new item to the function stack to perform a search over the array. We want to see if the device_id input is already stored in the array, which would mean that the user had already bookmarked that city.

  1. Add a new Data Manipulation operation, then select Arrays, and finally Has Any Element.

  2. Here, specify bookmarks in the array dropdown (the name we defined in step 2️⃣ for the list).

  3. Add an expression by clicking on the pencil icon. Select the = operator, setting device_id to the left of it, and $this to the right. This will check whether any of the array elements is equal to the device_id variable, and return a boolean variable: true if an element matches the device_id, false if not.

  1. Click Save after specifying this expression, set in_array as the variable name (this will be the boolean variable mentioned above), and click Save again to close the panel.

4️⃣ Conditional statement

Finally, we'll add a conditional statement, as we want to add the device ID to the bookmark list in case that ID is not in the list, but we don't want to add it in case it already is, to avoid having duplicated IDs in the list.

  1. For that, we'll add a new function to the stack, selecting Data Manipulation, and then Conditional.

  2. Click on the pencil icon and set the statement below. Click Save.

We'll see how the conditional will have two paths: Then and Else. The first path will be taken if the in_array variable is false (which means the device_id has not been found in the bookmarks list). If this is the case, we'll want to add the new device_id to the bookmarks list, and update the table record. Otherwise, the Else path will be taken. In this case, as the device ID is already present in the bookmarks list, we won't perform any further operations, else than returning an empty body in the HTTP response.

4️⃣.1️⃣ Then path

  1. Under Then, add a new function: Data ManipulationArraysAdd To End of Array

  2. Set bookmarks as existing variable (we defined this one in step 2️⃣)

  3. Set device_id as value. This will add the device_id to the end of the bookmarks array.

Finally, we want to update the bookmarks field in the table with the bookmarks array we created (containing the newly added device_id), for the row with cities_id as ID.

  1. Under the Array: Add to end function we just created, add a new function: Database RequestsEdit RecordCities

  2. In the Inputs tab, on Find Cities record by field, set id (name of the table field) next to field_name, and cities_id (input value received with the HTTP request) next to field_value. As you can imagine, this will specify which record of the table will be edited.

  1. Under Cities Metadata, set the bookmarks[] field of the table equal to the bookmarks list variable containing the new device_id item (see screenshot below). Make sure all the other items are invisible. This will prevent errors later on.

  1. Now we'll go to the Output tab to decide what will be the content of the HTTP response returned after calling this endpoint. We chose to return all the fields of the updated table record. We set the name result to this variable (it will be needed later).

4️⃣.2️⃣ Else path

We still need to specify what will happen if the conditional defined in step 4️⃣ takes the else path. In this case, as mentioned before, we'll just do "nothing", and return an empty body that will be sent in the HTTP response.

  1. Add a new function to the stack, under Else: Data ManipulationCreate Variable.

  2. Set the variable name to result. It needs to have the same name as the variable returned when editing the table record in the previous step. Finally, set its value to null.

Finally, under 3. Response section in the main endpoint dashboard, we need to specify what will be returned as the HTTP response. We need to bind the result variable defined both in 4️⃣.1️⃣ and 4️⃣.2️⃣. Click on the item inside the response area, and set it to the result variable as shown below.

Now we're done with the endpoint! Feel free to test it before jumping into Bravo to connect the app design to the Xano endpoints we just created.

⚙️ Creating the API requests in Bravo Data Library

Now that we've created the endpoints, it's time to create the API requests that will target them. At this point, go back to the World Cities with Xano tutorial and follow these steps.

Once you do that, you'll have the World Cities app as in the original tutorial. Now, we'll create two more API requests to implement the new bookmark functionality.

1️⃣ Request: GET Get cities by device

Duplicate one of the existing GET requests, and use the following URL:

https://XANO_URL/citiesByDevice?deviceId=${device.id}

In the Test Values tab, specify a device.id that already exists in the bookmarks field of the Xano database (in case you don't have any, add one with a random value). In our case, the value device33 already exists there.

Click Send to get a response. After doing this, make sure the following data is selected:

Finally, in the Selected Data panel, set the .data[].id path to city_id. This way, we can reuse the detail requests created in the original tutorial.

2️⃣ Request: PATCH Add bookmark

Now, we'll create the PATCH request we'll later bind to a remote action, to send the device.id to the Xano endpoint and add the bookmark.

Duplicate one of the existing requests, and use the following URL. Then, change the API verb to PATCH.

https://XANO_URL/cities/${city_id}

Go to the Body tab and add the following JSON.

{
  "device_id": "${device.id}"
}

Click Send to test the request. As we won't need to bind the response data, it's not necessary to modify the Received Data or Selected Data tabs.

3️⃣ Update the Get Single City request

Finally, we need to update the Get Single City request we created in the original tutorial. This is the request bound to the City Detail screen, where we'll bind the remote action to add a bookmark.

  1. In the Received Data panel of this request, make sure the .data.id path is selected, along with all the other necessary data for the City Detail screen.

  2. In the Selected Data panel, give this path the name of city_id as shown below. Notice that this is the same name we specified for the URL query string variable in the Add Bookmark request. This way, Bravo will know how to "connect" the Get Single City and Add Bookmark requests, so the bookmark is added to the city where the user triggered the remote action.

🔖 Binding the UI elements to the API requests

Finally, we need to bind the mobile UI to the API requests we just created. Once again, go back to the original tutorial and complete these steps.

For the bookmark functionality, we'll have a new screen: Bookmarked Cities. This screen will show the list of cities the user has bookmarked based on their device ID. In the data binding mode of this screen, bind the data as follow.

Finally, we'll bind the City Detail screen, where we have the bookmark icon with remote action.

  1. In the data binding, click on the bookmark icon layer.

  2. Under Action: Remote action, bind the PATCH Add Bookmark request as shown below. Configure the success and error response actions. In our example, we added an alert message for both.

That's it! Now you can test the bookmark functionality in your app by clicking on the bookmark icon in a city detail page, and see the city appear in the Bookmarked Cities screen.

Happy Bravorizing! 🥳

Last updated