Schemas
Have you ever wished you could create Zod Schemas from your TypeScript types, or use your TypeScript types to parse and validate data at runtime? You can do this in Agency!
schema() function
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)The bang(!) syntax
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, otherwise it will be a success.
You can use this with llm calls too:
const result: Person! = await llm("Describe a person.")Remember to unwrap the Result type to get the value out of it.
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.
Validating Result types
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.