-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: A tool that helps enforce consistency & rigor in responses #419
Comments
Why not utilize Swagger / JSON Schema? |
One of the things that originally drew me to Taffy was the absence of anything trying to solve my non-API problems for me. Why is this Taffy's problem to solve? Can't |
I'm not sure that solves the problem of multiple resources that return the same data types (e.g. customers, above) with different formatting. If I'm wrong, please elaborate.
I did consider making this a separate project, actually. And maybe it still will be. But since it's inspired by Taffy usage, I figured we'd start here. The problem I'm attempting to solve is that it's too easy for developers to be inconsistent with their former decisions. I don't want to have to track down every time I previously returned customer data and make sure I use the same object property names (and CaSe)... But I might need to add a new customer resource a year or more after the last time I worked on them. And the DB column names may not always exactly match what we want to be in the response. And maybe for that reason ☝🏻 it should stay as part of Taffy. The only time it really matters that object key names are consistent is when you're pushing data outside the edges of your app (e.g. an API). Maybe it would be useful for generating files to export, too, but otherwise, I don't see any utility beyond API's. Am I wrong? So, instead, if my past self had written a Likewise, if my changes also involve adding a new column to the DB, I can add that to the type and the response would be consistent any time the developer used it. This also enables generation of a data dictionary (which is maybe why @pfreitag suggested swagger/json-schema?), but my experiences with those things has been universally negative. Firstly, they're so complex and bloated that any customer I try to hand it to and say, "here, my responses are defined by this document" is going to take 1 look at it and know instantly that they'll never look at it again. |
In JSON Schema / Swagger / OpenAPI you can define a type and then say the endpoint returns a type. Swagger can actually generate nice HTML docs that you can share rather than the JSON file (example: https://petstore.swagger.io/), and you can use it to validate server side as well. Here's an example of referencing a definition
Maybe this isn't the right direction for what you are trying to accomplish, but I just wanted to point it out incase it is useful. |
@pfreitag thanks for sharing. That might be useful as an output from what I'm thinking of, but what you provided there doesn't enforce the consistency in our code. We'd still have to carefully check to make sure we're outputting responses that match the contract. What I have in mind is (hopefully!) something terse that not only would generate that sort of useful output, but also would take care of getting from "I've selected some columns from a table" to "Here's a JSON response that's guaranteed to match the contract". |
I've created a new branch named typed-responses for working on this. In it, I've made some (👷🏻 very rough! 🚧 ) changes and additions to illustrate what I have in mind, and added an example showcasing what the changes are capable of right now. I'll highlight a few things here:
Taffy/examples/api_TypedResponses/types/Customer.cfc Lines 1 to 9 in 6a39402
There's still a lot to do before this would be ready, but hopefully this illustrates one of the goals. Another goal that might be within sight now is the automatic generation of something that describes the responses, whether that's swagger json or json-schema, or something custom. |
I've started to dig into JSON Schema and I think there's a possibility we should support it as a way to define types. That said, is there a good json schema validator or something like that we can make use of? I'm even just a touch leery of using a Java library, because I don't want to put that dependency on our users. Trying to be as objective as possible, on one hand: JSON Schema is a standard and a reasonable one that could also save us the trouble of generating something like its output if we are getting the developers to provide it. (E.g. the generated data dictionary is the collection of json schemas from each type) But on the other hand, JSON Schema is an evolving spec and without a library to abstract that away, I'm afraid we'll get sucked into maintaining tooling around different drafts of JSON Schema. From what I see so far, there's no obvious answer. Please tell me there's a library out there to help with this? |
@atuttle that is certainly a downside to json schema, there is no builtin support for it in CFML so you'd have to use a Java Library, or roll your own implementation in CFML. |
I suppose we can always list specific draft versions that we support, and if someone desperately needs support for a newer draft they can contribute it. :) |
A problem I've seen consistently throughout my time using Taffy and helping others is that we all —myself included— struggle to manually make our API responses consistent with themselves. E.g.
/customers/1
and/customers
both return customer data, but one might usefirstName
while the other usesfirst_name
, because CFML's weak typing gives us plenty of opportunities to do the wrong thing.I do not want to create something that feels like an ORM.
But it would be really nice to have something like this:
👆🏻This assumes some sort of "Customer" type already exists, and understands how to pull the appropriate data from the query.
That's about as far as I've been able to develop this thought in my head so far. I will have the availability to spend time on this effort at work in the coming months, so now is a great time to get your ideas and feedback in so that they can be considered for the effort.
The proposal above should also work reasonably well for cases where you've got nested types.
We may not need the
fields
argument. Each type should be aware of all possible fields it would contain, and capable of loading them from queries by column name. If a column is missing from the query, it should be excluded from the result object.The returned objects would be simple structs, with the properties defined by the types. The type class would enforce key name CaSe sEnSiTiViTy. So if you don't want a key in the result, don't select it in the query. I guess there might be a use case where you'll want to select more columns than you want in the result, so we'll make the
fields
argument optional.You might have special handling you want to do for certain columns. E.g. if the column stores json data and you want it represented as real objects in the result, your implementation might look like this:
Given that you can specify custom functionality like this at the type-class level, do we need to leave leeway for you to add/override column type handlers at the resource-implementation level?
In addition to enforcing consistency in our outputs, other benefits of defining your types separately would include:
This is where you come in
The text was updated successfully, but these errors were encountered: