Skip to main content

API Validation

In the API Schema, we talked about how to define the API Schema, and also mentioned the validators field feature could assist each request parameter to check the format. In the chapter we will talk more about the validator's usage and currently how many validators VulcanSQL supports.

There are two ways to apply validators: define them in API schema and use validation filters.

Define validators in data api schema

The most common way to apply validators is by validators property for dynamic parameters, this field in the API Schema is an array type, so you could add the multiple validators on a single parameter like the example below:

urlPath: /orders/:order_id
request:
- fieldName: orders_id
fieldIn: path
validators:
- required
- uuid

In the above example, we restricted the parameter order_id to be in UUID format and be required. All the requests that aren't fit these requirements will be rejected.

info

VulcanSQL sometimes applys some validators automatically, e.g. when a parameter is used in url path, we'd apply required validator on it.

Set the arguments for the validators

Some validators accept some extra arguments. We could set them by adding args field, e.g: to add arguments for number and date validators:

urlPath: /orders
request:
- fieldName: create_date
fieldIn: query
validators:
- name: date
args:
format: 'YYYY-MM-DD'
- fieldName: price
fieldIn: query
validators:
- name: number
args:
min: 0
max: 1000000

As you saw, to add argument for a validator, we need to use the name field to indicate the validator name, and use args filed to specify arguments.

Validation filters

Another way to apply validators is using validation filters, it allows you to define validators with SQL Syntax. Every validator has a unique filter named with prefix is_, e.g. integer validator has the is_integer filter.

To use these filter, chain them after your parameters:

-- orders.sql
SELECT * FROM
orders
WHERE order_id = {{ context.params.order_id | is_required | is_uuid }}

Set the arguments for the validators

To set arguments for validators, use Python's keyword arguments:

-- orders.sql
SELECT * FROM
orders
WHERE create_date = {{ context.params.create_date | is_date(format='YYYY-MM-DD') }}
AND price = {{ context.params.price | is_integer(min=0, max=1000000) }}

For more information and further use cases, please check the document Validation Filter.

Error Response when sending invalid requests

When a request doesn't fit the requirements of validators, we'd reject the request and return an error response, below is an example:

# order.yaml
urlPath: /orders
request:
- fieldName: price
fieldIn: query
validators:
- name: number
args:
min: 0
max: 1000000

Then when you sent the request with GET<endpoint>/api/orders?price=1000001, it will return an HTTP status code with 400 and the below message:

{
code: 'vulcan.userError',
message: 'The input parameter is invalid, it should be integer type',
}

Current supported validators

required validator

Make the request parameter field the required parameter, use the Joi to check required. The args field:

  • disallow - Array type. Specifies what input values are also not as required and if the parameter value appeared in the disallow value, send the response with the error message.
# dep_users.yaml
urlPath: /dep_users
request:
- fieldName: department
fieldIn: query
validators:
- name: required
args:
disallow:
- ''
- ' '
- 'null'

Then when you sent the request with GET<endpoint>/api/dep_users?department=null, it will return an HTTP status code with 400 and the below message:

{
code: 'vulcan.userError',
message: 'The input parameter is invalid, it should be required',
}

uuid validator

Validate the UUID format for the request parameter, use the Joi to check UUID. The args field:

  • version - String type. Specifies the UUID version. the option could be uuidv1, uuidv4 or uuidv5
# order.yaml
urlPath: /orders/:id
request:
- fieldName: id
fieldIn: path
validators:
- name: uuid
args:
version: uuidv5

date validator

Validate whether the request parameter is Date Format type or not, use the dayjs package to be the format source. The args field:

  • format - String type. Specifies the date needed format, supported ISO_8601 token, e.g: 'YYYYMMDD', 'YYYY-MM-DD', 'YYYY-MM-DD HH:mm'.
# order.yaml
urlPath: /orders
request:
- fieldName: create_date
fieldIn: query
validators:
- name: date
args:
format: 'YYYY-MM-DD' # make the date only support 'YYYY-MM-DD' format

string validator

Validate whether the request parameter is a String type, use the Joi to check String ( including the args field ). The args field:

  • format - String type. Specifies the string format, and supports regular expression. Use the Joi pattern to check.
  • length - Number type. Specifies the String's exact length.
  • max - Number type. Specifies the minimum number of string characters.
  • min - Number type. Specifies the maximum number of string characters.
# bank_account.yaml
urlPath: /bank_account/:id
request:
- fieldName: id
fieldIn: path
validators:
- name: string
args:
format: '^09[0-9]{8}$'
length: 10

integer validator

Validate whether the request parameter is an Integer type, use the Joi to check Integer. ( including the args field ). The args field:

  • max - Number type. Specifies the maximum integer value.
  • min - Number type. Specifies the minimum integer value.
  • greater - Number type. Specifies that the integer value must be greater than the limit.
  • less - Number type. Specifies that the value must be less than the limit.
# bank_account.yaml
urlPath: /youth_users
request:
- fieldName: age
fieldIn: query
validators:
- name: integer
args:
- greater: 10
- less: 19

enum validator

Constraint the input values with a whitelist. The args field:

  • items - Array type (Required). Specifies the whitelist, you must add at least one element to this array.
tip

Enum validator won't care about the data type, so the both [1] amd ["1"] allow the value 1 no mater it is string or number.

# customers.yaml
urlPath: /customers
request:
- fieldName: marital_status
fieldIn: query
validators:
- name: enum
args:
items:
- Married
- Single
- Unknown