guardrail-dev / guardrail

Principled code generation from OpenAPI specifications
https://guardrail.dev
MIT License
522 stars 132 forks source link

Permit `type: object` anywhere a schema body is possible #76

Open blast-hardcheese opened 6 years ago

blast-hardcheese commented 6 years ago

Currently, only top-level definitions are turned into case classes. This provides a serious limitation to consuming existent OpenAPI specifications that represent APIs as heavily nested structures.

One possibility is to generate class names similar to the Scala compiler itself, suffixing the parent class with some disambiguating identifier. Additionally, as mentioned in #43, introducing an x-scala- extension that permits naming these in-line type: object definitions would significantly improve ergonomics of generated structures. A middle-ground where both approaches are taken is acceptable, though I expect non-trivial structures would end up with names for all children.

Alternately, generating successively nested case classes, defined inside the parent companion object would work for definitions, and a similar solution may be possible with direct parameters as well.

blast-hardcheese commented 5 years ago

@sbrunk So, my thoughts around this are as follows:

1) Make Target include a StateT where the state is a case class with a nextObjectLiteral: Int, representing the De Bruijn index of literals we've walked. 2) Recursively walk sub-schemas in ProtocolGenerator to ensure all object literals are created. You'll have to come up with imaginary class names based on the index in the StateT that we created 3) Structurally deduplicate object literals, selecting the first structure with an identical definition 3a. ⚠️ Unsure exactly where this needs to get done, but it's something that needs to get done. The structure we use will additionally be useful for deduplicating across different clients and servers, as currently identical objects end up with completely different classes, requiring either fancy conversions or unnecessary allocations 4) Based on the deduplication heuristic in point 3, do a lookup to find either the real or synthetic class name given the structure defined in propMeta

This is a significant amount of work, though something that's really starting to come to a head. If there's any part of this that you're interested in doing, please feel free -- I likely won't be able to start doing work in this direction for the next month or so.

sbrunk commented 5 years ago

@blast-hardcheese thanks for these pointers! I'll try to wrap my head around this in order to get a better understanding of it (probably not before Scala Days though).

blast-hardcheese commented 5 years ago

@sbrunk Thank you for your consideration and interest on this front! This would be a tremendous benefit for user experience!