apicollective / apibuilder

Simple, Comprehensive Tooling for Modern APIs
https://www.apibuilder.io/
MIT License
565 stars 83 forks source link

Basic Validation #426

Open Seanstoppable opened 8 years ago

Seanstoppable commented 8 years ago

It seems like there is a lot of basic validation that can be done on the client side, potentially saving a network call.

For example, validating numbers so they are within a range. Regex validation for Strings Non-empty strings Date ranges for strings, both in terms of not accepting dates outside of a certain range, as well as making sure a range does not exceed some threshold (i.e, I want to enforce that people don't make calls for 3 years of data).

These can and should also be on the server side, but also having them client side saves the service from bad calls, and the client from spending time making bad calls.

benjamine commented 8 years ago

after some though, it seems the easiest to way to do this is to rely on existing JSON-schema validators (lots of implementations: http://json-schema.org/implementations.html

we just need to:

Side note: what if apidoc just used JSON-schema for Models?, super mature, and would remove that first step

mbryzek commented 8 years ago

interesting - would be great to know what the delta is if any from the existing schemas to json schema. Couple thoughts:

benjamine commented 8 years ago

agreed, the shortcuts in apidoc are nice, I think mostñy the diffs are:

in general, I think json schema is a (big) superset, so writing a apidocModel/Enum => JSON schema should be trivial.

The only exceptions might be primitive types, but JSON schema can be extended for that, for integer types we can set minimum/maximum, and for floating types we can use some custom notation that a validator can catch. here's a json schema validator for js https://github.com/epoberezkin/ajv

mbryzek commented 8 years ago

definitely open to the idea! are you interested in exploring an initial PR?

benjamine commented 8 years ago

sure, I'm just not literate in Scala though :(, but not sure yet how much could be done by the apidoc service vs. code generators. this could be done 100% by a generator, but maybe we can simplify it for them.

This is a way in which we could we could implement request validation

At compilation time:

From my apidoc.json generate a single JSON.schema that can validate any operation request for my API, for that we just have to represent them in JSON format:

{
  operations:  {
     // in the schema all operations would be optional properties of the "operations" property, so you can include just one on a request.
     anOperationName: {       
       parameters:  {
         aParameter: {
           // here our schema would validate that the location is the expected
           location: 'form'
           // to validate this we use apidoc Model => JSON schema conversion
           value: ....
         }
         anotherParameter: {
           location: 'form'
           value: ....
         }
       },
       headers: {
          // we can validate headers too
       }
     }
  }
}

This apidoc.json => apirequest.json schema, is something generic that could be implemented only once, by a tool we provide (is there something like XSLT for JSON? :D ).

Then at every request, code generators would only have to do this for each request:

That way the part left to the generators is rather simple (I would easily implement that on the node.js code generator :) )

benjamine commented 8 years ago

I can write at least a ref implementation of that apidoc.json => apirequest.json schema generator, that is something we could provide as a service, users only need to do that at compilation time (or whenever apidoc.json changes).

benjamine commented 8 years ago

ok, I built a little prototype of that: https://github.com/benjamine/apidoc-json-schema

and deployed it using now, you can try this:

# on a folder where there's an apidoc.json
curl -X POST https://apidoc-json-schema-ltnrrsqyiy.now.sh/ --data-binary @./apidoc.json > jsonschema.json
benjamine commented 8 years ago

Now by the power of interoperability :) you get other things for free like converting types and trimming unspecified properties (aka whitelisting), in node.js using something like this: contracts which you can use for responses too (to prevent exposing any sensitive data).