# Building APIs with Cloud Functions and API Gateway

Author: [Mete Atamel](https://atamel.dev/) | Published: 2022-02-10 | Topics: Cloud Functions, Serverless, API Gateway, Google Cloud Platform, How To | Canonical: https://atamel.dev/posts/2022/02-10_cloud_functions_api_gateway/


## Building APIs with Cloud Run

If I want to build an API, I usually use Cloud Run. In Cloud Run, you run a
container and in that container, you run a web server that handles a base URL in
this format:

```
https://<service-name>-<hash>-<region>.a.run.app
```

You can then have the web server handle any path under that base URL such as:

```
https://<service-name>-<hash>-<region>.a.run.app/hello
https://<service-name>-<hash>-<region>.a.run.app/bye
```

## Building APIs with Cloud Functions

In Cloud Functions, you only have access to a function (no web server) and that
function can only handle the base path:

```
https://<region>-<project>.cloudfunctions.net/<function>
```

You cannot have additional paths under that base path. This is **one task one
function** design of Cloud Functions.

Does this mean that you cannot use Cloud Functions to build APIs with multiple
paths? Not necessarily.

## Workarounds

[Guillaume Blaquiere](https://twitter.com/gblaquiere), our Cloud GDE, talked
about a couple of workarounds in Python and Go on how to handle multiple paths
in a Cloud Function:

* [Use multiple paths in Cloud Functions, Python and
  Flask](https://medium.com/google-cloud/use-multiple-paths-in-cloud-functions-python-and-flask-fc6780e560d3)
* [Hack: Use Cloud Functions as a webserver with Golang](https://medium.com/google-cloud/hack-use-cloud-functions-as-a-webserver-with-golang-42edc7935247)

If you want a simple solution within a single Cloud Function, these could work
but they're workarounds and somewhat going against the design of Cloud Functions.

## API Gateway

A better approach is to use [API Gateway](https://cloud.google.com/api-gateway).
You let each Cloud Function handle single path and let API Gateway route
sub-paths according to the rules you define:

![API Gateway with Cloud Functions](/img/2022/api_gateway_gcf.png)

You can check my
[cloud-functions-api](https://github.com/meteatamel/cloud-functions-api) repo
for details on how to set this up but it involves 4 steps:

1. Deploy 2 functions `helloWorld` and `byeWorld`.
1. Create an API.
1. Create an API config using the OpenAPI spec to define which path goes to which function.
1. Deploy the API config to a gateway.

The API config file,
[openapi2-functions.yaml](https://github.com/meteatamel/cloud-functions-api/blob/main/openapi2-functions.yaml),
defines the paths as follows:

```yaml
paths:
  /hello:
    get:
      summary: Greet a user
      operationId: hello
      x-google-backend:
        address: https://REGION-PROJECT_ID.cloudfunctions.net/helloWorld
      responses:
        '200':
          description: A successful response
          schema:
            type: string
  /bye:
    get:
      summary: Greet a user
      operationId: bye
      x-google-backend:
        address: https://REGION-PROJECT_ID.cloudfunctions.net/byeWorld
      responses:
        '200':
          description: A successful response
          schema:
            type: string
```

With this setup, you have beginnings of an API backed by 2 Cloud Functions and
powered by the API Gateway:

```sh
# Test hello
curl https://greeter-gateway-5abbajef.ew.gateway.dev/hello
Hello, World

# Test bye
curl https://greeter-gateway-5abbajef.ew.gateway.dev/bye
Bye, World
```

---

Feel free to reach out to me on Twitter [@meteatamel](https://twitter.com/meteatamel)
for any questions/feedback.

