Yup validation schema typescript

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

License

kristianmandrup/schema-to-yup

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

Readme.md

Build a Yup schema from a JSON Schema, GraphQL schema (type definition) or any other similar type/class and field/properties model or schema 🙂

See Advanced config for all the more advanced configuration options available to customize this builder to support any of your requirements.

The builder currently supports the most commonly used JSON Schema layout

To support other schemas see Advanced config

You can use the YupBuilderConfig and TypeHandlerConfig type interfaces to facilitate building up the config object to pass to the YupBuilder .

npm install schema-to-yup -S or yarn add schema-to-yup

Create a JSON schema to validate against

const schema =  $schema: "http://json-schema.org/draft-07/schema#", $id: "http://example.com/person.schema.json", title: "Person", description: "A person", type: "object", properties:  name:  description: "Name of the person", type: "string", >, email:  type: "string", format: "email", >, foobar:  type: "string", matches: "(foo|bar)", >, age:  description: "Age of person", type: "number", exclusiveMinimum: 0, required: true, >, characterType:  enum: ["good", "bad"], enum_titles: ["Good", "Bad"], type: "string", title: "Type of people", propertyOrder: 3, >, >, required: ["name", "email"], >;

Create a config object to configure details of your validation

const config =  // for error messages. errMessages:  age:  required: "A person must have an age", >, email:  required: "You must enter an email address", format: "Not a valid email address", >, >, >;

Create the yup schema using the builder method buildYup

const  buildYup > = require("schema-to-yup"); const yupSchema = buildYup(schema, config);

Use the yup schema methods such as isValid to validate

// console.dir(schema) const valid = await yupSchema.isValid( name: "jimmy", age: 24, >); console.log( valid, >); // =>

The above example would generate the following sort of Yup validation schema:

