Skip to content

Commit

Permalink
add examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ianstormtaylor committed Nov 27, 2017
1 parent 9759836 commit c58e413
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 5 deletions.
26 changes: 21 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
<br/>

<p align="center">
<a href="#example">Example</a> •
<a href="#usage">Usage</a> •
<a href="#why">Why?</a> •
<a href="#principles">Principles</a> •
<a href="#examples">Examples</a> •
<a href="#documentation">Documentation</a>
</p>

Expand All @@ -35,12 +36,12 @@
<br/>
<br/>

Superstruct makes it easy to define interfaces and then validate Javascript data against them. Its type annotation API was inspired by [Typescript](https://www.typescriptlang.org/docs/handbook/basic-types.html), [Flow](https://flow.org/en/docs/types/) and [GraphQL](http://graphql.org/learn/schema/), so its familiar API makes it easy to get started. But Superstruct is designed for runtime data validations, like accepting arbitrary input in a REST or GraphQL API, so it throws detailed errors for you or your end users.
Superstruct makes it easy to define interfaces and then validate Javascript data against them. Its type annotation API was inspired by [Typescript](https://www.typescriptlang.org/docs/handbook/basic-types.html), [Flow](https://flow.org/en/docs/types/) and [GraphQL](http://graphql.org/learn/schema/), which gives it a API familiar, easy to understand API. But Superstruct is designed for runtime data validations, like accepting arbitrary input in a REST or GraphQL API, so it throws detailed errors for you or your end users.


<br/>

### Example
### Usage

Superstruct exports a `struct` factory for creating functions that validate data against a specific schema:

Expand Down Expand Up @@ -84,7 +85,7 @@ import isEmail from 'is-email'

const struct = superstruct({
types: {
uuid: v => isUuid.v5(v),
uuid: v => isUuid.v4(v),
email: v => isEmail(v) && v.length < 256,
}
})
Expand All @@ -96,7 +97,7 @@ const validate = struct({
})

const data = {
id: '5a2de30a-a736-5aea-8f7f-ad0f019cdc00',
id: 'c8d63140-a1f7-45e0-bfc6-df72973fea86',
email: 'jane@example.com',
}

Expand Down Expand Up @@ -148,10 +149,25 @@ Which brings me to how Superstruct solves these issues...
3. **Familiar API.** The Superstruct API was heavily inspired by [Typescript](https://www.typescriptlang.org/docs/handbook/basic-types.html), [Flow](https://flow.org/en/docs/types/) and [GraphQL](http://graphql.org/learn/schema/). If you're familiar with any of those, then its schema definition API will feel very natural to use, so you can get started quickly.


<br/>

### Examples

Superstruct's API is very flexible, allowing it to be used for a variety of use cases on your servers and in the browser...

- [Basic Validation](./examples/basic-validation.js)
- [Custom Types](./examples/custom-types.js)
- [Default Values](./examples/default-values.js)
- [Throwing Errors](./examples/throwing-errors.js)
- [Custom Errors](./examples/custom-errors.js)


<br/>

### Documentation

To get started




Expand Down
33 changes: 33 additions & 0 deletions examples/basic-validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable no-console */

import struct from '..'

// Define a struct to validate with.
const validate = struct({
id: 'number',
name: 'string',
email: 'string',
age: 'number',
departments: ['string'],
is_admin: 'boolean?',
})

// Define data to be validated.
const data = {
id: 1,
name: 'Jane Smith',
email: 'jane@example.com',
age: 42,
departments: ['engineering', 'product'],
}

// Validate the data by calling `validate`.
// In this case, the data is valid, so it will not throw.
try {

This comment has been minimized.

Copy link
@qgustavor

qgustavor Dec 2, 2017

Why the redundant try/catch blocks in this and other files?

This comment has been minimized.

Copy link
@ianstormtaylor

ianstormtaylor Dec 2, 2017

Author Owner

Good point. I did it to make clear that it will throw, but it is kind of confusing I guess.

validate(data)
console.log('Valid!')
} catch (e) {
throw e
}

// 'Valid!'
49 changes: 49 additions & 0 deletions examples/custom-errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable no-console */

import struct from '..'

// Define a struct to validate with.
const validate = struct({
id: 'number',
name: 'string',
email: 'string',
})

// Define data to be validated.
const data = {
id: 1,
name: true,
email: 'jane@example.com',
}

// Validate the data by calling `validate`. In this case the
// `name` property is invalid, so an error will be thrown that
// you can catch and customize to your needs.
try {
validate(data)
console.log('Valid!')
} catch (e) {
switch (e.code) {
case 'property_invalid': {
const err = new Error(`user_${e.key}_invalid`)
err.attribute = e.key
err.value = e.value
throw err
}
case 'property_required': {
const err = new Error(`user_${e.key}_required`)
err.attribute = e.key
throw err
}
case 'property_unknown': {
const err = new Error(`user_attribute_unknown`)
err.attribute = e.key
throw err
}
}
}

// Error: 'user_name_invalid' {
// attribute: 'name',
// value: false,
// }
42 changes: 42 additions & 0 deletions examples/custom-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable no-console */

import { superstruct } from '..'
import isEmail from 'is-email'
import isUuid from 'is-uuid'
import isUrl from 'is-url'

// Define a `struct` with custom types.
const struct = superstruct({
types: {
uuid: v => isUuid.v4(v),
email: v => isEmail(v) && v.length < 256,
url: v => isUrl(v) && v.length < 2048,
}
})

// Define a struct which returns a `validate` function.
const validate = struct({
id: 'uuid',
name: 'string',
email: 'email',
website: 'url?',
})

// Define data to be validated.
const data = {
id: 'c8d63140-a1f7-45e0-bfc6-df72973fea86',
name: 'Jane Smith',
email: 'jane@example.com',
website: 'https://jane.example.com',
}

// Validate the data by calling `validate`.
// In this case, the data is valid, so it will not throw.
try {
validate(data)
console.log('Valid!')
} catch (e) {
throw e
}

// 'Valid!'
49 changes: 49 additions & 0 deletions examples/default-values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable no-console */

import struct from '..'

// Define an auto-incrementing unique id.
let uid = 1

// Define a struct to validate with.
const validate = struct({
id: 'number',
name: 'string',
email: 'string',
age: 'number',
is_admin: 'boolean?',
created_at: 'date',
}, {
id: () => uid++,
is_admin: false,
age: 0,
created_at: () => new Date(),
})

// Define data to be validated.
const data = {
name: 'Jane Smith',
email: 'jane@example.com',
age: 42,
}

// Validate the data by calling `validate`, and storing the
// return value in the `user` variable. Any property that
// wasn't defined will be set to its default value.
let user

try {
user = validate(data)
console.log('Valid!', user)
} catch (e) {
throw e
}

// 'Valid!', {
// id: 0,
// name: 'Jane Smith',
// email: 'jan@example.com',
// age: 42,
// is_admin: false,
// created_at: Date,
// }
34 changes: 34 additions & 0 deletions examples/throwing-errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* eslint-disable no-console */

import struct from '..'

// Define a struct to validate with.
const validate = struct({
id: 'number',
name: 'string',
email: 'string',
})

// Define data to be validated.
const data = {
id: 1,
name: true,
email: 'jane@example.com',
}

// Validate the data by calling `validate`. In this case the
// `name` property is invalid, so a `property_invalid` error
// will be thrown.
try {
validate(data)
} catch (e) {
throw e
}

// StructError: 'Expected the `name` property to be of type "string", but it was `false`.' {
// code: 'property_invalid',
// type: 'string',
// path: ['name'],
// key: 'name',
// value: false,
// }
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"eslint": "^3.8.1",
"eslint-plugin-import": "^2.0.1",
"is-email": "^1.0.0",
"is-url": "^1.2.2",
"is-uuid": "^1.0.2",
"mocha": "^3.2.0",
"np": "^2.13.1",
"uglify-js": "^2.7.0",
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2554,10 +2554,18 @@ is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"

is-url@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.2.tgz#498905a593bf47cc2d9e7f738372bbf7696c7f26"

is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"

is-uuid@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-uuid/-/is-uuid-1.0.2.tgz#ad1898ddf154947c25c8e54966f48604e9caecc4"

isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
Expand Down

0 comments on commit c58e413

Please sign in to comment.