Creating a Simple CRUD API with Zuplo and Firestore

Creating a Simple CRUD API with Zuplo and Firestore

Learn how to use Zuplo and Firebase to securely expose your Firestore data via REST API

When it comes to building apps quickly and scalably, Firebase has been a go-to platform for many developers. Firebase makes it super easy to manage data, authentication, serverless functions, and many other essential components for modern apps. One downside is that Firebase lacks an easy way to expose data within Firestore as a REST API. Luckily, by pairing it with Zuplo, we can create a scalable and secure REST API in minutes that exposes our data hosted in Firestore.

This tutorial will look at how to turn a simple Firestore collection into a REST API. To do this, we will have a few prerequisites before you can follow along step-by-step. These prerequisites include:

  • Having an active Firebase account and access to the Firebase console
  • An active Zuplo account
  • Basic knowledge of REST APIs and JSON

Once you’ve handled these prerequisites, you can follow along below and create a REST API that uses Firestore to handle CRUD operations. Let’s kick things off by looking at setting up a new project in Zuplo.

Step 1: Setting Up Zuplo

Once you’ve signed into Zuplo, you must create a new project. If you’ve never created a project before, when you log in, you’ll be prompted to create your first project in the New Project modal.

If you already have an existing project, you’ll want to create a new one for this by clicking the New Project button in the top-right of the Projects screen. From here, the New Project modal will appear.

In the New Project modal, we will:

  1. Name our project “firebase-todo”
  2. Select the Empty Project type
  3. Click Create Project

Here is what the filled-out modal will look like before clicking the Create Project button.

Create Zuplo project

After clicking Create Project, Zuplo will kick off the process and spin up a new API gateway for us that will be ready within a few moments. Generally, the API gateway will be ready in under 10 seconds. With our API gateway spun up, our next step is configuring Firestore to handle our CRUD operations.

Step 2: Configure Firestore

Next, we will log into Firebase and navigate to the Firestore module. To do this, from within the Firebase console, click Build > Firestore Database in the left-side menu. This will take you to the Cloud Firestore main page.

From this page, we can manage our Firestore instance(s). If you have not created a database yet, click the Create database button. For this example, choose where you’d like the database to be hosted and set the security rules to production mode so we will have a secure instance out of the box.

Firestore setup

Once your database is ready, or if you already have a database available, open up the instance and click Start collection in the Panel view.

Start collection

In the Start a collection modal that appears, give this collection a Collection ID of “todos” and click Next.

Start collection modal

Let’s add our first document to the collection in step two. To do this, we will:

  1. Generate an Auto-ID for the collection by clicking the Auto ID button beside the Document ID field.
  2. Populate the first Field input with “description”, setting the Type and Value to “string” and “Milk”.
  3. Click Add Field and populate the Field input with “complete”, setting the Type and Value to “boolean” and “true”.
  4. Click Save to save the collection to your Firestore instance.

Below is what the form will look like before clicking the Save button.

configuring collection

With our document saved, we can now see that our entry has persisted in the Firestore instance.

firestore welcome page

With our Firestore instance up and running and some data in place, our next step is to configure Firestore to accept the traffic from Zuplo to the database.

Step 3: Configure Firebase Security

To configure the security for our API to access the Firestore instance, click on Project Overview in the top-left corner of the screen in Firebase. You'll need to create a web app in the Zuplo-Todo project (or however you’ve named yours). If you have one already created, you can skip past the creation steps documented below. If you need to create a web app, follow these steps.

First, click on the Web App icon in the Project Overview to begin the creation flow.

Firestore project overview

On the next screen, fill in the App nickname field with “Zuplo Todo Web App”, or another identifier of your choosing. Then, click Register app.

Register firebase app

In the second step, we will see instructions on how to integrate Firebase with our web app. We won’t need to do this currently, so we will skip past it and click Continue to console.

Firebase sdk instructions

At this point, our web app has been created, and we can proceed.

