Automatic request validation at the edge with OpenAPI and Fastly
Tags: fastly, openapi, security, serverless
Published: 2022-11-24 16:35:48

If you provide an API to your developer community, you might be familiar with OpenAPI (but don’t worry if you aren’t – I’ll explain everything). Perhaps you’re already using it to define all the endpoints and methods available, to generate documentation, or to support client apps like Postman. 

What if you could also use your OpenAPI definition to improve your API security by ensuring that all requests to your API match the patterns supported by your server? What if that also meant reducing load on your servers?

You can do this with [Compute@Edge](https://www.fastly.com/products/edge-compute) on Fastly. I'm going to show you [how](#how-to-validate-requests-with-computeedge-and-openapi). It's quick and there's no coding involved!

## Request validation: Why and when?

Request validation is an important part of any web application or service. It ensures that your server is receiving data in the format that it requires. This helps mitigate potential bugs (like unexpected errors and slow or invalid responses), and security vulnerabilities that might be exposed when the consumers of your API send wrong or malicious request data. 

There is nothing wrong with processes failing, and of course any good web application will include error handling. However, at scale, there are mounting costs both for the client, in terms of increased request latency, and for the server – in terms of resources. The **deeper** a request goes into a system before it fails, the more complex the error handling needs to be; the more expensive handling that transaction is; the longer it takes for the client to get a response, and the higher the chance of a malicious client discovering something interesting about the system architecture. The costs – and the risks – increase with depth.

That’s why it’s a good idea to fail fast and **shallow**, by performing validation as early as possible in the request lifecycle. With Fastly’s [Compute@Edge](https://www.fastly.com/products/edge-compute), you can do this before a request reaches your origin! 

## What is the OpenAPI Specification?

If the words “API specification” seem intimidating, think of flat-pack furniture, or, better yet, LEGO sets for grown-ups. These come with instructions for assembly, as well as for individual parts – a bit like a blueprint. A good blueprint will allow you to build something that looks and works exactly like it’s meant to. 

The principle behind the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md) (OAS – the industry’s most popular API specification format) is similar. It’s supposed to act as a blueprint for describing RESTful APIs. 

To adopt OAS, you create a document that defines your API in OpenAPI’s [standard format](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#format). Such documents are both machine and human-readable, which enables anyone to discover and understand the capabilities of a service without access to source code, additional documentation, or inspection of network traffic.

If you’re lucky, you might already have OpenAPI definitions for your APIs. If not, don’t panic! There are [tools](https://openapi.tools/#auto-generators) that can help you generate these documents from other API definition formats, source code, and even network traces.

> At Fastly, we rely on OpenAPI to [generate our API clients](https://dev.to/fastly/better-fastly-api-clients-with-openapi-generator-3lno), the [API reference](https://developer.fastly.com/reference/) on our [Developer Hub](https://developer.fastly.com), and our [Postman collection](https://www.postman.com/fastly).
> ![An OpenAPI definition, on the left, and resulting endpoint reference rendered on Fastly's Developer Hub, on the right](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xtd8xfnq1fombyqg9bc.png)

Adopting OpenAPI means you’ll be able to then reap the benefits of its growing ecosystem, to accomplish things like [code generation](https://dev.to/fastly/better-fastly-api-clients-with-openapi-generator-3lno), automatic documentation, [and more](https://stoplight.io/openapi#what-are-the-benefits-of-openapi).

## How to validate requests with Compute@Edge and OpenAPI

[Compute@Edge](https://www.fastly.com/products/edge-compute), Fastly’s serverless compute platform, allows you to build high scale, globally distributed applications – without having to manage the underlying infrastructure.

In a few short minutes, you’ll have a working Compute@Edge service, configured to perform basic validation of API requests against an OpenAPI definition. On every invocation, this service will ensure that:

- All required request parameters in the URI, query string, and headers of an incoming request are included and non-blank.
- Any applicable request payload adheres to the OpenAPI [request model](https://spec.openapis.org/oas/latest.html#request-body-object) of a corresponding API [operation](https://spec.openapis.org/oas/latest.html#operation-object).

Let’s do this! 

### Step 0

If you’ve never experimented with Compute@Edge, start by [getting set up](https://developer.fastly.com/learning/compute).

### Step 1

In an empty directory, run the following command using the [Fastly CLI](https://developer.fastly.com/learning/compute/#download-and-install-the-fastly-cli) to initialize a new Compute@Edge project in JavaScript, based on Fastly's [OpenAPI validation starter kit](https://developer.fastly.com/solutions/starters/compute-starter-kit-javascript-openapi-validation/):

```sh
fastly compute init \
  --from=https://github.com/fastly/compute-starter-kit-javascript-openapi-validation
```

### Step 2 (optional)

The project you just created comes pre-configured with an example origin ([httpbin.org](https://httpbin.org)) and an [OpenAPI definition](https://github.com/fastly/compute-starter-kit-javascript-openapi-validation/blob/main/src/definition.json), so if you don’t have your own OpenAPI document handy, you can skip this step. Otherwise, now is a good time to: 

1. Replace `src/definition.json` with your API definition.
> **Important!** API definitions must be:
> * Written (or [converted](https://mermade.org.uk/openapi-converter)) to the 3.x version of the OpenAPI standard;
> * In [JSON format](https://onlineyamltools.com/convert-yaml-to-json);
> * Fully [dereferenced](https://redocly.com/docs/cli/commands/bundle/#introduction) (it cannot contain any `$ref` pointers).

2. Replace references to `httpbin.org`, in `fastly.toml`, with your API origin – and make any other [configuration changes](https://developer.fastly.com/reference/compute/fastly-toml/#reference), as necessary.

### Step 3

Run `fastly compute serve` to run the Compute@Edge service on your local machine. Check the console to see both stdio and log output from your application.

Next, open up a new terminal instance and try sending valid and invalid requests to the local server: 

```sh
# Valid request: returns the response from the origin
curl -L -X \
  POST 'http://127.0.0.1:7676/anything' \
  -H 'Custom-Header: Hello!' 
```
```sh
# Invalid request: returns a synthetic response (400 Bad Request)
curl -L -X \
  GET 'http://127.0.0.1:7676/not-an-existing-endpoint' 
```

You can also run `fastly compute publish` and follow the steps in the wizard to publish your Compute@Edge service online.

That’s it!

> 💡 You can customize the behavior of this Compute@Edge service, for example, by returning validation errors in the client response, or adding more complex request handling logic after validation. Check out our growing collection of [JavaScript code examples](https://developer.fastly.com/solutions/examples/javascript/) on Fastly’s Developer Hub for more inspiration.