ballerina-platform / ballerina-library

The Ballerina Library
https://ballerina.io/learn/api-docs/ballerina/
Apache License 2.0
138 stars 56 forks source link

[Phase 02] Support resource functions in OpenAPI Client Generation tool #5158

Open lnash94 opened 1 year ago

lnash94 commented 1 year ago

Description: Parent issue: https://github.com/ballerina-platform/ballerina-standard-library/issues/5366

During this 2nd phase, try to improve the client resource method body with the client resource method call in below way

string response = check httpClient->/some/endpoint(payload, headers, "application/json", name = "foo", id = 123);

Current Generated code

resource isolated function get api/v2/opportunities(string? embed = ()) returns OpportunityObject|error {
        string resourcePath = string `/api/v2/opportunities`;
        map<anydata> queryParam = {"embed": embed};
        resourcePath = resourcePath + check getPathForQueryParam(queryParam);
        OpportunityObject response = check self.clientEp->get(resourcePath);
        return response;
    }

With Improvement

resource isolated function get api/v2/opportunities(string? embed = ()) returns OpportunityObject|error {
        OpportunityObject response = check self.clientEp->/api/v2/opportunities/.get(embed);
        return response;
    }
lnash94 commented 1 year ago

Once we are going to check the feasibility of this improvement in the client resource function we encounter this ,

Other than query parameters, object can be send as a path parameter or header according to the OpenAPI 3.0 . Please find more information on related to parameter serialization in OpenAPI 3.0 here.

This scenario was handled previously by introducing a util function to generate the path according to the serialization.

resourcePath = resourcePath + check getPathForQueryParam(queryParam);
------------
# functions to generate query parameter path
isolated function  getPathForQueryParam(map<anydata> queryParam)  returns  string|error {
    string[] param = [];
    param[param.length()] = "?";
    foreach  var [key, value] in  queryParam.entries() {
        if  value  is  () {
            _ = queryParam.remove(key);
        } else {
            if  string:startsWith( key, "'") {
                 param[param.length()] = string:substring(key, 1, key.length());
            } else {
                param[param.length()] = key;
            }
            param[param.length()] = "=";
            if  value  is  string {
                string updateV =  check url:encode(value, "UTF-8");
                param[param.length()] = updateV;
            } else {
                param[param.length()] = value.toString();
            }
            param[param.length()] = "&";
        }
    }
    _ = param.remove(param.length()-1);
    if  param.length() ==  1 {
        _ = param.remove(0);
    }
    string restOfPath = string:'join("", ...param);
    return restOfPath;
}

but given the improvement resource method

OpportunityObject response = check self.clientEp->/api/v2/opportunities.get(embed);

we can't handle the parameter serialization. Therefore we have to move with the current implementation [1] until we receive some support from http to handle parameter serialization-related issues https://github.com/ballerina-platform/ballerina-standard-library/issues/1747 [1]

resource isolated function get api/v2/opportunities(string? embed = ()) returns OpportunityObject|error {
        string resourcePath = string `/api/v2/opportunities`;
        map<anydata> queryParam = {"embed": embed};
        resourcePath = resourcePath + check getPathForQueryParam(queryParam);
        OpportunityObject response = check self.clientEp->get(resourcePath);
        return response;
    }