Skip to content

Commit

Permalink
Merge pull request #2152 from lnash94/service_query_annotation
Browse files Browse the repository at this point in the history
[master] Add Query Parameter Annotation Mapping for Http Service
  • Loading branch information
lnash94 authored Sep 21, 2024
2 parents 084d608 + e3855c5 commit b222df2
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
// under the License.

import ballerina/http;
import ballerina/http_test_common as common;
import ballerina/test;
import ballerina/url;
import ballerina/http_test_common as common;

listener http:Listener QueryBindingEP = new (queryParamBindingTestPort, httpVersion = http:HTTP_1_1);
final http:Client queryBindingClient = check new ("http://localhost:" + queryParamBindingTestPort.toString(), httpVersion = http:HTTP_1_1);
Expand Down Expand Up @@ -167,8 +167,29 @@ service /queryparamservice on QueryBindingEP {
resource function get studentRest(StudentRest studentRest) returns StudentRest {
return studentRest;
}

resource function get queryAnnotation(@http:Query {name: "first"} string firstName, @http:Query {name: "last-name"} string lastName) returns string {
return string `Hello, ${firstName} ${lastName}`;
}

resource function get queryAnnotation/negative/q1(@http:Query {name: ""} string firstName) returns string {
return string `Hello, ${firstName}`;
}

resource function get queryAnnotation/negative/q2(@http:Query {name: ()} string lastName) returns string {
return string `Hello, ${lastName}`;
}

resource function get queryAnnotation/mapQueries(@http:Query {name: "rMq"} Mq mq) returns string {
return string `Hello, ${mq.name} ${mq.age}`;
}
}

public type Mq record {
string name;
int age;
};

