Skii
Table of contents
Motivation
Skii is a toolkit for creating typesafe backends.
The fundamental complexity of backend development is transferring and transforming data as it passes between your database, your ORM, your API endpoints, your caching layer, and the client. It's your job to write code to ensure that the data is in the proper shape at each step along the way.
Usually, you end up with a codebase that's a rat's nest of duct tape and type validators. These type validators may be explicitly defined (using tools like Joi, Yup, or Zod), implicitly defined (the return type of SQL query), or composed entirely of hopes and prayers (if you don't use TypeScript!).
That's where Skii comes in. Skii makes it easy to define and enforce the shape of your data as it passes through the layers of your application.
But we'll get to that. Let's start with some basics.
Installation
yarn add skii
npm install --save skii
Basic usage
Primitives
;;;;;
The core of Skii is a validation library, similar to Yup, Joi, or io-ts. If you've never heard of any of these, don't worry, no prior experience is required.
Let's create a simple schema that validates strings.
; ;
Every Skii schema has certain methods.
Parsing
We can use the .parse
method to check a value against the schema type.
stringSchema.parse'asdf'; // => return "asdf"stringSchema.parse12; // => TypeError
Type inference
You can infer the TypeScript type of any schema like so:
;; // string
Optional
We can make schemas optional
like so:
; // returns astringOrUndefined.parseundefined; // => passes, returns undefined ;// string | undefined
Nullable
Similarly, we can make a schema nullable like so:
;stringOrUndefined.parsenull; // => passes, returns null ;// string | null
Immutability
Skii schemas are immutable! All methods return a new schema instance.
.parse
, .optional
, and .nullable
are available on any Skii schema.
Enums
;// SkiiType<"lab" | "schnauzer" | "beagle">
Arrays
Objects
- merge
- augment
- pick
- omit
- partial
Example
1. Define your data models in Skii
; ;
2. Spec your API
; // familiar Express-like APIapp .patch .implement; app.serve3000;
This is an example for implementing a REST API but Skii has built-in modules to define REST, RPC, and GraphQL APIs in a totally typesafe way.
3. Generate a TypeScript client SDK from your API
// ./server/app.tsapp.export.toSDK; // ./client/index.ts; ;
Installation
yarn add skii
npm install skii --save
Concepts
Schema definitions vs API definitions
Moving forward, it is vital that you understand the difference between "model definitions" and "API definitions". GraphQL users tend to be acutely aware of this distinction, but if you have a background implementing traditional SQL-backed REST APIs it may be confusing initially.
Model definitions define the data types that will be stored in your database.
API definitions define the data types that are accepted or returned by the API consumed by the client.
If you've ever created an ORM model, that would be classified as a "schema definition" since ORMs provide helper functions for writing to your database. On the other hand, GraphQL definitions are "API definitions" since they define what data your clients can read or write to the database.
In Skii you define your models first. Then you create API endpoints using your models as a basis. What this means exactly will become clear as you read through these docs.
Usage
Import
;
Create a Skii instance
You create an "instance" of skii with the SkiiFactory
method.
; ;
Create model definitions
You can use the Skii instance to define data util.
;
You can use the following methods to define the properties of a model
// for primary keyss.id; // primitive typess.string;s.int;s.float;s.boolean; // arrays of primitive typess.array.string;s.array.float;s.array.int;s.array.boolean;
With the exception of s.id()
(which is always considered required
), you can append .required()
to any of these to make it a required field.
With the exception of s.id()
(which is always considered unique
), you can append .unique()
to any property to enforce uniqueness.
Relations
Use s.toOne
and s.toMany
to create relations between models.
;
Recursive relations
To create recursive relations without getting TypeScript errors, you have to explicitly type your models.
; ;
Validation checks
Currently Skii doesn't support validation checks beyond verifying basic types (string, float, etc). We plan to incorporate more advanced validation (e.g. number min/max, string length, regex support, isEmail
, isURL
, etc) in a future release.
Configuration
;
For all but the simplest cases, you'll want to configure your Skii instance by passing a type the
You are able to configure various options by passing a TypeScript type into the generic SkiiFactory
function, like so:
;
Define schema definitions
You define your data types with skii.model
.