For the last few months, I have had to pause the development of rescript-rest because an important feature was missing in my other library, rescript-schema. I finally managed to implement it, and I am happy to announce the release of ReScript Schema V7 as well as the continuation of rescript-rest development.
ReScript Schema V7
S.object superpowers
I needed this for rescript-rest, and I hope it will be useful for many other rescript-schema users.
s.flatten
Now, it’s possible to spread/flatten an object schema in another object schema, allowing you to reuse schemas in a more powerful way.
type entityData = {
name: string,
age: int,
}
type entity = {
id: string,
...entityData,
}
let entityDataSchema = S.object(s => {
name: s.field("name", S.string),
age: s.field("age", S.int),
})
let entitySchema = S.object(s => {
let {name, age} = s.flatten(entityDataSchema)
{
id: s.field("id", S.string),
name,
age,
}
})
s.nestedField
A new nice way to parse nested fields:
let schema = S.object(s => {
{
id: s.field("id", S.string),
name: s.nestedField("data", "name", S.string)
age: s.nestedField("data", "name", S.int),
}
})
Object destructuring
Also, it’s possible to destructure object field schemas inside of the definition. You could also notice it in the s.flatten example 
let entitySchema = S.object(s => {
let {name, age} = s.field("data", entityDataSchema)
{
id: s.field("id", S.string),
name,
age,
}
})
While the example with s.flatten expect an object with the type {id: string, name: string, age: int}, the example above and with s.nestedField will expect an object with the type {id: string, data: {name: string, age: int}}.
Extend field with another object schema
You can define object field multiple times to extend it with more fields:
let entitySchema = S.object(s => {
let {name, age} = s.field("data", entityDataSchema)
let additionalData = s.field("data", s => {
"friends": s.field("friends", S.array(S.string))
})
{
id: s.field("id", S.string),
name,
age,
friends: additionalData["friends"],
}
})
Destructuring works only with not-transformed object schemas. Be careful since it’s not protected by type system.
Autocomplete improvements
Updated context type names to s for better auto-complete in your IDE.
-
effectCtx → s
-
Object.ctx → Object.s
-
Tuple.ctx → Tuple.s
-
schemaCtx → Schema.s
-
catchCtx → Catch.s
S.json redesign
Added unsafe mode for S.json:
-
S.json → S.json(~validate: bool)
- More flexible
- Improved tree-shaking
- Tools using
rescript-schema can get the info from the tagged type: JSON → JSON({validated: bool})
Other cool changes and sometimes breaking
-
Added serializeToJsonStringOrRaiseWith
-
Allow to create S.union with a single item
-
Removed s.failWithError. Use S.Error.raise instead
-
PPX: Removed @schema for type expressions. Use @s.matches instead.
-
Removed async support for S.union. Please create an issue if you used the feature
-
Improved parsing performance of S.array and S.dict ~3 times
-
Automatic serializing stopped working for tuples/objects/unions of literals. Use S.literal instead
-
Removed InvalidTupleSize error code in favor of InvalidType
-
Changed payload of Object and Tuple variants in the tagged type
-
Redesigned Literal module to make it more efficient
- The
S.Literal.t type was renamed to S.literal, became private and changed structure. Use S.Literal.parse to create instances of the type
-
S.Literal.classify → S.Literal.parse
-
S.Literal.toText → S.Literal.toString. Also, started using .toString for Function literals and removed spaces for Dict and Array literals to make them look the same as the JSON.stringify output
-
Moved built-in refinements from nested modules to improve tree-shaking:
-
S.Int.min → S.intMin
-
S.Int.max → S.intMax
-
S.Int.port → S.port
-
S.Float.min → S.floatMin
-
S.Float.max → S.floatMax
-
S.Array.min → S.arrayMinLength
-
S.Array.max → S.arrayMaxLength
-
S.Array.length → S.arrayLength
-
S.String.min → S.stringMinLength
-
S.String.max → S.stringMaxLength
-
S.String.length → S.stringLength
-
S.String.email → S.email
-
S.String.uuid → S.uuid
-
S.String.cuid → S.cuid
-
S.String.url → S.url
-
S.String.pattern → S.pattern
-
S.String.datetime → S.datetime
-
S.String.trim → S.trim
-
S.Int.min → S.intMin
-
S.Int.max → S.intMax
-
S.Number.max → S.numberMax/S.integerMax
-
S.Number.min → S.numberMin/S.integerMin