Closed stalep closed 4 months ago
Hi @stalep, I'm gearing up to try to produce this. (I'm working my way through the setup instructions -- it's been an odyssey -- I'm up to trying to run the Horreum tests, but they are failing due to a lack of Docker...so that's the next stumbling block for me to remove.)
If you want to assign this issue to me, feel free.
Hi @webbnh, we've noticed an issue with the openapi-python generator in the latest version of Horreum. I'm looking at it and we plan to have it fixed in the upcoming version. I'll ping you when it's fixed in master!
They openapi-python generator now work with master @webbnh
Hi all,
Contrary to all appearances, I am trying to make headway on this stuff. 🥴
I was able to generate the API client, but the tool has some complaints, and so it doesn't generate code for all the APIs:
$ openapi-python-client generate --path openapi.yaml
Generating horreum-rest-api-client
Warning(s) encountered while generating. Client was generated, but some pieces may be missing
WARNING parsing POST /api/run/{id}/description within run. Endpoint will not be generated.
Unsupported content type text/plain
WARNING parsing POST /api/run/{id}/schema within run. Endpoint will not be generated.
Unsupported content type text/plain
I got confirmation from the tool's maintainer: it indeed does not currently support text/plain
content for request bodies.
We have various options. The simplest might be to tweak the YAML for those two APIs:
/api/run/{id}/description:
post:
[...]
requestBody:
content:
text/plain:
schema:
type: string
[...]
and replace text/plain
with application/octet-stream
, which is a supported type. I don't think that doing so will have any negative effects, and it allows the tool to generate those two APIs successfully.
I'm not blocked by this, but let me know if you want me to post a PR with this change.
Hi @webbnh we have a pr open that fixes the python generation. Hoping to have it merged by tomorrow!
Hi @stalep, what was the PR, and has it been merged, yet? (Was it https://github.com/Hyperfoil/Horreum/pull/1292?)
The reason I ask is that, at JoeT's prompting, I've found a bug in the openapi.yaml
file: the /components/schemas/ProtectedTimeType
schema says that the start
field is a date-time
string (like 2019-09-26T07:58:30.996+0200
), but the API response contains 'start': 1697154107508
. The stop
field looks to have the same issue.
Do you want me to create a PR?
Here's the change:
diff --git a/docs/site/content/en/openapi/openapi.yaml b/docs/site/content/en/openapi/openapi.yaml
index 95085210..ecac9851 100644
--- a/docs/site/content/en/openapi/openapi.yaml
+++ b/docs/site/content/en/openapi/openapi.yaml
@@ -3240,15 +3240,15 @@ components:
type: string
example: performance-team
start:
- format: date-time
+ format: int64
description: Run Start timestamp
- type: string
- example: 2019-09-26T07:58:30.996+0200
+ type: integer
+ example: 1698013206000
stop:
- format: date-time
+ format: int64
description: Run Stop timestamp
- type: string
- example: 2019-09-26T07:58:30.996+0200
+ type: integer
+ example: 1698013206000
ProtectedType:
required:
- access
@webbnh openapi.yaml
is generated from code annotations on api classes so unfortunately changes to the file will get replaced each time the project compiles.
I am also working on the compatibility with openapi-python-client
. I wish they would add support for text/plain
content type :)
https://github.com/openapi-generators/openapi-python-client/discussions/821
The example
on ProtectedTimeType
is something we can easily change but I suspect the example
is based on the data format for adding data into Horreum. Do you mind sharing the endpoint you queried when you got the unexpected start and stop? (or at least the /api/...
portion of the endpoint)
I opened an issue in the project that creates the openapi.yaml https://github.com/Hyperfoil/Horreum/issues/1336
openapi.yaml
is generated from code annotations on api classes so unfortunately changes to the file will get replaced each time the project compiles.
@willr3, thanks for mentioning, that. BTW, what do you mean by "each time the project compiles"?...it's a little weird to have a build output checked into the repository....
I am also working on the compatibility with
openapi-python-client
.
Ah, good...so I'm not alone! 😁
The
example
onProtectedTimeType
is something we can easily change but I suspect theexample
is based on the data format for adding data into Horreum. Do you mind sharing the endpoint you queried when you got the unexpected start and stop? (or at least the/api/...
portion of the endpoint)
The field at issue is either format
or type
...I just changed example
to keep the three fields consistent.
The first API I hit the problem in is /api/dataset/list/{testId}
, but there are others which use the ProtectedTimeType
, as well.
I opened a PR that fix the annotations and should generate an openapi.yaml
that properly describes start
and stop
as Long
.
https://github.com/Hyperfoil/Horreum/pull/1337
I will be away for a week but we have a PR open to address the other type issues with openapi-python-client
https://github.com/Hyperfoil/Horreum/pull/1335
hopefully during that week we get some news on text/plain
https://github.com/openapi-generators/openapi-python-client/discussions/821
I opened a PR that fix the annotations and should generate an
openapi.yaml
that properly describesstart
andstop
asLong
[and] we have a PR open to address the other type issues withopenapi-python-client
💪
hopefully during that week we get some news on
text/plain
openapi-generators/openapi-python-client#821
I admire your optimism. (Did you see https://github.com/openapi-generators/openapi-python-client/issues/699?)
my optimism is waning given: 699
How are you testing the python client? Do you start a new project and import the generated horreum-rest-api-client
folder? If you could give an example of what that looks like in python (like you would give to a kid who is just learning python) I would like to start testing the generated client when I get back in a week.
I went with the simplistic approach for my first pass:
openapi.yaml
file into itopenapi-python-client generate --path openapi.yaml
cd
'd to the resulting horreum-rest-api-client
directorydemo.py
script, there (so that the Python path works out nicely by default)x
bit set on the script file), I just run ./demo.py
My current script is just endeavoring to try out all of the APIs that I can. It doesn't do much that is actually useful, other than to call them and report the result. So far, I'm only trying the GET
methods and only the methods which don't require authentication. So, it's more of a functional test than a PoC at this point. Once I've gotten everything shaken down, I'll move on to create another script which is more useful. But, as a demonstration of what one might do with the client, it's a fair start.
In "real" code, you presumably wouldn't use my api_call()
wrapper, but it handles the repetitive boiler plate for me. The import
magic makes the resulting code more expressive:
with u_client as client:
response = version(client=client)
response = get_dataset(client=client, id=124811)
// etc.
Thank you for the code. I was able to get more of it running with the 'openapi.yaml' changes in my PR than with master so we are taking steps in the right direction
You asked earlier what I mean about generating the openapi.yaml. The horreum-api module of the Horreum project has code annotations on the service endpoints and the data classes. Part of the compilation creates a new openapi.yaml and places it in the docs module. The same compilation then uses the openapi.yaml to generate the Typescript client for the web interface module in Horreum. We have caught breaking changes to data types or endpoint paths with this method but nothing is perfect.
Thank you for the code. I was able to get more of it running with the 'openapi.yaml' changes in my PR than with master so we are taking steps in the right direction
Excellent. I've been accumulating fixes here, although I'm a few commits behind master
, now.
You asked earlier what I mean about generating the openapi.yaml. The horreum-api module of the Horreum project has code annotations on the service endpoints and the data classes. Part of the compilation creates a new openapi.yaml and places it in the docs module. The same compilation then uses the openapi.yaml to generate the Typescript client for the web interface module in Horreum. We have caught breaking changes to data types or endpoint paths with this method but nothing is perfect.
All of that makes good sense, except for the part where the YAML file is supposed to be committed to the repo before the build which is supposed to create it. 😆
I see that John has made some changes to the Maven configuration which look relevant (unfortunately, I don't speak Maven), but, really, the openapi.yaml
file should be a build output (like a .jar
file or documentation or anything else generated by the build), and it should be handled similarly, not like a source file pulled from the repo: then the interface spec can never be out of sync with the interface, because they are built from the same source at the same time.
I've been accumulating fixes here, although I'm a few commits behind
master
, now.
I've resync'd with master
, and it looks like you guys have caught up to me, except for the text/plain
thing. 😉
And, yes, everything that I have in the demo script so far seems to work. 🎉
All of that makes good sense, except for the part where the YAML file is supposed to be committed to the repo before the build which is supposed to create it. 😆
We host the src code and the documentation for the website (https://horreum.hyperfoil.io/) in the same repo. This way we can ensure that PRs with functional changes contain all user documentation and the website is always up-to-date with the latest stable branch of Horrum.
There is a bit of an anomaly with this set-up, in that, for build artefacts that are published on the website (which is only openapi.yaml
currently) , we have to ensure that the changes to openapi.yaml are checked in with the PR.
The yaml is generated as part of the build, and after a change has been made and tested locally the src code change and the openapi.yaml changes should be checked in the same PR.
I see that John has made some changes to the Maven configuration which look relevant (unfortunately, I don't speak Maven), but, really, the
openapi.yaml
file should be a build output (like a.jar
file or documentation or anything else generated by the build), and it should be handled similarly, not like a source file pulled from the repo: then the interface spec can never be out of sync with the interface, because they are built from the same source at the same time.
There was an issue with maven not running certain phases given some conditions, the recent changes rectify this. the openapi.yaml
is a build output, and is used to automatically build the Tyepscript client, but atm we do not automatically build python/go clients (we have talked about it but have not opened an issue).
The main issue I see with treating openapi.yaml
as a build artefact is we would have to go through a full Horreum release to consume it in downstream projects, but when we are developing clients (and changing the api spec) we do not want a published version for pple to consume, but we want to consume from the master branch which contains ongoing fixes. We also do not want to publish an unstable openapi.yaml
on the website, we wish to keep that in sync with the latest stable Horreum release
Thanks, @johnaohara. While you were typing that in here, I was preaching over here. 😀
Even so, it might be good if you had a test which verified that the openapi.yaml
file produced by the build matched the one from the docs
tree in the source repo.
Even so, it might be good if you had a test which verified that the
openapi.yaml
file produced by the build matched the one from thedocs
tree in the source repo.
I think that is a good idea :) atm it is a manual check.
The anomaly exists because we have taken a shortcut in hosting the website artefacts in the same repo as the src code. we should update the the website build to pull in an openapi.yaml that has been published somewhere as part of a release.
We have another concern in that for developers developing against the current master branch we probably should publish the openapi.yaml somewhere without having to expect them to build the project from a snapshot. i.e. if you are a python dev, working on a python client, we wouldn't expect you to install the entire java toolchain just to get the current SNAPSHOT openapi.yaml
. We have chosen to publish it in the master branch, although we could update the build process to publish it is a SNAPSHOT
openapi.yaml on the website or in github
Hi @webbnh, I just ran the openapi python gen client from master and it ran without any warnings/errors.
We now have a pr (https://github.com/Hyperfoil/Horreum/pull/1360) that will generate python and go code as part of the Horreum build.
Unfortunately, almost all of the responses fail to parse. I don't know whether that's a problem in what I'm doing, or a problem in the openapi.yaml
file, or in the generated code, or something else. I'll try to work on this some more tomorrow.
I want to create an example python project to run through the api with a test DB when I get back from vacation. I mostly use python for Jupiter notebooks. @webbnh is there a python unit test library you would recommend for creating the tests for the python client?
is there a python unit test library
@willr3, I'm accustomed to using PyTest and to running it under Tox.
However, it's not obvious to me that you want to write unit tests for this. (It could be a terminology problem, but unit tests generally operate by isolating certain portions of the code-under-test (aka CUT) from their dependencies, by replacing the dependencies with fake or mock implementations of them.) What I think you want to test is integration -- that the generated client actually works with the real API implementation -- and for that you'll need functional tests.
This is not to say that PyTest cannot be used to implement functional testing (it can, but its forte is unit testing). But, I just want to make sure that your focus is useful and that your choice of words doesn't confuse things. 🙂
Coming out of PerfConf I am excited to see the fruit of this investigation!
In chatting with @johnaohara in RDU I wanted to put a comment here about shipping a python client package versus expecting users to generate the client from OpenAPI. It is my understanding with chatting with @johnaohara the expectation is there will be a python client shipped with each version of horreum -- there isn't an expectation the user builds the client from the OpenAPI spec.
@jtaleric, that is my understanding, as well: the Horreum build now produces a Python client. This needs to be packaged as a Python "package" and made available for consumers' use. So, there are two work items (beyond making sure it all works, which is what I'm currently exploring, albeit at a glacial pace): get the Horreum build to produce the package file(s) [I'm sure this is well-trodden ground, but I myself haven't had to tread it, yet], and devise a policy and mechanism for publishing them [doing "releases" is reasonably straightforward; however, making branch builds, etc. available might require more "stuff"].
@jtaleric, that is my understanding, as well: the Horreum build now produces a Python client.
ack. I know there has been some discussions with shipping a client package vs users building a client, I just wanted to make sure everyone is on the same page, and it sounds like we are so great! 😄
Presumably this should be assigned to @lampajr for closure. 🙂
Presumably this should be assigned to @lampajr for closure. 🙂
Sorry I missed this comment :disappointed:
Closing this issue :rocket:
Using https://horreum.hyperfoil.io/openapi/ it should be possible to create a Python client connecting to Horreum. There might be obstacles we do not know about, so a PoC would be welcome To get started: Download the API: