GitHub

Components

Models

Models are backbone of Rio's validation mechanism. You can assign models to methods in order to validate before your method call. Thus, your code will be more readable and less error prone. We strictly suggests schemas written with JSON Schema (Draft-07).

Rio doesn't support references in models.

models/Person.json


{
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    }
  }
}

You will be provided client-side models written in Kotlin, Swift and Typescript when you use models in your project.

Rio doesn't support any kind of reference usages in JSON schema models.

Required Variables in Models

While defining models, we specify the type of each variable and if a variable needs to be initialized.

If a variable is in the required array, this means that variable needs to be initialized in typescript code.

User Model Example

{
  "type": "object",
  "required": [ // these specified fields needs to be initialized
    "userFullName", 
    "email",
    "userId",
  ],
  "properties": {
    "userId": {
      "type": "string"
    },
    "userRank": {
      "type": "string"
    },
    "userFullName": {
      "type": "string"
    },
    "email": {
      "type": "string"
    },
    "lastEnteredPlatform":{
      "enum": [
        "WEB",
        "IOS",
        "ANDROID"
      ]
    }
  }
}

For more advanced use cases please visit https://json-schema.org.

Using A Model

In order to user models for validation, you need to import them in your class template file. There are 4 types of models:

  • inputModel : Request body input model
  • outputModel : Response body output model
  • errorModel : Error response body output model
  • queryStringModel : Query string params input model

Usage:

classes/User/template.yml


authorizer: index.authorizer
init:
  handler: index.init
  inputModel: UserProfileInputModel
  outputModel: ProfileModel
  errorModel: ErrorModel
  queryStringModel: ProfileQSModel
get:
  handler: index.getInstance
  inputModel: UserProfileGetModel
  outputModel: ProfileModel
  errorModel: ErrorModel
  queryStringModel: ProfileQSModel
getState: index.getState
getInstanceId: index.getInstanceId
methods:
  - method: updateProfileInput
    inputModel: StoreInfo
    outputModel: ProfileModel
    errorModel: ErrorModel
    queryStringModel: ProfileQSModel
    type: WRITE
    handler: index.update


  - method: getStoreInfo
    queryStringModel: UserProfileParamsModel
    outputModel: ProfileModel
    errorModel: ErrorModel
    queryStringModel: ProfileQSModel
    type: READ
    handler: index.profile

Advanced Query String Model

Models for query string variables work a little different from other kind of models. This is important for two main reasons.

First of all, just like any other web framework or web application, their internal format must be Record<string, string>. As a workaround, RIO looks for two special query string keys: data:string and __isbase64:boolean. If you provide them RIO directly assumes that there is some information in base64 format in data key. Thus, whatever you put into data overwrites the query string variables and your final data become Record<string, any> format.

Secondly, to be able to validate queryStringModel, RIO tries to convert each variable to expected type. Only primitive types are supported for this feature. After the conversion phase, RIO checks if the data is valid and sends the original data to the handler method.

const model = {
    "type": "object",
    "properties": {
        "chars": { "type": "string" },
        "num1": { "type": "number" },
    },
    "required": [ "num1" ],
    "additionalProperties": false
}


const queryStringData = { chars: 'XyZ!', num1: '1', num2: '2' }

Before validation, RIO converts each type according to the model.

Adding Models to Methods

After we created the model (in this example CreateTodoInput and CreateTodoOutput), we should add the model to the method file which we are going to use. Add the models to your methods in template.yml file.

# template.yml
...rest
methods:
    - method: createTodo
      inputModel: CreateTodoInput     # CreateTodoInput model added
      outputModel: CreateTodoOutput   # CreateTodoOutput model added
      handler: index.createTodo

Validation

Rio has an optional built-in validation with JSON schema models. After adding a valid JSON schema into models, you assign them to your methods as input, output, query string or error model. Rio will evaluate the data with your model and inform the client accordingly.

Let's say we have a model called SayHelloInput

{
  "type": "object",
  "required": [
    "firstName"
  ],
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    }
  }
}

Post Body Validation

To validate a post body you need to define validation in inputModel field like this:

init: index.init
getState: index.getState
methods:
  - method: sayHello
    inputModel: SayHelloInput
    tag: test
    handler: index.sayHello

Query String Validation

To validate data sent in querystrings you need to define validation in queryStringModel field like this:

init: index.init
getState: index.getState
methods:
  - method: sayHello
    queryStringModel: SayHelloInput
    tag: test
    handler: index.sayHello

Error Validations

Rio uses AJV for model validation. If a validation fails Rio returnes a response with status code: 400.

{
  "code": "VALIDATION",
  "message": "Model validation has been failed.",
  "issues": [
    {
      "instancePath": "",
      "schemaPath": "#/required",
      "keyword": "required",
      "params": {
        "missingProperty": "firstName"
      },
      "message": "must have required property 'firstName'"
    }
  ]
}
Previous
Dependencies