in `http4k-by-example`, the contract module genera...
# http4k
n
in
http4k-by-example
, the contract module generates these random
object927961565
objects. is there a way to name those manually?
I found the optional “definitionId” field to fix this, although now I have another issu:
d
Unfortunately you can only name the top level objects. This is because under the covers the data class is turned into JSON and then the schema is generated from there. In order to overcome this we would have to rewrite the Open API renderer and reimplement HttpMessageMeta.
@Tom Ellis was looking at something like this a week or so ago for his project, although not sure if he got anywhere with it.
t
yeah we did - it worked well enough for us. we extended HttpMessageMeta to carry the example object through to rendering time, then during render used reflection and recursion to walk the example object creating the json schema in much the same way the current one does.
n
Oh, do you have a sample of doing that?
I have fully converted a service at work to HTTP4K and there a only a few gaps I need to fill, which I could do if I could tweak the resulting JSON before it’s rendered.
Or even just have the renderer do reflection on each of the JSON types and check its class name and use that instead of
object2178172
d
is it really that important to have nice names in the swagger docs? Not sure I entirely get the point TBH.
n
We share our Swagger docs internally to other devs as part of our API Marketplace strategy. There’s a requirement that they’re all human readable. In this case I can just download the swagger.json, modify it, and host it as a static file on a different route
t
@dave Yeah our use case is similar in that we actually share the swagger docs with clients and also generate API libraries in other languages using them. Having the correct names of child model objects is important to that. @Nezteb - will extract an example and post it
n
oh man, that’d be awesome. what i ended up doing in the meantime was serving a
/auto-swagger.json
and a regular static
/swagger.json
, which has some manual manipulations in it.
d
I'm interested in maybe converting to the reflection approach, but aren't sure how much work it would be, and also would like to keep the API nice. Any example implementations would be great
n
here’s another (ugly) thing i was experimenting with. get the generated json, deserialize it into a
swagger-parser
type called
Swagger
, manipulate it, serialize it back to JSON (or YAML if they add
?yaml
to their GET operation), and return it
t
This is pretty much a straight copy of the existing openapi v2 renderer, except if you add:
receiving(requestExampleMeta('MyObject', MyLens, MyExample))
when building your contract meta you get a HttpMessageWithExampleMeta which, when doing
asSchema
will call
ObjectToJsonSchema
And it’s this guy that does the reflection madness. If we were to go back or you were going to do something with OpenApi v3 - it might make more sense to use something like https://github.com/mbknor/mbknor-jackson-jsonSchema to generate an actual v4 json schema and plumb that into the openapi definition though. thoughts?
d
Thanks @Tom Ellis - I'll take a look. With regards to the OpenApi - I'm hesitant to bind anything totally to Jackson - what we could do instead is provide a default Schema Renderer (using normal Json), and then have Jackson implement it's own one which is imported from
http4k-jackson
. I didn't know about
jackson-module-jsonSchema
so that might come in ultra-handy. Going to stay well away from the Scala one though... 🙂
t
haha fair enough! 😉
Copy code
v3.142.0
[http4k-contract] Both OpenApi v2 and v3 are now supported, including automatic schema generation. Some classes for OpenApi2 have moved to a new package. See module docs for details. Optionally include http4k-format-jackson to get JSON schema models based on JVM objects.
[http4k-format-jackson] Added reflective JSON schema creator, to be used for generating named models from JVM objects.
😍 1
d
@Tom Ellis yeah - there is one small bug with the OpenApiv3 stuff which I'm 50% through fixing (I was going to do it before posting an update here) - it's a bit annoying, but schemas which return raw lists of objects blow up during the schema generation phase. It's here: https://github.com/http4k/http4k/issues/239
Copy code
v3.143.0
[http4k-contract] Fix #239 - OpenApi v3 schemas for raw lists blow up when rendering.
[all] Update various dependencies.

