epam-cross-platform-lab / swagger-dart-code-generator

Swagger/OpenAPI code generator based on Chopper and JsonAnnotation for Flutter
Apache License 2.0
254 stars 111 forks source link

[BUG]Multipart/form-data request is not working, with swagger: 2.0 #726

Open linbintie opened 4 months ago

linbintie commented 4 months ago

Hi guys!

Library version used: swagger_dart_code_generator: ^2.15.0

Describe the bug

We are generating our current specification and some of the services are not properly generated. All of the multipart/form-data services are being created as common https://github.com/post calls without any @partfile attributes, leading us on not being able to use the generator for those services. Our spec is attached for your references (using OpenAPI 2.0).

 /project:
    post:
      tags:
        - project
      operationId: addProject
      consumes:
        - multipart/form-data
      parameters:
        - name: session
          in: formData
          type: string
          required: true
        - name: name
          in: formData
          type: string
          required: true
        - name: projId
          in: formData
          type: string
          required: true
        - name: dbSet
          in: formData
          type: string
          required: true
        - name: zone
          in: formData
          type: string
          allowEmptyValue: true
        - name: iconFile
          in: formData
          type: file
      responses:
        '201':
          description: Created
          schema:
            $ref: '#/definitions/project'

gen code:

@override
  Future<Response<Project>> _projectPost({
    required String? session,
    required String? name,
    required String? projId,
    required String? dbSet,
    String? zone,
    List<int>? iconFile,
  }) {
    final Uri $url = Uri.parse('/project');
    final $body = <String, dynamic>{
      'session': session,
      'name': name,
      'projId': projId,
      'dbSet': dbSet,
      'zone': zone,
      'iconFile': iconFile,
    };

    final Request $request = Request(
      'POST',
      $url,
      client.baseUrl,
      body: $body,
    );
    return client.send<Project, Project>($request);
  }

The generated code is wrong Are we missing something?

akshatshah commented 4 months ago

@linbintie I faced the same issue. I think it's because the isMultipart boolean value is set based on the requestBody here:

https://github.com/epam-cross-platform-lab/swagger-dart-code-generator/blob/2a5d6733a1c665662a1a14f7c58fe1540a8f2894/lib/src/swagger_models/requests/swagger_request.dart#L120

I was able to fix it by changing to the OpenAPI 3.0 spec which would have requestBody instead of consumes.

linbintie commented 4 months ago

sorry, I can't changing to the OpenAPI 3.0 because the services depends on OpenAPI 2.0. We rely on the same spec file to generate the code. I can't make a unilateral change. Is there any other way to fix it?

Vovanella95 commented 4 months ago

Hi @linbintie , we can create workaround for you. Just let us know, what is expected generated code looks like

linbintie commented 4 months ago

Thanks, @Vovanella95 I want is to generate code like this:

@override
  Future<Response<Project>> _projectPost({
    required String? session,
    required String? name,
    required String? projId,
    required String? dbSet,
    String? zone,
    List<int>? iconFile,
  }) {
    final Uri $url = Uri.parse('/project');
    final List<PartValue> $parts = <PartValue>[
      PartValue<String?>(
        'session',
        session,
      ),
      PartValue<String?>(
        'name',
        name,
      ),
      PartValue<String?>(
        'projId',
        projId,
      ),
      PartValue<String?>(
        'dbSet',
        dbSet,
      ),
      PartValue<String?>(
        'zone',
        zone,
      ),
      PartValueFile<List<int>?>(
        'iconFile',
        iconFile,
      ),
    ];
    final Request $request = Request(
      'POST',
      $url,
      client.baseUrl,
      parts: $parts,
      multipart: true,
    );

    return client.send<Project, Project>($request);
  }

it can work very well.

Vovanella95 commented 4 months ago

Hi @linbintie , It's Chopper generated code, We can not generate it. We generate only .swagger.dart files. Can we generate swagger.dart file somehow for you?

linbintie commented 4 months ago

@Vovanella95 yes, you can.

Vovanella95 commented 4 months ago

@linbintie could you provide expected generated .swagger.dart file?

Sorry I do not have experience with multipart :)

linbintie commented 4 months ago

@Vovanella95 it's okay,thank you.

this is .swagger.dart file:

consumes:
  - application/json
info:
  title: test
  version: 0.1.0
produces:
  - application/json
schemes:
  - http
swagger: '2.0'
basePath: /ad_v1
paths:
  /project:
    post:
      tags:
        - project
      operationId: addProject
      consumes:
        - multipart/form-data
      parameters:
        - name: session
          in: formData
          type: string
          required: true
        - name: name
          in: formData
          type: string
          required: true
        - name: projId
          in: formData
          type: string
          required: true
        - name: dbSet
          in: formData
          type: string
          required: true
        - name: zone
          in: formData
          type: string
          allowEmptyValue: true
        - name: iconFile
          in: formData
          type: file
      responses:
        '201':
          description: Created
        default:
          description: error
Vovanella95 commented 3 months ago

Hi @linbintie , you provided swagger file. I asked for expected generated .swagger.dart file)) Sorry for misunderstanding)))

linbintie commented 3 months ago

@Vovanella95

like this code?

Future<chopper.Response<Project>> projectPost({
    required String? session,
    required String? name,
    required String? projId,
    required String? dbSet,
    String? zone,
    http.MultipartFile? iconFile,
  }) {
    generatedMapping.putIfAbsent(Project, () => Project.fromJsonFactory);

    final Uri $url = Uri.parse('/project');
    final List<PartValue> $parts = <PartValue>[
      PartValue<String?>(
        'session',
        session,
      ),
      PartValue<String?>(
        'name',
        name,
      ),
      PartValue<String?>(
        'projId',
        projId,
      ),
      PartValue<String?>(
        'dbSet',
        dbSet,
      ),
      PartValue<String?>(
        'zone',
        zone,
      ),
      if (iconFile != null)
        PartValueFile(
          'iconFile',
          iconFile,
        ),
    ];

    final Request $request = Request(
      'POST',
      $url,
      client.baseUrl,
      parts: $parts,
      multipart: true,
    );
    return client.send<Project, Project>($request);
  }
Vovanella95 commented 3 months ago

Hi @linbintie , yes, it's good! Thanks a lot! Will try to handle it asap

linbintie commented 3 months ago

@Vovanella95 thank you.