Schemas
Types help with compile-time safety. In Agency, you can also use the same types for runtime validation.
There are several ways to use types for runtime validation. You can get the schema from a type using the schema function, and use it to validate an object:
type Person = {
name: string;
age: number;
}
const personSchema = schema(Person)
// validated will be a Result type
const validated = personSchema.parse(someObject)If you have a string containing JSON data, use parseJSON.
const validated = personSchema.parseJSON(someJSONString)Agency also has a shorthand for validation: the bang syntax. Here’s what it looks like.
const foo: Person! = someObjectNow, foo will be a Result type. If the validation fails, it will be a failure.
You can also use the bang shorthand syntax to validate parameters passed into functions:
function greet(name: string!, age: number!) {
// ...
}If any of these parameters fails to validate, the function returns immediately with a failure.
You can use the bang syntax to validate the return value from a function as well.
function getPerson(): Person! {
// ...
}If the value fails to validate, the function will return a failure.
Schemas and Result Types
When you use schema validation with Result types, there are some nuances to be aware of:
failures are never validated. For instance, suppose you have validation on the parameters of a function. If you pass in afailure, Agency won't validate it. Similarly, if a function returns afailure, Agency doesn't validate thatfailure.- We never rewrap a
Resulttype. This only applies to successes, because as I said, Agency doesn't even try to validate afailure. But we don't double-wrapsuccesses. If a function returns asuccessbut fails validation, we will return afailure. If a function returns asuccessand passes validation, we don't wrap it in anothersuccess. We simply propagate the existingsuccessvalue.
You can also add validation for the Result type itself.
const foo: Result! = someObjectThis will validate that foo is a Result type, which could be either success or failure.
Here's another example:
const foo: Result<Person>! = someObjectThis will validate that foo is a Result type, and if it's a success, it will validate that the wrapped value is a Person.
With Result types, you can also define types for both the success and failure. However, failures aren't touched, so what happens if you try to validate it?
const foo: Result<Person, Error>! = someObjectAgency still only validates if foo is a success. If it's a failure, we do not validate that the failure has the given type. This is because if we did, and the validation failed, we would have to replace this failure with a new failure, and then we would lose the original failure information.