v3.142.0
[http4k-contract] Both OpenApi v2 and v3 are now supported, including automatic schema generation. Some classes for OpenApi2 have moved to a new package. See module docs for details. For OpenApi v3, optionally include http4k-format-jackson to get JSON schema models based on JVM objects.
[http4k-format-jackson] Added reflective JSON schema creator, to be used for generating named models from JVM objects.
hmm - there still seems to be a problem with the generated API for posting content. Some kind of problem in the Swagger UI making it not work.. Grrr. Raised as: https://github.com/http4k/http4k/issues/243
Fixed it - turns out that the Swagger UI is really picky about missing JSON values vs nulls:
Copy code
v3.143.1
[http4k-core] - Replace RequestContexts with reference to Store. H/T @amcghie
[http4k-contract] - Added some missing deprecations.
[http4k-contract] - Fix #243 - Nulls not allowed in OpenApi V3 JSON models.
👍 1
n
Awwwwww yeah. 😎 Yeah, Swagger UI is wonky. It also renders map types poorly.
[http4k-format-jackson] Added reflective JSON schema creator, to be used for generating named models from JVM objects.
Is there an example of this anywhere? I’d love to check that out
d
the docs for the contract module should give you an example. it's v easy as long as you have both jackson and contract modules imported to gradle. check out the bottom of: https://www.http4k.org/guide/modules/contracts/
n
ahhh, i was looking at the module docs for http4k-format-jackson, not contracts. thank you!
t
just having a go at generating a v3 schema using the OpenApiv3, and am running into a couple of issues compared to what i had above: • it seems the v3 spec doesn’t allow an ‘id’ field in object schemas • required is an array of required fields on the type itself • the current implementation doesn’t seem to recurse into objects. in our example, we have an envelope with a generic data field - our examples have this set so in our reflective generator it goes and generates, but with the OpenApiv3 renderer it just spits out that the data field is a string type. notably, in the example in the routes the paths section, the full example is present
key for us is to be able to use the openapi generator to generate clients, so it may be a good idea to add a couple of tests to try generation from the output of the renderer?
d
@Tom Ellis The format did change a bit - we're obviously now using the format spat out from the Jackson generator which evidently isn't. TBH, the primary focus was to get the content rendering in the UI - which it appears to do. WRT the changes you mentioned: - id - this is present in the Jackson output, but I imagine shouldn't really cause a problem (extra fields in JSON generally don't) - required - whilst this renders in the UI, I can see that it's not the official spec. - there is recursion into objects supported - we test for that in the tests (https://github.com/http4k/http4k/blob/master/http4k-contract/src/test/resources/org/http4k/contract/openapi/v3/OpenApi3AutoTest.renders%20as%20expected.approved), but as the generic type is erased at compile time, I suspect the jackson generator is spitting out a generic "any" type instead - it uses the class and not the instance that you provide to generate the schema. Hopefully you'll be able to rework your object to use the new JsonSchemaCreator interface to generate the schema, which means that you can reuse most of the logic which is currently in the new OpenApi3 class for rendering the overall structure. If you do and fancy re-posting/PRing it then maybe we can look at including it as an alternative. There is obviously a gap between what we will be able to achieve because we don't have ALL of the OpenApi metadata to play with, but we can definitely look at iterating on what we've got now.
t
Yeah fair enough, will try to rework our stuff so we can upgrade to keep getting http4k goodness. 😄 Re id/required - I only mention it because the openapi client generator blows up trying to generate a client from the spec that OpenApiv3 generates. Super common use case beyond just using the swagger ui, something you may want to support. Will try and find some time to see if we can contribute a pr for our method. We're also looking at other ways around annotating model classes so we can render more metadata, e.g. field descriptions
We'd also like to try adding in the bearer auth definition
d
See what you mean - looks like the generator is as picky by default than the UI - just in totally different ways!!! I've started a branch for adding some generator tests and made a couple of tweaks in master to make it work a little nicer (Inc generate operationIds by default not blowing up on the requestBody being there ). You can turn off the validation as an option to the generator, which will get a bit further. By the looks of it, we will probably just have to bin the Jackson schema generator as it's not usable for V3 (although we might be able to get it working for v2 of we can be bothered), then fall back on the reflection based approach.
n
ah, i didn’t fully read dave’s earlier response. because it’s using jackson and not reflection, it can’t see non-instantiated types
d
I've got a cunning plan to make this much better. Bear with me. 🙃
👍 1
(hope it pans out now!) #pressure 😉
😂 1
n
for now i’ve got what i need. i created a dummy route that returns any objects i don’t need. and the description of the route is “do not use this”. it’s ugly, but this is an internal API anyway 😄