-
Notifications
You must be signed in to change notification settings - Fork 2
Description
I realized some days ago that we have the OpenAPI specification for the API at:
https://gateway.internxt.com/drive/api-json
(see also https://gateway.internxt.com/drive/)
When I tried running it through oapi-codegen I got a lot of errors related to invalid formats like "bigint" and {placeholders} in paths. I gave the information to chatgpt and got back a script that adds the missing parameters to the paths and replaces the invalid formats.
import json
import re
import sys
from copy import deepcopy
VALID_METHODS = {"get", "post", "put", "patch", "delete", "options", "head", "trace"}
def ensure_path_params(spec):
"""Ensure that all {placeholders} in path strings are declared in parameters."""
for path, path_item in spec.get("paths", {}).items():
placeholders = re.findall(r"\{([^}]+)\}", path)
if not placeholders:
continue
# Path-level parameters
path_params = path_item.get("parameters", [])
declared = {p["name"] for p in path_params if p.get("in") == "path"}
for ph in placeholders:
if ph not in declared:
path_params.append({
"name": ph,
"in": "path",
"required": True,
"schema": {"type": "string"}
})
if path_params:
path_item["parameters"] = path_params
# Operation-level parameters
for method, operation in path_item.items():
if method.lower() not in VALID_METHODS:
continue
op_params = operation.get("parameters", [])
declared_op = {p["name"] for p in op_params if p.get("in") == "path"}
for ph in placeholders:
if ph not in declared_op:
op_params.append({
"name": ph,
"in": "path",
"required": True,
"schema": {"type": "string"}
})
if op_params:
operation["parameters"] = op_params
return spec
def fix_invalid_formats(schema):
"""Recursively walk the schema and fix invalid formats like bigint."""
if isinstance(schema, dict):
if schema.get("format") == "bigint":
# If it's "integer" or "number", convert to int64
schema["type"] = "integer"
schema["format"] = "int64"
for v in schema.values():
fix_invalid_formats(v)
elif isinstance(schema, list):
for item in schema:
fix_invalid_formats(item)
def main():
if len(sys.argv) != 3:
print("Usage: python fix_openapi.py input.json output.json")
sys.exit(1)
infile, outfile = sys.argv[1], sys.argv[2]
with open(infile) as f:
spec = json.load(f)
fixed = ensure_path_params(deepcopy(spec))
fix_invalid_formats(fixed)
with open(outfile, "w") as f:
json.dump(fixed, f, indent=2)
print(f"✅ Fixed spec written to {outfile}")
if __name__ == "__main__":
main()After running the OpenAPI json through this script:
python fix-spec.py openapi.json openapi-fixed.jsonoapi-codegen can create a go client like so:
go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
go tool oapi-codegen -generate "client,types,models" openapi-fixed.json > oapi-codegen/client.gen.goI wish I had known this earlier. I think generating the client like this and adding a custom AuthTransport with a roundtripper that sets relevant headers will be easier to maintain. oapi-codegen creates all the structs and funcs needed and also does all the marshalling and unmarshalling for us. The AuthTransport can look something like this:
type AuthTransport struct {
token string
rt http.RoundTripper
}
func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
clone := req.Clone(req.Context())
clone.Header.Set("Authorization", "Bearer " + t.token)
return t.rt.RoundTrip(clone)
}And the client can then be created like this:
c, err := openapi.NewClientWithResponses(APIURL, openapi.WithHTTPClient(&http.Client{
Transport: &AuthTransport{
token: newToken,
rt: http.DefaultTransport,
},
}),
)We would still need all the encryption/decryption and upload/download code though. What do you think about using oapen-codegen for this project?
I may take a break from coding for a while, but I'm watching this repo and will try to help with issues if they pop up.