Using a newly created web app or an existing one, we will then select it from the dropdown on the Project Overview screen. Available apps will be listed at the top of the screen underneath the project name.

new firebase app

Click on the Cog to be brought into the Project settings screen.

On the Project settings screen, click the Service Accounts tab and then click the Manage Service Account permissions link in the top-right of the screen.

Firebase project settings

On the Service accounts for project screen, select the “Firebase Admin SDK Service Agent” entry by clicking on the link in the Email field.

Service accounts

On the next screen, select the Keys tab. Under the ADD KEY dropdown, choose Create new key.

Creating a new key

This will prompt you to create a new private key for the firebase-adminsdk user. On the modal that appears, set the Key type as JSON and click CREATE. From here, you’ll be prompted on where to save the .json file with the credential. Once saved, you’ll see a confirmation on the screen.

private key created

This key will enable Zuplo to connect to our Firestore database. This will be one of two pieces of authentication we will use to ensure our API and data are secure. The Service.json will secure the Zuplo to Firestore connection and we will use API Key authentication to make sure that clients connecting to Zuplo are authenticated and authorized to use the API they are making the request to.

system diagram

Our next step is to begin defining routes for the APIs themselves. For that, we will hop back into Zuplo.

Step 4: Creating The GET Endpoint

Back in Zuplo, we will open up our firebase-todo app. In the menu on the left, select routes.oas.json.

The first endpoint we will create will be our /todos endpoint, which will retrieve all of our todos within Firestore. To set this up, we will need to do the following on the Route Designer screen:

  1. Set the Summary as “Get all todos”
  2. Set the Path as “/v1/todos”
  3. Set the Method as “GET”
  4. Set CORS as “Anything Goes”
  5. In the Request Handler section, set the:
  6. Handler as “URL Rewrite”
  7. Rewrite URL as
    firestore.googleapis.com/v1/projects/${env.PROJECT_ID}/databases/(default)/documents:runQuery

Adding The Environment Variables

Based on the value in the Rewrite URL field, we need to grab the env.PROJECT_ID from an environment variable within Zuplo.

First, we need to get the Project ID for the project from Firebase. To grab this value, go back to your Firebase project settings, and under General, copy the value under Project ID. In my case, this value is “zuplo-todo”.

getting project ID

With this value on the clipboard, we will click on the Settings tab in Zuplo, select Environment Variables from the left-side menu, and click Add Variable.

Adding environment variable to Zuplo

In the modal that appears, do the following:

  1. Set the Name field as “PROJECT_ID”.
  2. Set the Value field as “zuplo-todo”.
  3. Click Save to persist the newly created environment variable.

Zuplo env var modal

After clicking Save, you should see that the variable has been added to the Environment Variables list.

Saved Zuplo env var

While in the Environment Variables screen, let’s quickly look at adding the service.json file contents we created in Firebase earlier. To do this, you’ll once again click on Add Variable and add the following to the form in the modal:

  1. Set the Name field to “SERVICE_ACCOUNT_JSON”.
  2. Set the Value field to the contents of the service.json file we saved earlier from Firebase
  3. Note that the actual file name will look similar to “zuplo-todo-985b6bba61e5.json”
  4. Check this variable off as Secret to encrypt the value and make it invisible after setting it.
  5. Lastly, click Save to save the variable.

Marking env var as secret

Once saved, this variable should also appear in the Environment Variables list, like so:

two environment variables

Now, let’s navigate back to the routes.oas.json file in Zuplo and click Save in the bottom left corner of the screen.

Zuplo routes

This will then take our current configuration and deploy it to the gateway. At this point, we can run a quick test to see if our newly created endpoint is up and running. By clicking back into our “Get all todos” route from the Route Designer, we can see that we can run a test directly through the Zuplo UI.

finding the test button

Click the Test button, and a simple test pane will appear. This will be pre-populated with our endpoint details, and we can just click Test to fire off a request.

After the test has run, we will see that the endpoint is returning to us a 403 Forbidden with a “Missing or insufficient permissions” message being returned in the response body.

403 API response

