Search code examples
javaclientopenapiopenapi-generator-maven-plugin

Client-side file download with OpenAPI Generator-Plugin


I'm trying to implement a REST API using OpenAPI (v3.0.3) and the openapi-generator-maven-plugin (v6.6.0). I want the plugin to generate both server and client from the specification.

I'm trying to implement a method to download a (ZIP) file, which I imagine would be a rather common operation, but I cannot get it to work on the client side. And unfortunately, my search didn't turn up any useful hints, so I'm asking a new question. In the spec, I have written:

  /download:
    get:
      operationId: download
      responses:
        "200":
          description: Success
          content:
            application/zip:
              schema:
                type: string
                format: binary

The server side (generator spring) is generated as expected and returns a ResponseEntity of type "Resource" (I have implemented the method to return a Spring InputStreamResource). When calling the server endpoint with a hand made client, it works as expected and I can read the InputStream without problem.

The generated client however (generator java, with library native) is not really doing what I think it should. Here is a part of the generated download method:

  public ApiResponse<File> downloadWithHttpInfo() throws ApiException {
    HttpRequest.Builder localVarRequestBuilder = downloadRequestBuilder();
    try {
      HttpResponse<InputStream> localVarResponse = memberVarHttpClient.send(
          localVarRequestBuilder.build(),
          HttpResponse.BodyHandlers.ofInputStream());
      if (memberVarResponseInterceptor != null) {
        memberVarResponseInterceptor.accept(localVarResponse);
      }
      try {
        if (localVarResponse.statusCode()/ 100 != 2) {
          throw getApiException("download", localVarResponse);
        }
        return new ApiResponse<File>(
          localVarResponse.statusCode(),
          localVarResponse.headers().map(),
          localVarResponse.body() == null ? null : memberVarObjectMapper.readValue(localVarResponse.body(), new TypeReference<File>() {}) // closes the InputStream
        );
      } finally {
      }

First, it returns a response of type file...Ok, I could live with that. But it just handles the response wrong: First, it retrieves a HttpResponse. That is correct and gets the input stream, but then it tries to map the response body through a JSON mapper (memberVarObjectMapper). Which is obviously wrong since the return type in the spec is "application/zip", so the method breaks here with a JSON parse error.

So, my questions:

  1. Should I change my spec in some way to make it clear(er) to the generator what I want?
  2. Can I get the client to not use the JSON mapper and instead directly return the InputStream from the response?
  3. If there is no workaround, is there another generator library which works better? I wanted to use native since we're using Java 17, but if there's other generators which work and rely on external libraries I guess I have use one of those.

Solution

  • I just ran into the same thing yesterday. I switched to using resttemplate library with useAbstractionForFiles set to true, and that worked. I would prefer to have used the native library, but it seems it may be a bug without much traction: https://github.com/OpenAPITools/openapi-generator/issues/3672