-
Notifications
You must be signed in to change notification settings - Fork 73
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
[POC] Adds a "dynamic" module to dynamically load services from smithy models #17
Conversation
This relies on mutability + suspension to build a map of schemas that work against dynamic data, backing product types with arrays. The goal is notably to get to a state where services could be proxied dynamically, whether for actual proxyfication purposes, or to create CLIs that do not need recompilation, or create UIs/playgrounds dynamically.
modules/dynamic/src/smithy4s/dynamic/DynamicModelCompiler.scala
Outdated
Show resolved
Hide resolved
Don't trust the CI, the new module is not currently wired (nor do I intend to do it right away) |
I can now confirm this works on JS :) |
… into dynamic-schemas
@Baccata,
|
pureTest( | ||
"Extract field names from all structures in a service's endpoints" | ||
) { | ||
val svc = dynamic.Compiler.compile(expected).allServices.head |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using expected
as a base as it's already been verified as the correct output of model dump in the test above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test fails because the smithy prelude is not dumped in the json representation. We would prepopulate the visitor by running it on a handcrafted model containing just the primitives
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense. I'll let you know if I get to working on it first :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried that, turns out the floatShape
visitor was not doing anything in particular - still the case for other cases. E.g. when I tried to compile PizzaSpec's model, it's doesn't recognize Food
(a union). I can look at this again after the weekend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried that, turns out the floatShape visitor was not doing anything in particular - still the case for other cases. E.g. when I tried to compile PizzaSpec's model, it's doesn't recognize Food (a union). I can look at this again after the weekend.
Yeah, I had left a fair amount there as TODOs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of it should be implemented in eb05278
also, can we include this in the root project? It makes local publishing much easier. |
@kubukoz sure yeah, go for it :) |
Added new spec, trying to dump the model of PizzaSpec to find more issues - currently it's failing because it doesn't recognize the |
* | ||
* Created for testing purposes. | ||
*/ | ||
object JsonIOProtocol { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kubukoz, I've created this to facilitate testing. Given a service given by the dynamic model, we can create a "proxy" function, that round trips a Document => IO[Document]
kleisli through the fromJsonIO
and toJsonIO
functions.
Then, if we take that proxy and create a corresponding statically generated stub from it, in theory the data should go through the proxy back and forth, in an untampered fashion.
We can add some middleware to intercept and store the incoming and outgoing json in a CE-Ref, and either perform assertions on the json itself, or use it for logging purposes when we see that the data has not gone through the dynamic proxy as expected.
modules/dynamic/test/src-jvm/smithy4s/dynamic/model/JsonIOProtocol.scala
Outdated
Show resolved
Hide resolved
Co-authored-by: Olivier Mélois <baccata64@gmail.com>
… into dynamic-schemas
import schematic.Field | ||
import schematic.Alt | ||
|
||
object DefaultSchematic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems useful for working with schemas, maybe it could be exposed to the users in some module closer to core?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about, but decided against it because of a lack for a better motivation, at this time. When the time arise, we'll move it
Sooo this is currently working in all capacity that I'd need it to, is there anything major that needs to happen before we merge? |
@kubukoz sorry I had missed that. I need to do another pass, clean some things up (make most of them private) and move stuff to an |
@kubukoz I've cleaned things up, renamed some things, etc. Time for some bikeshedding :) |
… smithy models (#17) Adds a dynamic module to dynamically load existential `Service` and `Schema` instances from the json-representation of smithy models. The construct exposed for doing this is called `DynamicSchemaIndex` Because the `Service` and `Schema` interface do not make any constraint with regards to how datatypes are stored in memory, it is possible to reify Schemas that work against generic representations: * products are backed by Array[Any] * sums are backed by (Int, Any) tuples Because of this, we can load `Service` instances in an existential fashion, which allows to connect front-ends (service stubs) and back-ends (client stubs) from separate protocols without needing any code generation. An example use-case for it is the derivation of fully dynamic CLIs that read a spec file to expose the commands, and invoke http apis via the compiled clients. Another use-case could be dynamic http mocks that can be hot-reloaded. Co-authored-by: Olivier Mélois <baccata64@gmail.com> Co-authored-by: Jakub Kozłowski <kubukoz@gmail.com>
This relies on a one-pass + suspension to build a map of schemas that work against dynamic data structures, backing product types with
Array[Any]
, and union-types with(Int, Any)
The goal is notably to get to a state where services could be proxied dynamically, whether for actual proxyfication purposes, or to create CLIs that do not need recompilation, or create UIs/playgrounds dynamically.