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.
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 thedisallow
value, send the response with the error message.
- API Schema
- Validation Filter
# dep_users.yaml
urlPath: /dep_users
request:
- fieldName: department
fieldIn: query
validators:
- name: required
args:
disallow:
- ''
- ' '
- 'null'
SELECT * FROM users
WHERE department = {{ context.params.department | is_required(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 beuuidv1
,uuidv4
oruuidv5
- API Schema
- Validation Filter
# order.yaml
urlPath: /orders/:id
request:
- fieldName: id
fieldIn: path
validators:
- name: uuid
args:
version: uuidv5
SELECT * FROM order
WHERE id = {{ context.params.id | is_uuid(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'
.
- API Schema
- Validation Filter
# 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
SELECT * FROM order
WHERE create_date = {{ context.params.date | is_date(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.
- API Schema
- Validation Filter
# bank_account.yaml
urlPath: /bank_account/:id
request:
- fieldName: id
fieldIn: path
validators:
- name: string
args:
format: '^09[0-9]{8}$'
length: 10
SELECT * FROM bank_account
WHERE id = {{ context.params.id | is_string(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.
- API Schema
- Validation Filter
# bank_account.yaml
urlPath: /youth_users
request:
- fieldName: age
fieldIn: query
validators:
- name: integer
args:
- greater: 10
- less: 19
SELECT * FROM bank_account
WHERE age = {{ context.params.age | is_integer(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.
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.
- API Schema
- Validation Filter
# customers.yaml
urlPath: /customers
request:
- fieldName: marital_status
fieldIn: query
validators:
- name: enum
args:
items:
- Married
- Single
- Unknown
SELECT * FROM customers
WHERE marital_status = {{ context.params.marital_status | is_enum(items=['Married', 'Single', 'Unknown']) }}