This means that our API call was successfully routed to Firebase. However, Firebase has not allowed the request to retrieve data from our Firestore instance due to insufficient permissions.

We actually have to make a few adjustments to make this request work. As is, it is being sent over and blocked for a few reasons.

Firstly, the query is being set over as a GET request, but it needs to be a POST for the request to Firebase to work. To fix this, we will add a Policy to the request pipeline to modify the request into a POST request and add a request body to the call.

Creating and Adding In Policies

To create the policy, we will do the following:

  1. In the left-side menu, on the modules folder, click the + button.
  2. Name the new file “set-query-body.ts”
  3. In the new file, add the following code:
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

export default async function policy(
  request: ZuploRequest,
  context: ZuploContext,
  options: never,
  policyName: string,
) {
  const query = {
    structuredQuery: {
      from: [
        {
          collectionId: "todos",
        },
      ],
    },
  };

  const nr = new ZuploRequest(request, {
    body: JSON.stringify(query),
    method: "POST",
  });

  return nr;
}
  1. Click Save in the bottom left corner of the screen.

Our policy has been created but still needs to be applied to our /todos endpoint. To add the policy, do the following:

  1. Within the routes.oas.json file, click on the “Get all todos” endpoint in the Route Designer (if you don’t already have it up)
  2. In the Request Handling pane, click on Policies to expand the section and click Add Policy.

Adding the policy

  1. On the Choose Policy screen, search for “custom” and then select the Custom Code Inbound policy.

custom code policy

  1. On the Create Policy screen, we will set up the configuration to point to the set-query-body module we created earlier. To do this, we will
  2. Set the Name field to “set-query-body”
  3. Set the Configuration as follows:
{
  "export": "default",
  "module": "$import(./modules/set-query-body)"
}
  1. Click OK to save the policy. Once everything is filled in, this is how the configuration should look before saving it.

configuring the policy

  1. After clicking OK, the policy should be added to the Request pipeline. It will also show up in the Zuplo UI.

new policy appears

  1. Our last step is to click Save in the bottom left corner of the screen. This will push this new configuration out to our API gateway.

Testing The Endpoint

To test this policy and ensure it works, we can debug it by sending another test through Zuplo. To do this, click the Test button within the Request Handling pane.

In the Test Your API modal, click Test and wait for the response to return. Once the response has come back, you’ll see we are still getting the 403 Forbidden error. However, when we click on Logs and expand them, we can see that Zuplo is correctly receiving the request and rewriting the URL, including adding our environment variable for PROJECT_ID.

testing the API again

Adding The Upstream Firebase Admin Auth Header

Our request still doesn’t work because of one last piece: adding the Authorization header so that Zuplo can call the Firebase API as an authenticated and authorized user.

To add in the necessary authorization header, we can do the following:

  1. We will add another policy for the “Get all todos” endpoint by clicking Add Policy within the request pipeline.
  2. In the Choose Policy modal, type “firebase” and then choose the Upstream Firebase Admin Auth entry.

adding firebase auth policy

  1. In the plugin configuration that appears, you’ll see the default logic that will create a JWT from the value in our SERVICE_ACCOUNT_JSON environment variable that we added earlier.

configuring firebase auth policy

  1. Click Okay to add the policy to the request.
  2. Click Save in the bottom left corner to deploy the updated configuration to our gateway.

Our endpoint will now use two policies in the request pipeline. You can confirm this in the Zuplo UI by ensuring both are visible.

second policy appears

Testing The Updated Endpoint

Once again, let’s click the Test button to test our endpoint. After running a test request, we should be able to see a 200 OK status returned, as well as the contents of our todo that we added earlier in Firestore. Success!

testing the endpoint with new policy

At this point, we’ve created a simple GET API that connects to our Firestore database and returns the values in a collection. Of course, the API is completely public at this point, but we will cover more about how to secure it in the next tutorial, Firebase Day 2.

Formatting the API Response