const schema = yup.object().shape( name: yup.string().required(), age: yup.number().required().positive(), // . >);

Please note that this library does not currently resolve $ref (JSON Pointers) out of the box. You can use another library for that.

You could f.ex use json-schema-ref-parser to preprocess your schema. Also see:

By default, any property will be explicitly notRequired unless set to be required, either via required: true in the property constraint object or via the required list of properties of the object schema definition (of the property).

You can override the notRequired behavior by setting it on the new mode object of the configuration which can be used to control and fine-tune runtime behaviour.

const jsonSchema =  title: "users", type: "object", properties:  username:  type: "string" >, >, >;
const yupSchema = buildYup(jsonSchema,  mode:  notRequired: true, // default setting >, >); // will be valid since username is not required by default const valid = yupSchema.validateSync( foo: "dfds", >);
const yupSchema = buildYup(jsonSchema,  mode:  notRequired: true, // default setting >, >); // will be invalid since username is required by default when notRequired mode is disabled const valid = yupSchema.validateSync( foo: "dfds", >);

The new run time mode settings are demonstrated under sample-runs/mode

No validation error (prop not required unless explicitly specified):

$ npx babel-node sample-runs/modes/not-required-on.js

Validation error if not valid type:

$ npx babel-node sample-runs/modes/not-required-on.js

You can access the internal Yup shape, via shapeConfig on the yup schema returned by the buildYup schema builder function. Alternatively simply call propsToShape() on the yup builder.

This allows you to easily mix and match to suit more advanced requirements.

const  buildYup > = require("json-schema-to-yup"); const  shapeConfig > = buildYup(json, config); // alternatively // const shape = buildYup(json, config).propsToShape() const schema = yup.object().shape( . shapeConfig, . customShapeConfig, >);

Currently the following schema types are supported:

  • strict
  • default
  • nullable
  • const
  • required
  • notRequired
  • oneOf ( enum , anyOf )
  • notOneOf
  • refValueFor for confirm password scenario
  • typeError custom type error message
  • when
  • isType
  • nullable ( isNullable )

Reference constraints within the schema can be defined as follows:

schema =  required: ["startDate", "endDate"], type: "object", properties:  startDate:  type: "number", >, endDate:  type: "number", min: "startDate", >, >, >;

Internally this will be resolved using Yup.ref as documented here in the Yup readme.

ref allows you to reference the value of a sibling (or sibling descendant) field to validate the current field.

Yup.ref is supported in the Yup docs for the following:

  • ensure
  • compact
  • items ( of )
  • maxItems ( max )
  • minItems ( min )
  • itemsOf ( of )
  • integer
  • moreThan ( exclusiveMinimum )
  • lessThan ( exclusiveMaximum )
  • positive
  • negative
  • min ( minimum )
  • max ( maximum )
  • truncate
  • round
  • minLength ( min )
  • maxLength ( max )
  • pattern ( matches or regex )
  • email ( format: ’email’ )
  • url ( format: ‘url’ )
  • lowercase
  • uppercase
  • trim

For pattern (RegExp) you can additionally provide a flags property, such as flags: ‘i’ . This will be converted to a RegExp using new RegExp(pattern, flags)

For the pattern constraint you can also pass in excludeEmptyString to exclude empty string from being evaluated as a pattern constraints.

The library JSON Schema model builder is a powerful toolset to build a framework to create any kind of output model from a JSON schema.

If you enjoy this declarative/generator approach, try it out!

  • Have unit tests that cover most of the constraints supported.
  • Could use some refactoring using the latest infrastructure (see NumericConstraint )
  • Please help add more test coverage and help refactor to make this lib even more awesome 🙂

A new version is under development at schema-to-yup-mono which is this code ported to a lerna monorepo with a cleaner, mode modular structyure. More work needs to be done in terms of TDD and unit testing. Ideally this repo should be ported to Nx

Please feel free to come with ideas and suggestions on how to further improve this library.

2018 Kristian Mandrup (CTO@Tecla5)

Источник

Response validation with Yup

Problem: Many times in our Frontend we just «accept» that an API response is what it should be. In Typescript we hide behind generics to type cast, but what if our API is a success with a data structure that we didn’t expect? This happened a few times in a recent project. The backend logic for the API hit about 4 different services (that we had no control over), each of these are points of failure. Sometimes one would silently fail causing the API to be a 200 with invalid data. I had a great time. Here is what I am talking about:

async function getMe()  try  const response = await fetch('http://get.profile') const json: Profile = await response.json() // Surely `json` will be the shape me need, nothing can go wrong renderMe(json) > catch (error)  // Nothing will ever go wrong console.error(error) > > 

Now, 99% of the time, this is fine, and 99% of the time, I do this as well. Probably shouldn’t, but here we are. We kinda assume that if something goes wrong with the response then the catch will catch it. Otherwise, we’re all good. This doesn’t just happen with custom fetch calls. In React, if you use a fetch hook, many times it will allow you to pass in generics ( useFetch() ) to say what the shape of the data will be. Again, this works, I do it, but there isn’t a lot of safety from incorrect data. Idea: I have been thinking about is using a validation library, in this case yup to add a extra layer of protection (this idea will work with any validation library). Usually, if we’re working with forms we already have a validation library installed, so we aren’t really introducing extra dependencies into our project. Additionally, if you’re a Typescript user, these libraries can make type definitions a lot easier as well! Looking at our example above, we need to introduce 2 extra things. One is our schema and the other is validating our json .

Schema

Continuing with the get profile idea, we’ll create a profile schema. Depending on how you like to structure your projects. This could be in a profile.schema.ts or profile.model.ts file. Allowing you to separate things a little easier.

import  object, string, date > from 'yup' export const profile = object( email: string().email().required(), name: string().required(), birthday: date().required() >) /** * For Typescript users, you can import `InferType` from yup * and export the Profile type * export type Profile = InferType */ 

Validate the data

Now that we have our profile definition, we can validate our json , and handle any ValidationError that yup might throw.

import  ValidationError > from 'yup' async function getMe()  try  const response = await fetch('http://get.profile') const json = await response.json() const data = await profile.validate(json,  stripUnknown: true >) renderMe(data) > catch (error)  if (error instanceof ValidationError)  alert("The response data is invalid") return > alert("Uncaught error occured") > > 
  1. We have removed our generics. If the validate call is successful, then we can be confident that data is in our Profile shape.
  2. In the catch block, we can now test for this ValidationError and provide the user some extra details about the issue, instead of a generic ‘Something went wrong’ message.
  3. (Optional) I also passed in stripUnknown: true to the validate options. As the name suggests, it will remove any data that isn’t in our profile schema. This makes the data more consistent but also ‘forces’ someone to update the schema if additional data is added.

Using a hook library

In the case that you are using a fetch hook of some description. Some of them may have a validation option where you can do the same thing. Alternatively, I’ve seen that many allow for a transform step. Giving you a chance to change the data before returning it to the user.

const  data, loading, error > = useFetch('http://get.profile',  transform: async (json) =>  const data = await profile.validate(json) return data > >) 

That’s all folks

Aaaand. that is it. Nothing else to really add. If you take anything away from this it would be, don’t fully trust that your data is as expected. Adding additional checks in your components or logic won’t hurt anyone. Validation libraries are usually very performant and already installed in many projects, utilising them to standardise schema definitions, type definitions and API data may provide some additional benefits to your projects. It could also help with mocking data, I am sure there are libraries out there that can take one of these schemas and output some JSON that matches the structure.

Below is a Codesandbox (hopefully it shows up) with this idea implemented, feel free to play around a bit. I did set the console to be open, but it sometimes vanishes so it might be best to open it in a different tab. Play around with the me function and return some weird data to see if the validation works.

Bit of a disclaimer: the ideas in this article are just ideas. I haven’t been able to test them out fully yet. Complex data structures or conditional responses might require a more complex schema. I have noticed with complex schemas that the InferType becomes a «everything is optional» type, which isn’t always ideal.

Источник

Читайте также:  Java to string radix
Оцените статью