silkapp / rest

Packages for defining APIs, running them, generating client code and documentation.

Home Page:http://silkapp.github.io/rest

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Digestive Functors

themoritz opened this issue · comments

Are there any plans to add support for the digestive-functors package?

At the moment, the best way I can see of using them is with stringI, and then running the form against JSON (eg with the digestive-functors-aeson package). However, if I do this I don't get any documentation on the schema for the endpoint.

But in principle, a kind of schema is implicitly contained in the FormTree of the digestive form that could be used. So I'm imagining a kind of DigestiveInput constructor for the Format data that extracts the information from the FormTree and generates a schema.

Advantages could be (mostly the advantages of digestive-functors):

  • Composability of forms and therefore of endpoints that share structure
  • More convenient error handling
  • Different forms yielding the same data type, so I no longer need a separate data type for every endpoint.
  • Data types whose accessor functions share names (because I want the schema for them to share names) no longer need to be in separate modules.

What do you think?

First of all, I'm not that familiar with digestive-functors, so I don't know most of those terms you are using. I think I get the gist of what you are suggesting, please let me know if we seem to be talking about the same thing :)

We haven't considered digestive-functors, we use json-schema for similar purposes already. json-schema can also validate input, but it's less expressive than what digestive-functors is. Rest also doesn't use the validation mechanism at present.

One of my wishes for rest would be to allow some form of preprocessing step before values end up in handlers. With json-schema i imagined this as a different input dictionary that would first run a validation, possibly throwing an error. Since you have a json-schema instance for each type you might then be able to do something like

handler = mkInputHandler (jsonSchemaValidationI) f
  where
    handler :: MyInput -> ExceptT (Reason e) x

where jsonSchemaI has the same signature as jsonI.

The result of running the handler with validation would be something like ExceptT (Reason (Either SchemaError e)) x, to handle the case where the schema validation fails.

We could implement this already for json-schema since jsonI already requires that constraint, but to extend it with validations from other libraries we should implement #20, possibly with the addition to allow dictionaries to pipe data through each other, think schemaI :: ByteString -> Maybe Value and jsonI :: Value -> Maybe MyType.

Some other notes:

Different forms yielding the same data type, so I no longer need a separate data type for every endpoint.

Why can't you use the same data type in different end points?

At the moment, the best way I can see of using them is with stringI

Could you for now use jsonI instead to get an aeson Value and pass that to digestive-functors instead? And possibly you could use something like a phantom type/newtype over Value to still provide a json-schema instance for documentation.

Yes, I think we're exactly on the same page regarding validation! What I'd like to have is exactly the separation between validator and handler that you describe (so that ideally only the "business logic" stays in the handler).

I guess what I'd be happy with is some way to hook into the input formats, e.g. with a similar effect as placing my own MoritzI constructor for Input next toJsonI and then custom validation for that. #20 along with piping data through the dictionaries also sounds promising.

Re your other comments:

Why can't you use the same data type in different end points?

You are totally right, I can indeed just do that. :)

Could you for now use jsonI instead to get an aeson Value and pass that to digestive-functors instead?

Yes, I could do that (and it's probably better than just using a string), but the problem still is that a schema instance for a generic aeson Value doesn't make much sense. Then users still won't know the schema of my particular data structure that the handler takes.

Anyway, thanks for the swift reply!

I'll close this in favor of #20.