openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[Dart] Add UInt8List support, allowing for type:string format:binary definitions

Open 0xNF opened this issue 3 years ago • 11 comments

Summary

tl;dr UInt8List support, which Dart-Dio has, has been added to the regular Dart2 generator.

Fixes #12161.

Details

Changes to the Generators:

To support UInt8List in the generator, Typed Data imports had to be added. Additionally, some OpenAPI data types have been switched to Uint8List.

  • [AbstractDartCodeGen.java]: added Uint8List/dart:typed_data to the imports.
  • [AbstractDartCodeGen.java]: Changed typeMapping of {file, binary} to Uint8List away from MultiPartFile
  • [AbstractDartCodeGen.java]: Copied Multipart/Uint8list differentiation in postProcessOperationsWithModels from DartDioClientCodegen.java
  • [dart2/apilib.mustache]: Added import 'dart:typed_data';

Changes to the API classes

To support Uint8List in the generated API output, parts of the *api.dart files had to be refactored. Presently Dart2 relies on passing utf8 decoded response byte strings through its API calls, but this leads to errors because not all response objects are json strings. To handle this, I refactored many of the calls to take Uint8List's straight from response.bodyBytes. Decoding into a String object doesn't happen until it needs to, which is right before passing the object down into the Json Decoding section.

  • [api_client.dart]: deserialize and deserializeAsync now take Uint8List as their default input
  • [api_helper.dart]: removed _decodeBodyBytes in favor of just using response.bodyBytes
  • [api_helper.dart]: added decodeError method to deal with the byte response, which decodes the resposne into a utf-8 String.

To confirm this change, use the following specfile:

specfile
openapi: 3.0.3
info:
  version: "1.1"
  title: Dart Uint8list Demo
servers:
  - url: "localhost"
    variables:
      host:
        default: localhost
paths:
  /getData:
    get:
      operationId: GetData
      description: "Should return a Uint8List of bytes"
      responses:
        "200":
          description: Binary data
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
    put:
      operationId: PutData
      description: "Should push a Multipart File"
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                fileContent:
                  type: string
                  format: binary
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: string
  /item:
    get:
      operationId: GetItem
      description: "Should return an Item"
      responses:
        "200":
          description: items
          content:
            application/json:
              schema:
                $ref: "#components/schemas/item"
components:
  schemas:
    Item:
      type: object
      description: "Some json thing"
      required:
        - intField
        - doubleField
        - stringField
        - dateField
        - timeField
        - dateTimeField
        - boolField
        - b64Field
        - intArrayField
      properties:
        intField:
          type: integer
          format: int32
        doubleField:
          type: number
          format: float
        stringField:
          type: string
        dateField:
          type: string
          format: date
        timeField:
          type: string
          format: time
        dateTimeField:
          type: string
          format: date-time
        boolField:
          type: boolean
        b64Field:
          type: string
          format: byte
        intArrayField:
          type: array
          items:
            type: integer
            format: int32

PR checklist

  • [x] Read the contribution guidelines.
  • [x] Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • [x] Run the following to build the project and update samples:
  • [x] File the PR against the correct branch: master (6.1.0) (minor release - breaking changes with fallbacks), 7.0.x (breaking changes without fallbacks)
  • [x] If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@jaumard @josh-burton @amondnet @sbu-WBT @kuhnroyal @agilob @ahmednfwela

0xNF avatar Sep 17 '22 09:09 0xNF

When I get home I'll try to fix it, but I didn't touch any of those files by hand. I only ran the generate samples script. I didn't even open these in my editor.

0xNF avatar Sep 17 '22 13:09 0xNF

@kuhnroyal @wing328 Can you check why the tests were passing here when there was a compile error for the generated code?

ahmednfwela avatar Sep 19 '22 07:09 ahmednfwela

@0xNF did you make any changes in the java files? I can't see them in the PR

ahmednfwela avatar Sep 19 '22 07:09 ahmednfwela

The Java changes seem to have gotten lost. Sorry this PR is kinda messy. I'm flipping between too many branches rn.

0xNF avatar Sep 19 '22 08:09 0xNF

@kuhnroyal @wing328 Can you check why the tests were passing here when there was a compile error for the generated code?

The test did run and passed. Does it has anything to do with Dart version?

      - uses: dart-lang/setup-dart@v1
        with:
          sdk: 2.14.0

That's what we use in the CI.

wing328 avatar Sep 19 '22 08:09 wing328

dart 2 uses 2.12 in the generated code, which 2.14 should be able to run

ahmednfwela avatar Sep 19 '22 08:09 ahmednfwela

Can you please paste the compilation error here as well? I'll try to repeat that locally.

wing328 avatar Sep 19 '22 08:09 wing328

It's probably because I force pushed the update to my own branch, and the tests didn't re-run here.

0xNF avatar Sep 19 '22 09:09 0xNF

It's probably because I force pushed the update to my own branch, and the tests didn't re-run here.

To trigger the run, please update the samples and the Github action (dart job) will run again.

wing328 avatar Sep 19 '22 11:09 wing328

Should I be regenerating all samples? Up til now I've just been regenerating the relevant samples for my changes (Dart). But then the CI complains.

0xNF avatar Sep 20 '22 01:09 0xNF

yes please update the samples as the CI fails: https://github.com/OpenAPITools/openapi-generator/actions/runs/3086648029/jobs/4991237644

wing328 avatar Sep 20 '22 13:09 wing328

@0xNF @wing328 Is there any movement on this? It looks like this PR is functionally ready to land. Just needing some clean-up.

Currently, I'm facing an issue around this as passing a UInt8List to a generated API endpoint causes the following error:

DioError [DioErrorType.other]: Bad state: No serializer for 'Uint8List'.

Relevant Code (Generated API's model.dart):

    yield serializers.serialize(
      object.appBinaryData,
      specifiedType: const FullType(Uint8List),
    );

zmoshansky avatar Jan 10 '23 23:01 zmoshansky

@zmoshansky this PR is for dart generator, and it seems like you are using the dart-dio generator, please create a new Issue with reproducible sample

ahmednfwela avatar Jan 10 '23 23:01 ahmednfwela