As we can see, the response from Firestore is not necessarily the most efficient or easy to use. This is why we will add a policy to the response pipeline that will format it in a way that will make it a bit more standardized and in the form developers expect.

First, we will need to create the policy by:

  1. Click the + button beside modules in the left-side menu to add a new file.
  2. Select Outbound Policy.
  3. Name the new file “firestore-response-to-json.ts”.

Within the firestore-response-to-json.ts file, we will add the following code to format the response:

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

type MyPolicyOptionsType = {
  documentId: string;
};

export default async function policy(
  response: Response,
  request: ZuploRequest,
  context: ZuploContext,
  options: MyPolicyOptionsType,
  policyName: string,
) {
  if (response.ok) {
    const data = await response.json();
    context.log.info(data);

    const documentId = options.documentId ?? "id";

    let transformed;

    if (!Array.isArray(data)) {
      transformed = transformDoc(data, documentId);
    } else {
      // Check if the data is an array and has documents or only contains readTime
      transformed =
        Array.isArray(data) && data.some((item) => item.document)
          ? transformFirestoreResults(data, documentId)
          : [];
    }

    return new Response(JSON.stringify(transformed), {
      status: response.status,
      statusText: response.statusText,
      headers: response.headers,
    });
  }

  return response;
}

function transformFirestoreResults(results: any[], documentId: string) {
  return results.map((result) => {
    const { document } = result;
    return transformDoc(document, documentId);
  });
}

function transformDoc(document: any, documentId: string) {
  const fields = document.fields;

  let transformedDoc = {
    [documentId]: document.name.substring(document.name.lastIndexOf("/") + 1),
  };

  for (let field in fields) {
    const value = fields[field];
    const valueType = Object.keys(value)[0];
    transformedDoc[field] = parseValue(value[valueType], valueType, documentId);
  }

  return transformedDoc;
}

function parseValue(value: any, valueType: string, documentId: string) {
  switch (valueType) {
    case "stringValue":
      return value;
    case "booleanValue":
      return value;
    case "integerValue":
      return parseInt(value, 10);
    case "doubleValue":
      return parseFloat(value);
    case "timestampValue":
      return new Date(value);
    case "mapValue":
      return transformFirestoreResults([value], documentId);
    case "arrayValue":
      return value.values.map((v) =>
        parseValue(v[Object.keys(v)[0]], Object.keys(v)[0], documentId),
      );
    case "nullValue":
      return null;
    default:
      return value;
  }
}

After the code is in place, click Save in the screen's bottom-left corner.

With the policy created, we need to add the outbound policy to the response pipeline. let’s do the following to add it:

  1. In Zuplo, go back to our endpoint in routes.oas.json, and in the Request Handling pane, click on Add Policy (similar to what we did for adding the policy to our request).
  2. In the Choose Policy modal, search for “custom” and select the Custom Code Outbound policy.

Adding outbound policy

  1. In the Create Policy modal, set the policy Name as “firestore-to-json”
  2. under Configuration, add the following code that will include our module and supply an option for documentId (the documentId value returned for the Firestore document).
{
  "export": "default",
  "module": "$import(./modules/firestore-response-to-json)",
  "options": {
    "documentId": "id"
  }
}

With the configuration plugged in, our screen should now look like this:

configuring outbound policy

  1. From here, we will click OK, then click Save in the screen's bottom-left corner to save the updated endpoint and cascade out the new configuration to the gateway.

Testing The Updated Endpoint

We are now ready to test the endpoint again using the Test button. This time, when sending a request, we should get a response that is a bit more readable after routing through our outbound policy that we just added to transform the JSON response from Firestore. The result should look like this:

testing outbound policy

Now that we have built one API endpoint let's build the rest of our CRUD endpoints, starting with adding a new to-do item.

Step 5: Creating The POST Endpoint

For our Create todo endpoint, we will go back into routes.oas.json and, from the Route Designer, do the following:

  1. Click the Add Route button
  2. Fill in the Summary value as “Create todo”
  3. Add the Path as “/v1/todos”
  4. Change the Method dropdown from “GET” to “POST”
  5. Set CORS as “Anything Goes” to enable CORS.

