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.