I am new on OSB.
1) I have a Service S1 with two methods say : AsyncQueryAccount, SyncQueryAccount . AsyncQueryAccount has input parameters id, name . SyncQueryAccount has input parameters id,name,addToQueue .
2) I have a Service S2 with one method say : AsyncQueryAccount. This has input parameters id,name .
My Objective is to call S1, S2 both upon request being made to the Proxy.
If operation is AsyncQueryAccount then it should call subsequent method in S1, S2.
If operation is SyncQueryAccount then it should call AsyncQueryAccount removing addToQueue in S2 and SyncQueryAccount in S1.
To achieve this I tried following
Proxy --> Route to S1
and as part of Route to S1 --> Added a Service Callout to S2 with details saying:
If $operation = 'SyncQueryAccount' or $operation = 'AsyncQueryAccount' then invoke AsyncQueryAccount in S2.
This works fine when AsyncQueryAccount is called, but fails when SyncQueryAccount is called.
How do we make sure that when SyncQueryAccount is called, then AsyncQueryAccount is called in S2 as well.
I get error saying:
A system error has occurred at 'RouteNode1'. Reason: 'OSB Service Callout action received SOAP Fault response'. Please contact an ESB system administrator
As I understood your problem,I think flow should be like as below
Proxy --> callout S2 --> if $operation = 'SyncQueryAccount' then callout SycnQueryAccount specific service(please use Xquery for transformation if required) or callout AsyncQueryAccount specific service.
Please try to assign request payload into different variables because I suspect that your request body is getting changed once you recieve response from First service.
Related
I'd like to ask if there is some way to skip rest of the split route and jump directly to aggregator part, when in the exception handler I mark the split route to continue.
I have a route like this:
receive a message
fetch config for 3 endpoints
merge config and message as a tuple for each endpoint, and create a list of it
.split(), and in the split route I convert message according to config for each endpoint(s1), fetch oauth token(s2), send to final endpoint with token(s3), collect response for each endpoint(s4), aggregate(split aggregator; splitting ends here, let's call it sa)
return as a whole one result
stop
You can see, in the split route there are 4 steps(s1-s4); if any of these step fails I want to jump to aggregation(sa). For example, it does not make sense to continue the split route, if s1 or s2 fails.
I define an onException() clause to handle the exception and mark it to continue(continued(true)),because anyway I want to reach aggregator. Also, if I mark continue(false), not only split route, but the whole route(meaning the main route even before splitting) will be rolled back. I want to decide rollback after getting all the causes/exceptions in each split branch.
I have a workaround for a simple case, which is, in exception handler for errors in s2, I add a property in the exchange oauth_failed to be true, and add a condition check choice().when() after s2; if this prop is null, then go to s3 (continue sending). Solely for this purpose I must isolated s3 as a separate route(direct:s3).
.bean(S2Bean.class)
.choice()
.when(simple("${exchangeProperty.oauth_failed} == null")) // null = continue the flow
.to("direct:s3")
.endChoice()
// otherwise, it will skip s3 and s4, and jump to aggregator directly
.end()
But, what can I do if s1 throws exception? Do I need to isolate s2 as a direct endpoint too? Then each step in the pipeline should be a separate endpoint. I don't like that.
Find a solution: use doTry and doCatch in split route and don't .stop().
from("direct:split")
.doTry()
.bean(S1Bean.class)
.bean(S2Bean.class)
.bean(S3Bean.class)
.bean(S4Bean.class)
.endDoTry()
.doCatch(javax.ws.rs.ProcessingException.class) // oauth timeout
.log(LoggingLevel.ERROR, "Time out, never retry, just aggregate")
.bean(MyGenericExceptionHandler.class)
.doCatch(Exception.class)
.log(LoggingLevel.ERROR, "Other exceptions, mark as failed, aggregate")
.bean(MyGenericExceptionHandler.class)
.end();
And in the MyGenericExceptionHandler, exchange.getIn().setBody(xxx) to set body to the expected type which my aggregator needs. The exception is in exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class), response code is null. (I create a dto to contain both status code and/or exception, so that either success or failure, I aggregate with same class)
Don't call stop().
I have written an apache 2.x module that attempts to scan request bodies, and conditionally return 403 Forbidden if certain patterns match.
My first attempt used ap_hook_handler to intercept the request, scan it and then returned DECLINED to the real handler could take over (or 403 if conditions were met).
Problem with that approach is when I read the POST body of the request (using ap_get_client_block and friends), it apparently consumed body so that if the request was subsequently handled by mod_proxy, the body was gone.
I think the right way to scan the body would be to use an input filter, except an input filter can only return APR_SUCCESS or fail. Any return codes other than APR_SUCCESS get translated into HTTP 400 Bad Request.
I think maybe I can store a flag in the request notes if the input filter wants to fail the request, but I'm not sure which later hook to get that.
turned out to be pretty easy - just drop an error bucket into the brigade:
apr_bucket_brigade *brigade = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc);
apr_bucket *bucket = ap_bucket_error_create(403, NULL, f->r->pool,
f->r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(brigade, bucket);
bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(brigade, bucket);
ap_pass_brigade(f->next, brigade);
We have configured REST proxy service that accepts JSON input. If the input is not a well formed JSON OSB is throwing Translation error with HTTP 500 Staus code. Is that possible we can send Customized error message in this scenario
You need to create a global error handler for your pipeline and set the desired error message using a replace action here, followed by a "Reply" action.
Keep in mind that if you try to "read" the original request body in the global error handler, and if the original request was malformed, it will get thrown up to the system error handler and you will get the system error message again.
Here's a sample OSB 12.2.1.1 project you can use to try this: https://github.com/jvsingh/SOATestingWithCitrus/tree/develop/OSB/Samples/ServiceBusApplication1
The accompanying soapui project contains two requests. The malformed request should return this:
(I have only set the response here. You would also need to set the proper content type and decide whether you want to treat this as "success" or "failure" etc. in the reply action)
The code gets the username and password from the user's inputs. Then it gets the device Mac Address using the 2 functions. I know this part can be simplified, I'm open to recommendations.
I'm 100% sure that $scope.data.macAddr is not empty because I'm able to print it on the console. I was worried about the data type, but I confirmed it that is a string using the "type" of, which returns 'String'.
Update: Also when I inspect the post headers only username and password are sending over.
I don't understand why http.post sends an empty/ not passing it at all to the server.
P.S I know about the MD5 risks. I'm using MD5 just to test my code. Eventually, at the end, I will use HTTPS/SSL with Bcrypt
var link = 'http://app.example.com/api.php';
MacAddress.getMacAddress(function(macAddress){$scope.getMacAddr(macAddress);}, function(fail){console.log(fail);});
$scope.getMacAddr = function(macAddr) {
$scope.macAddr = macAddr;
$scope.data.macAddr = macAddr;
}
$http.post(link, {
username: md5.createHash($scope.data.username),
password: md5.createHash($scope.data.password),
macAddr: $scope.data.macAddr
}).then(function(res) {
console.log(typeof ($scope.data.macAddr));
OK, so you have two asynchronous calls here. One is the call to get the MAC address, and one is the http post. Here is what happens:
At T0: You call getMacAddress(), passing a callback function that will be called, later, when the mac address is available
At T1: You send an HTTP request, passing a callback to then()
At T1000: The mac address is available: the callback passed at step 1 is called, and initializes $scope.data.macAddr
At T150000: the http response is available. The callpack passed at step 2 is called, and prints $scope.data.macAddr.
Send your http request from inside the callback function that you pass at step 1, when the mac address is available.
I am using Restangular in one of my works
The server guys have give me the following calls which i need to integrate on the AngularJS client
PUT api/partners/password – RequestPayload[{password,confirmpassword}]
partner id is being sent in the header
GET api/partners/password/forgot/ - Request Payload [{emailaddress}]
partner id is being sent in the header
The javascript code that I have written to call these services is as follow
Restangular.all('Partners').one('Password').put(params); - sends params as query string
Restangular.all('Partners').one('Password').one('Forgot').get(params); - sends object in the url
I have tried other ways but it simply doesn't make the correct call.
Help me out guys!
So, for point #1. it puts the object at hand, not another object. So you have 2 options:
Option 1
var passReq = Restangular.all('Partners').one('Password');
passReq.confirmPassword = ....
passReq.put(); // confirmPassword and the params of the object will be sent
Option 2 is
var passReq = Restangular.all('Partners').one('Password').customPUT(obj);
For Point #2, you cannot send a request body (payload) in the GET unfortunately.