Validating the right way: API gateway with JsonSchema
Tags: apigateway, jsonschema, javascript, aws
Published: 2024-05-19 19:04:34

We all know input validation, right? Tons of ways on doing it and it saves us a lot of time preventing troubles of many types. There are different types of validation and for different use cases we may use different approachs. We may validade inputs with some requirements, custom functions and, whenever using #Angular we are able to validate things through some high level Validation function from Reactive Forms module. 

Well, before start with Backend i always got myself thinking about how to validate the body of a REST requisition. Don't get me wrong, I can for sure guarantee that things will be sent fine, but always wandered if the backend function receiving the data would have to parse it back and validate the same way I do when the front end receive data. Some time passed, I started to do backend and had to come up with a solution and since we used API Gateways, things were right next. 

When I was getting things done and understanding stuff propperly with serverless and API Gateway, I used to validate inputs like this:

```
module.exports.myAPIPostFn = async (event) => {
    const { prop1, prop2, prop3 } = event.body
    if(notNull(prop1) || notNull(prop2) || notNull(prop3))
        throw new Error('Error [400]: invalid body')
    
    ... // code continues...
}
```

It doesn't sit right, you see? **By doing that, I feel like i'm making the function responsible for it's input integrity, while it should receive things right in first place**. Of course that if I want to be sure no side effects would occour I could try and use some classes and models for it also, but it also didn't fit with the way things were being done. 

If the caller was the responsible, then I should try and find something to validate things at it's side. That's when I found the input validation with JSON Schema. As stated in its [official website](https://json-schema.org/)

> JSON Schema is the vocabulary that enables JSON data consistency, validity, and interoperability at scale

See? Just what I was looking for. It has a set of rules that one can use in a very declarative way to define what a JSON should look like. A JSON schema would look like this

```
{
	"$schema": "http://json-schema.org/draft-04/schema#",
	"type": "object",
	"required": [
		"name",
		"surName",
		"age",
		"email",
		"phone",
		"isMarried"
	],
	"properties": {
		"name": { "type": "string" },
		"surName": { "type": "string" },
		"age": { "type": "integer" },
		"email": { "type": "string" },
		"phone": { "type": "string" },
		"isMarried": { "type": "boolean" }
	},
	"additionalProperties": false
}

```
With this schema **I am able to define the object's properties with name, type and also prevent additional props from comming with it**. The best part of it, when using serverless with API Gateway, is that the integration is as symple as including a line of code (actually, 3 if you count linke breaks):

```
newClient:
    handler: src/functions/client/handler.newClient
    events:
        - http:
              path: client
              method: put
              integration: LAMBDA
              authorizer: ${self:custom.authorizerConfig}
              **request:
                  schemas:
                      application/json: ${file(schemas/new-client.json)}**
```
When using serverless you can provide several configs for your event type, and when it comes to using HTTP event type you are also able to define a schema for the request. **When the schema is defined, the serveless will setup the API in a way that it uses the provided schema to validate the body of the request being received**. This will ensure that when the lambda function executes, the `event.body` will have all the desired properties and, if they don't, the API Gateway will gracefully respond with `Invalid request body` without ever call the lambda.

In the end I got quite happy with this approach since it brought me some advantages:

- Cleaner code (we all love it)
- Better controll over contract between front and backend without changing the way the backend works (AKA not implementing models)
- Close one more security breach, since now I am able to prevent some malicious inputs
- Cost saving: I no longer have to execute lambda code to notice that inputs are wrong. 


![Looney Toones "That's all folks"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ajeyuja2firgdx60e12.png)

That's it for now. Let me know in the comment section if you would have done differently. I am also looking for some simmilar tool to validate data comming from **path and query parameters**, if you happen to know I would be glad to hear!