With this set, our fields in the UI should look like this:

New endpoint

Adding In Policies

Next, we will add our Policies. Clicking on the Policies section on the screen, we will:

  1. Under Request, click Add Policy.
  2. On the Choose Policy modal, find and click on the Upstream Firebase Admin Auth policy (the same one we added on the GET route created earlier).
  3. On the Create Policy modal, leave the settings as they are and click the OK button to add the policy to our API.

Then, under the Request Handler section, we will select the Handler as “URL Rewrite” and set the Rewrite URL as:

firestore.googleapis.com/v1/projects/${env.PROJECT_ID}/databases/(default)/documents/todos

Formatting the API Request

Lastly, we want to ensure the endpoint receives a sensibly formatted JSON body. With the way Firestore works, it’s not necessarily intuitive from a REST perspective for users trying to add a todo to the list. For this, we will create a new inbound policy that will transform our incoming JSON into the format Firestore expects.

To create the policy, under the modules folder in the left-side menu, we will:

  1. Click the + button to add a new Inbound Policy.
  2. Name the new file “json-to-firestore-request.ts”.
  3. Open up the newly created file in the UI by clicking on it.

We will then add the following code to our policy:

import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

export default async function (request: ZuploRequest, context: ZuploContext) {
  const requestBody = await request.json();

  // Transform the incoming JSON body into Firestore format
  const firestoreDocument = {
    fields: {},
  };

  for (const [key, value] of Object.entries(requestBody)) {
    let firestoreValue;

    switch (typeof value) {
      case "string":
        firestoreValue = { stringValue: value };
        break;
      case "boolean":
        firestoreValue = { booleanValue: value };
        break;
      case "number":
        if (Number.isInteger(value)) {
          firestoreValue = { integerValue: value.toString() };
        } else {
          firestoreValue = { doubleValue: value };
        }
        break;
      default:
        throw new Error(`Unsupported data type for key ${key}`);
    }

    firestoreDocument.fields[key] = firestoreValue;
  }

  const nr = new ZuploRequest(request, {
    body: JSON.stringify(firestoreDocument),
  });

  nr.headers.set("content-type", "application/json");

  // Continue processing the request
  return nr;
}

In this code, we are parsing the body received by our endpoint and converting it into the format expected by Firestore. This includes taking the TypeScript type and converting it into the equivalent type that Firestore supports. The policy will return a new request that is correctly formatted and can be sent to Firestore to add the todo from the request body.

Once the code is in place, we will click Save in the bottom left corner to persist it in Zuplo and push it out to our gateway.

