You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The HTTP services sends different status code responses depends on the business logic. The Ballerina HTTP services supports this scenario using the StatusCodeResponse records. Users can define their own status code records by type inclusion and modify the body and headers. But at the client side, users have to check the status code before processing the response payload and/or headers. This disallows them to use direct data-binding since data-binding works only for the successful responses. This proposal is to provide a way to directly data-bind the response to specific status code record types.
Goals
Provide a way to directly data-bind status code records with defined payload and headers structures
Motivation
Consider the below example service which returns different status code responses:
The service returns two status code responses - 200 - OK and 404 - Not Found
Both status code responses has defined payload structure - 200 - Album and 404 - ErrorMessage
Both status code responses has common header structure - Headers
Now, lets try to write an HTTP client to capture the above details:
importballerina/http;
publicfunction main() returnserror? {
http:ClientalbumClient=checknew ("localhost:9090/api");
http:Responseres=checkalbumClient->/albums/'3;
// The Payloadjson payload =checkres.getJsonPayload();
ifres.statusCode==http:STATUS_OK {
Album_=checkpayload.fromJsonWithType();
} elseifres.statusCode==http:STATUS_NOT_FOUND {
ErrorMessage_=checkpayload.fromJsonWithType();
} else {
// Unexpected status code responses
}
// There is another way to do direct data-binding and obtain the `ApplicationResponseError`// for failure status codes. The error details has the body and headers.// But most of the users are not aware of this error type// The Headersdo {
Headers_= {
user\-id:checkres.getHeader("user-id"),
req\-id:checkint:fromString(checkres.getHeader("req-id"))
};
} onfail {
// Unexpected response headers
}
}
Even though this works, users has to a lot of work to obtain the necessary details. In addition they have to do unnecessary checks. This becomes more complex when we have more status code responses with different media-types, payload types and headers.
This also has an impact on the client generation from the OpenAPI. Consider the below OpenAPI specification for the above service:
the return type is only for the successful response other responses will be notified as an error
if the user want to access the payload for 404 - Not Found scenarios, he has to get the ApplicationResponseError and get the details to extract the payload and headers. But mostly, the users are not aware of such error type
the header information is not exposed
Even though the OpenAPI specification gives a well defined status code responses, currently it is not possible to expose them properly in the Ballerina client/service generation.
Description
To address the above issue, the following should be supported in the HTTP module
// Client errors and other status code responses will be returned as errorAlbumFound|AlbumNotFoundres=checkalbumClient->/albums/'3;
There can be other variations of this status code response support:
There can be scenarios where the user defined response type can be a union of multiple status code responses which represents the same status code. In that case, the return type should be the first matching status code response (this is inline with cloneWithType specification)
// Consider the scenario for `404 - Not Found`AlbumNotFoundres=checkalbumClient->/albums/'3; // => matched to `AlbumNotFound`AlbumNotFound|http:NotFoundres=checkalbumClient->/albums/'3; // => matched to `AlbumNotFound`http:NotFound|AlbumNotFoundres=checkalbumClient->/albums/'3; // => matched to `http:NotFound`
The payload binding will return an anydata type for a response which does not have a 4XX or 5XX status code (Contradiction: The anydata returned from a resource will be converted to the default response with respect to the resource method). So if there are two successful responses with same/different payload structure, data binding will work for those payload structures.
For example consider the scenario when there is a two record types for the following successful responses: 201 Created - CreatedAlbum and 202 Accepted - AcceptedAlbum
// This worksCreatedAlbum|AcceptedAlbumalbumResponse=checkalbumClient->/albums.post(album);
Lets consider the status code response as well: 201 Created - AlbumCreatedRes and 202 Accepted - AlbumAcceptedRes
// This will work with this proposalAlbumCreatedRes|AlbumAcceptedResres=checkalbumClient->/albums.post(album);
The conflict occur if they use the union mix of the record types and status code response types.
Possible solution is to destructure the target type into three type one with all the anydata types, status code response types and normal http:Response. First try the status code response/response binding and if it fails then try to bind the data to the provided anydata types and if it fails return as http:Response(if that type exist otherwise it is an error) . This way this status code response binding is not breaking the existing behaviour. We are checking against the status code responses first since the different status code responses can have the same body type. So the status code response has the most relevant representation.
The construction of the status code response should consider the following:
body - should be cloned with type defined in the status code response type
headers - should be a narrowed projection of the headers with parsing the header string value with the header type defined in the status code response type
media-type - should be extracted from the content-type header
construct the status code response with the above values and add the appropriate status code object field - this is only possible in the Java native side since we need to resolve the extract type to map if there is a union type provided as a target type(as discussed in the first two points)
Dependencies
This implementation is required for the following proposal in the OpenAPI tool:
TharmiganK
changed the title
[WIP] Proposal: HTTP status code response binding support in the HTTP client
Proposal: HTTP status code response binding support in the HTTP client
Feb 26, 2024
With this PR: ballerina-platform/module-ballerina-http#1954, the above status code binding feature is moved to a separate client: http:StatusCodeClient. This is to have a clear separation from normal data-binding and the special status code data-binding.
Summary
The HTTP services sends different status code responses depends on the business logic. The Ballerina HTTP services supports this scenario using the
StatusCodeResponse
records. Users can define their own status code records by type inclusion and modify the body and headers. But at the client side, users have to check the status code before processing the response payload and/or headers. This disallows them to use direct data-binding since data-binding works only for the successful responses. This proposal is to provide a way to directly data-bind the response to specific status code record types.Goals
Motivation
Consider the below example service which returns different status code responses:
Key points to consider:
200 - OK
and404 - Not Found
200 - Album
and404 - ErrorMessage
Headers
Now, lets try to write an HTTP client to capture the above details:
Even though this works, users has to a lot of work to obtain the necessary details. In addition they have to do unnecessary checks. This becomes more complex when we have more status code responses with different media-types, payload types and headers.
This also has an impact on the client generation from the OpenAPI. Consider the below OpenAPI specification for the above service:
Lets generate a client from the above specification:
Here,
404 - Not Found
scenarios, he has to get theApplicationResponseError
and get the details to extract the payload and headers. But mostly, the users are not aware of such error typeEven though the OpenAPI specification gives a well defined status code responses, currently it is not possible to expose them properly in the Ballerina client/service generation.
Description
To address the above issue, the following should be supported in the HTTP module
There can be other variations of this status code response support:
Binding the success payload directly
Binding only the success payload directly. So this will not break the existing behaviour
Binding only the
404 - Not Found
. This is also possible if the user is only concern about the non-success responseBinding the other status code responses as
http:Response
Design points
There can be scenarios where the user defined response type can be a union of multiple status code responses which represents the same status code. In that case, the return type should be the first matching status code response (this is inline with
cloneWithType
specification)The payload binding will return an
anydata
type for a response which does not have a4XX
or5XX
status code (Contradiction: Theanydata
returned from a resource will be converted to the default response with respect to the resource method). So if there are two successful responses with same/different payload structure, data binding will work for those payload structures.For example consider the scenario when there is a two record types for the following successful responses:
201 Created
-CreatedAlbum
and202 Accepted
-AcceptedAlbum
Lets consider the status code response as well:
201 Created
-AlbumCreatedRes
and202 Accepted
-AlbumAcceptedRes
The conflict occur if they use the union mix of the record types and status code response types.
Possible solution is to destructure the target type into three type one with all the
anydata
types, status code response types and normalhttp:Response
. First try the status code response/response binding and if it fails then try to bind the data to the providedanydata
types and if it fails return ashttp:Response
(if that type exist otherwise it is an error) . This way this status code response binding is not breaking the existing behaviour. We are checking against the status code responses first since the different status code responses can have the same body type. So the status code response has the most relevant representation.The construction of the status code response should consider the following:
content-type
headerDependencies
This implementation is required for the following proposal in the OpenAPI tool:
The text was updated successfully, but these errors were encountered: