Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the OpenAPI generated client's method signature to match the HTTP client's method signature #6475

Closed
TharmiganK opened this issue May 2, 2024 · 0 comments · Fixed by ballerina-platform/openapi-tools#1698
Assignees
Labels
module/openapi-tools Points/4 Team/PCM Protocol connector packages related issues Type/Improvement

Comments

@TharmiganK
Copy link
Contributor

Description:

Improve the signature of the OpenAPI generated client's method to have clear parameter separation with headers, queries and payload. The HTTP client methods have such separation:

  • map<string|string[]> parameter to represents the headers
  • included record parameter to represents the queries
  • anydata parameter to represent the payload

Describe your problem(s)

Consider the following OAS:

openapi: 3.0.1
info:
  title: Api
  version: 0.1.0
servers:
- url: "{server}:{port}/api"
  variables:
    server:
      default: http://localhost
    port:
      default: "9090"
paths:
  /albums:
    get:
      operationId: getAlbums
      parameters:
      - name: version
        in: header
        required: true
        schema:
          $ref: '#/components/schemas/Version'
      - name: user-id
        in: header
        required: true
        schema:
          type: string
      - name: genre
        in: query
        schema:
          type: string
      responses:
        "200":
          description: Ok
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Album'
    post:
      operationId: postAlbums
      parameters:
      - name: version
        in: header
        required: true
        schema:
          $ref: '#/components/schemas/Version'
      - name: user-id
        in: header
        required: true
        schema:
          type: string
      - name: directory
        in: query
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Album'
        required: true
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Album'
components:
  schemas:
    Album:
      required:
      - artist
      - genre
      - name
      - year
      type: object
      properties:
        name:
          type: string
        artist:
          type: string
        year:
          type: integer
          format: int64
        genre:
          type: string
      additionalProperties: false
    Version:
      type: string
      enum:
      - V2
      - V1

The current generated client:

public isolated client class Client {
    ...

    # Get the albums
    #
    # + genre - The genre
    # + return - Ok 
    resource isolated function get albums(Version version, string user\-id, string? genre = ()) returns Album[]|error {
        string resourcePath = string `/albums`;
        map<anydata> queryParam = {"genre": genre};
        resourcePath = resourcePath + check getPathForQueryParam(queryParam);
        map<any> headerValues = {"version": version, "user-id": user\-id};
        map<string|string[]> httpHeaders = getMapForHeaders(headerValues);
        return self.clientEp->get(resourcePath, httpHeaders);
    }

    # Post an album
    #
    # + directory - The directory
    # + payload - The album 
    # + return - Created 
    resource isolated function post albums(Version version, string user\-id, Album payload, string? directory = ()) returns Album|error {
        string resourcePath = string `/albums`;
        map<anydata> queryParam = {"directory": directory};
        resourcePath = resourcePath + check getPathForQueryParam(queryParam);
        map<any> headerValues = {"version": version, "user-id": user\-id};
        map<string|string[]> httpHeaders = getMapForHeaders(headerValues);
        http:Request request = new;
        json jsonBody = payload.toJson();
        request.setPayload(jsonBody, "application/json");
        return self.clientEp->post(resourcePath, request, httpHeaders);
    }
}

Usage compare to the HTTP client:

Album[] _ = check httpClient->/albums({user\-id: "123", version: "V1"}, genre = "pop");

Album[] _ = check generatedClient->/albums(user\-id = "123", version = "V1", genre = "pop");

Describe your solution(s)

The new generated client:

public isolated client class Client {
    ...

    # + headers - Headers to be sent with the request 
    # + queries - Queries to be sent with the request 
    # + return - Ok 
    resource isolated function get albums(GetAlbumsHeaders headers, *GetAlbumsQueries queries) returns Album[]|error {
        string resourcePath = string `/albums`;
        resourcePath = resourcePath + check getPathForQueryParam(queries);
        map<string|string[]> httpHeaders = getMapForHeaders(headers);
        return self.clientEp->get(resourcePath, httpHeaders);
    }

    # + headers - Headers to be sent with the request 
    # + queries - Queries to be sent with the request 
    # + return - Created 
    resource isolated function post albums(PostAlbumsHeaders headers, Album payload, *PostAlbumsQueries queries) returns Album|error {
        string resourcePath = string `/albums`;
        resourcePath = resourcePath + check getPathForQueryParam(queries);
        map<string|string[]> httpHeaders = getMapForHeaders(headers);
        http:Request request = new;
        json jsonBody = payload.toJson();
        request.setPayload(jsonBody, "application/json");
        return self.clientEp->post(resourcePath, request, httpHeaders);
    }
}

The new header and query records:

# Represents the Headers record for the operation: postAlbums
public type PostAlbumsHeaders record {
    string user\-id;
    Version version;
};

# Represents the Headers record for the operation: getAlbums
public type GetAlbumsHeaders record {
    string user\-id;
    Version version;
};

public type Version "V2"|"V1";

# Represents the Queries record for the operation: postAlbums
public type PostAlbumsQueries record {
    string? directory?;
};

# Represents the Queries record for the operation: getAlbums
public type GetAlbumsQueries record {
    # The genre
    string? genre?;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module/openapi-tools Points/4 Team/PCM Protocol connector packages related issues Type/Improvement
Projects
Archived in project
Status: Done
1 participant