With our new policy created, our next step is to add our new json-to-firestore-request policy to our request pipeline. For this, back in the routes.oas.json file, we will do the following:

  1. Expand the Policies section and click Add Policy under Response.
  2. On the Choose Policy modal, select Custom Code Inbound.
  3. On the Create Policy modal, set the Name field as “json-to-firestore“, and make the following changes in the Configuration pane:
  4. Change the “module” value in the code to “$import(./modules/json-to-firestore-request”.
  5. Delete the “options” object, as it is not needed for this policy.
  6. Click OK.

This is what the Create Policy screen should look like before you save it:

Creating fourth policy

With both policies in place, our endpoint configuration is complete and should look like this: fourth policy appears

Click Save in the screen's bottom left corner to push the new endpoint out to the gateway.

Testing The Endpoint

Now, we can proceed with testing it by clicking the Test button beside the Path field on the Route Designer pane.

On the Test Your API modal, we will add a request body, send the request, and, if all goes well, hopefully, receive a 200 OK response. Below is an example of a request that you can test with this endpoint, as well as what the screen should display when you receive a successful response.

testing fourth policy

If you want to do a secondary test to see the latest entry being retrieved from the GET endpoint we created earlier, we can:

  1. Click on the endpoint in the Route Designer.
  2. Open the Test Your API modal by clicking the Test button beside the Path field.
  3. Click Test in the Test Your API modal.

After the response has come back, we should see our latest entry added to the returned array of todos.

inspecting response body

Formatting The API Response

Our final step here is to make the response from the new POST endpoint look more familiar to users of the REST API. We will reuse our previous firestore-to-json policy and add it as an outbound policy to our response pipeline. To add the policy, do the following:

  1. Under Policies, click Add Policy under Response.
  2. On the Choose Policy screen, select firestore-to-json under Existing Policies.
  3. Click Save in the bottom left corner to deploy the latest configuration to the gateway.

This will add the policy to the request pipeline and transform our oddly formatted Firestore response into a nice, pretty JSON response.

Test The Updated Endpoint

Let’s run another test, following the same steps as before. Only this time will we add an item for “Crackers”. After you’ve run the test, here’s what our output should look like:

formatted response

We now have a nicely formatted response that feels more like a traditional REST API. We now have two endpoints: one to create todos and another to retrieve them. Our next step is to create an update endpoint to update entries within our todos list.

Step 6: Creating The PATCH Endpoint

For our Update todo endpoint, we will go back into routes.oas.json and, from the Route Designer, do the following:

  1. Click the Add Route button
  2. Fill in the Summary value as “Update todo”
  3. Add the Path as “/v1/todos/{todoId}”
  4. Change the Method dropdown from “GET” to “PATCH”
  5. Set CORS as “Anything Goes” to enable CORS.

You’ll notice we added a URI parameter to this request. The route must update a specific item based on its ID. By adding the {todoId}, we are letting Zuplo know that this is where that particular parameter will be when processing the request. With this set, our fields in the UI should look like this:

creating patch endpoint

Add In Policies

Next, we will add our Policies. Clicking on the Policies section on the screen, we will:

  1. Under Request, click Add Policy.
  2. On the Choose Policy modal, find and click on the Upstream Firebase Admin Auth policy (the same one we added on the GET route created earlier).
  3. On the Create Policy modal, leave the settings as they are and click the OK button to add the policy to our API.
  4. Next, click Add Policy again under Request.
  5. Under Existing Policies, select json-to-firestore.
  6. Finally, under Response, click Add Policy and select firestore-to-json under Existing Policies.

This configuration will allow us to send upstream requests to Firestore and send and receive nicely formatted JSON requests and responses as we have done with the other endpoints.

Then, under the Request Handler section, we will once again select the Handler as “URL Rewrite” and set the Rewrite URL as:

firestore.googleapis.com/v1/projects/${env.PROJECT_ID}/databases/(default)/documents/todos/${params.todoId}?updateMask.fieldPaths=complete&updateMask.fieldPaths=description&updateMask.fieldPaths=complete

You’ll notice that this URL has a bit more added to it compared to the one we did for our POST endpoint.

Firstly, you’ll see that our URI parameter from the Path is being pushed into our Rewrite URL using ${params.todoId}. This will allow us to pass through that variable and ensure that the correct entry is being updated in Firestore.

Secondly, you’ll see that we have also added a query parameter to the Rewrite URL. This is because we want to make this into a really clean interface for our API users, and by using updateMask in the URL as a query parameter, we can have it so that it will only update the fields that are passed and not the entire object. Suppose we only update the description field and don’t send the others. In that case, Firebase will only update that one field instead of overwriting the entire object (potentially with null values, blowing away our previous values). In the URL, you will see that we’ve added this for both description and complete, as those are the two fields we care about.

With the Policies and URL Rewrite dialed in, our configuration should now look like this in the Route Designer:

patch endpoint configuration

Click Save in the screen's bottom left corner to push the new endpoint out to the gateway.

Testing The Endpoint

We will once again test out our new endpoint by clicking the Test button beside the Path field on the Route Designer pane.

Since we will be updating an entry, we must grab the document ID from Firestore for the entry we want to change. We will change “Milk” to “Almond Milk” in our example. To grab the ID for our Milk entry, you can either call the GET endpoint and copy the ID value or grab it directly from Firestore. If you grab it from the GET endpoint in Zuplo, this is where that value can be found:

testing patch endpoint

On the Test Your API modal, we will

  1. add the ID for “Milk” as a URI parameter, overwriting the placeholder {todoId}.
  2. In the request body, we will add a JSON object with a new description for our item.
  3. Click Test to send the request.

We will receive a 200 OK response if all goes well. Below is an example of a request you can test with this endpoint (you’ll need to switch the URI parameter), as well as what the screen should display when you receive a successful response.

200 OK response

We can also confirm back in Firestore that the update was successful. By going to that specific document, we should see that the value is now “Almond Milk”.

Checking in firestore

With 3 endpoints created, we want to round out our CRUD APIs by adding a DELETE endpoint. Let’s tackle that next!

Step 7: Creating The DELETE Endpoint

For our Delete todo endpoint, we will go back into routes.oas.json and, from the Route Designer, do the following:

  1. Click the Add Route button
  2. Fill in the Summary value as “Delete todo”
  3. Add the Path as “/v1/todos/{todoId}”
  4. Change the Method dropdown from “GET” to “DELETE”

Similar to our PATCH endpoint, we added a URI parameter to this Path. This is because the route must delete a specific item based on its ID. With this set, our fields in the UI should look like this:

Delete endpoint

Adding In Policies

Next, we will add our Policies. Clicking on the Policies section on the screen, we will:

  1. Under Request, click Add Policy.
  2. On the Choose Policy modal, find and click on the Upstream Firebase Admin Auth policy (the same one we added on the GET route created earlier).
  3. On the Create Policy modal, leave the settings as they are and click the OK button to add the policy to our API.

Here, you’ll see we only needed to add the Upstream Firebase Admin Auth policy since we have no request or response JSON to deal with.

Then, under the Request Handler section, we will once again select the Handler as “URL Rewrite” and set the Rewrite URL as:

firestore.googleapis.com/v1/projects/${env.PROJECT_ID}/databases/(default)/documents/todos/${params.todoId}

Again, like the PATCH endpoint, we’ve added the URI parameter to the endpoint’s Path and injected it into our Rewrite URL so that Firestore knows which entry to delete.

With the Policies and URL Rewrite dialed in, our configuration should now look like this in the Route Designer:

Configured deletion endpoint

Click Save in the screen's bottom left corner to push the new endpoint out to the gateway.

Testing The Endpoint

We will once again test out our new endpoint by clicking the Test button beside the Path field on the Route Designer pane.

Since our API will delete data, we must grab the document ID from Firestore for the entry we want to delete. In our test, we will delete the “Almond Milk” entry we updated earlier. To grab the ID for our Almond Milk entry, call the GET endpoint and copy the ID value or grab it directly from Firestore.

On the Test Your API modal, we will

  1. add the ID for “Almond Milk” as a URI parameter, overwriting the placeholder {todoId}.
  2. In the request body, we will add a JSON object with a new description for our item.
  3. Click Test to send the request.

Hopefully, we will receive a 200 OK response if all goes well. Below is an example of a request that you can test with this endpoint (you’ll need to switch the URI parameter), as well as what the screen should display when you receive a successful response, including an empty response body.

Testing delete endpoint

We can also confirm in Firestore that the delete request was successful. In Firestore, we should see that an “Almond Milk” entry no longer exists and that only 2 items remain, one for “Bread” and one for “Crackers”.

Checking against firestore

Conclusion

With that, we’ve done it! We’ve created our CRUD APIs by using Zuplo to create a sleek REST interface with Firestore as the backend. In minutes we’ve created a fully functional and scalable REST API using Firebase Firestore and Zuplo.

In the next parts of this series we will build on these APIs and add the following functionalities:

  • Day 2: Add API key authentication.

  • Day 3: Add validation for requests.

  • Day 4: Generate developer documentation.

  • Day 5: Monetize the API and add AI features.

Keep following for more detailed step-by-step tutorials and enhancements throughout Firebase week!