service /default on QueryBindingEP {
resource function get checkstring(string foo = "hello") returns json {
json responseJson = {value1: foo};
Expand Down Expand Up @@ -353,7 +374,7 @@ function testNegativeStringQueryBindingCaseSensitivity() returns error? {
if response is http:Response {
test:assertEquals(response.statusCode, 400);
check common:assertJsonErrorPayload(check response.getJsonPayload(), "no query param value found for 'foo'",
"Bad Request", 400, "/queryparamservice/?FOO=WSO2&bar=go", "GET");
"Bad Request", 400, "/queryparamservice/?FOO=WSO2&bar=go", "GET");
} else {
test:assertFail(msg = "Found unexpected output type: " + response.message());
}
Expand All @@ -365,7 +386,7 @@ function testNegativeIntQueryBindingCastingError() returns error? {
if response is http:Response {
test:assertEquals(response.statusCode, 400);
check common:assertJsonErrorPayload(check response.getJsonPayload(), "error in casting query param : 'bar'",
"Bad Request", 400, "/queryparamservice/?foo=WSO2&bar=go", "GET");
"Bad Request", 400, "/queryparamservice/?foo=WSO2&bar=go", "GET");
} else {
test:assertFail(msg = "Found unexpected output type: " + response.message());
}
Expand All @@ -374,7 +395,7 @@ function testNegativeIntQueryBindingCastingError() returns error? {
if response is http:Response {
test:assertEquals(response.statusCode, 400);
check common:assertJsonErrorPayload(check response.getJsonPayload(), "error in casting query param : 'bar'",
"Bad Request", 400, "/queryparamservice/?foo=WSO2&bar=", "GET");
"Bad Request", 400, "/queryparamservice/?foo=WSO2&bar=", "GET");
} else {
test:assertFail(msg = "Found unexpected output type: " + response.message());
}
Expand Down Expand Up @@ -549,7 +570,7 @@ function testEmptyQueryParamBinding() returns error? {
if response is http:Response {
test:assertEquals(response.statusCode, 400);
check common:assertJsonErrorPayload(check response.getJsonPayload(), "no query param value found for 'x-Type'",
"Bad Request", 400, "/queryparamservice/q9?x-Type", "GET");
"Bad Request", 400, "/queryparamservice/q9?x-Type", "GET");
} else {
test:assertFail(msg = "Found unexpected output type: " + response.message());
}
Expand Down Expand Up @@ -736,3 +757,27 @@ function testMapOfJsonTypedQueryParamBinding3() returns error? {
response = check queryBindingClient->get("/queryparamservice/q13?obj=" + mapOfJsonsEncoded);
test:assertEquals(response.statusCode, 400, msg = "Found unexpected output");
}

@test:Config {}
function testforQueryParamterNameOverwrite() returns error? {
string result = check queryBindingClient->get("/queryparamservice/queryAnnotation?first=Harry&last-name=Potter");
test:assertEquals(result, "Hello, Harry Potter", msg = string `Found ${result}, expected Harry`);

map<json> mapOfJsons = {
name: "Ron",
age: 10
};
string mapOfQueries = check url:encode(mapOfJsons.toJsonString(), "UTF-8");

result = check queryBindingClient->get("/queryparamservice/queryAnnotation/mapQueries?rMq=" + mapOfQueries);
test:assertEquals(result, "Hello, Ron 10", msg = string `Found ${result}, expected Harry`);
}

@test:Config {}
function testforNegativeQueryParamterNameOverwrite() returns error? {
string result = check queryBindingClient->get("/queryparamservice/queryAnnotation/negative/q1?firstName=Harry");
test:assertEquals(result, "Hello, Harry");

result = check queryBindingClient->get("/queryparamservice/queryAnnotation/negative/q2?lastName=Anne");
test:assertEquals(result, "Hello, Anne");
}
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- [Add `anydata` support for `setPayload` methods in the request and response objects](https:/ballerina-platform/ballerina-library/issues/6954)
- [Improve `@http:Query` annotation to overwrite the query parameter name in client] (https:/ballerina-platform/ballerina-library/issues/6983)
- [Improve `@http:Query` annotation to overwrite the query parameter name in service] (https:/ballerina-platform/ballerina-library/issues/7006)

## [2.12.0] - 2024-08-20

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_NAME_CALLER_INFO;
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_NAME_HEADER;
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_NAME_PAYLOAD;
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_NAME_QUERY;
import static io.ballerina.stdlib.http.api.HttpConstants.COLON;
import static io.ballerina.stdlib.http.api.HttpConstants.PROTOCOL_HTTP;
import static io.ballerina.stdlib.http.api.HttpUtil.getParameterTypes;
Expand Down Expand Up @@ -89,6 +90,7 @@ public class ParamHandler {
+ ANN_NAME_CALLER_INFO;
public static final String CACHE_ANNOTATION = ModuleUtils.getHttpPackageIdentifier() + COLON
+ ANN_NAME_CACHE;
public static final String QUERY_ANNOTATION = ModuleUtils.getHttpPackageIdentifier() + COLON + ANN_NAME_QUERY;

public ParamHandler(ResourceMethodType resource, int pathParamCount, boolean constraintValidation) {
this.resource = resource;
Expand Down Expand Up @@ -272,11 +274,28 @@ private void createHeaderParam(String paramName, BMap annotations) {

private void createQueryParam(int index, ResourceMethodType balResource, Type originalType) {
io.ballerina.runtime.api.types.Parameter parameter = balResource.getParameters()[index];
QueryParam queryParam = new QueryParam(originalType, HttpUtil.unescapeAndEncodeValue(parameter.name), index,
parameter.isDefault, constraintValidation);
String paramName = parameter.name;
BMap annotations = (BMap) balResource.getAnnotation(
StringUtils.fromString(PARAM_ANNOT_PREFIX + IdentifierUtils.escapeSpecialCharacters(paramName)));
if (annotations != null) {
String queryParamName = getQueryParamName(paramName, annotations);
paramName = queryParamName.isBlank() ? paramName : queryParamName;
}
paramName = HttpUtil.unescapeAndEncodeValue(paramName);
QueryParam queryParam = new QueryParam(originalType, paramName, index, parameter.isDefault,
constraintValidation);
this.queryParams.add(queryParam);
}

private static String getQueryParamName(String paramName, BMap annotations) {
BMap mapValue = annotations.getMapValue(StringUtils.fromString(QUERY_ANNOTATION));
Object queryName = mapValue.get(HttpConstants.ANN_FIELD_NAME);
if (queryName instanceof BString query) {
return query.getValue();
}
return paramName;
}

public boolean isPayloadBindingRequired() {
return payloadParam != null;
}
Expand Down

0 comments on commit b222df2

Please sign in to comment.