How to define dependencies on two client calls in quarkus reactive programming - quarkus

I have two Client APIs that return an Uni.
Uni<Customer> getCustomer(customerID)
Uni<Address> getAddress(addressID)
And I want to open a REST API
Uni<FullCustomer> getFullCustomer(String customerID)
The logic is to make the Customer Client call first. If the returned customer object has addressID then make the second Address Client call and get shipping address details. If shipping address is not available then just wrap the customer in FullCustomer object and return else wrap both customer and address in FullCustomer object and return.
I dont want to block the thread on client call (await().indefinitely()), hence i am using onItem and transfer method call. But my code returns a Uni<Uni> and i want it to return a Uni.
#GET
#Path("api/customer/{id}")
#Produces({ "application/json" })
Uni<Uni<FullCustomer>> getFullCustomer(#PathParam("id") String customerID){
Uni<Customer> customerResponse = getCustomer(customerID);
Uni<Uni<FullCustomer>> asyncResponse = customerResponse.onItem().transform(customer -> {
if (customer.getAddressId() != null) {
Uni<Address> addressResponse = getAddress(customer.getAddressId());
Uni<FullCustomer> fullCustomer = addressResponse.onItem().transform(address -> {
if (address.getShippingAddress() != null) {
return new FullCustomer(customer, address.getShippingAddress());
} else {
return new FullCustomer(customer);
}
});
}
return Uni.createFrom().item(new FullCustomer(customer));
});
return asyncResponse;
}
How can I rewrite my code so that it returns Uni keeping reactive ( async client ) calls

Got the solution. Thanks Ladicek for comments.
public Uni<FullCustomer> getFullCustomer(#PathParam("id") String customerID) {
return getCustomer(customerID)
.onItem()
.transformToUni(customer -> {
if (customer.getAddressId() != null) {
return getAddress(customer.getAddressId()).onItem().transform(address -> {
if (address.getShippingAddress() != null) {
return new FullCustomer(customer, address.getShippingAddress());
} else {
return new FullCustomer(customer);
}
});
} else {
return Uni.createFrom().item(new FullCustomer(customer));
}
});
}

Related

Xamarin IOS InAppBiling plugin how to get receipt-data

I use Plugin.InAppBiling for In-App Purchase ios. I want to know Purchase receipt data.
here is my code.
private async Task<bool> MakePurchase(string productId)
{
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync();
if (!connected)
{
return false;
}
var verify = DependencyService.Get<IInAppBillingVerifyPurchase>();
var purchase = await CrossInAppBilling.Current.PurchaseAsync(productId, ItemType.InAppPurchase, verify);
if (purchase == null)
{
return false;
}
else if (purchase.State == PurchaseState.Purchased)
{
if (Device.RuntimePlatform == Device.iOS)
{
Console.WriteLine("CHECK");
if(verify == null)
{
Console.WriteLine("null");
}
else
{
Console.WriteLine($"{verify}");
}
}
return true;
}
return false;
}
finally
{
await billing.DisconnectAsync();
}
}
The payment process goes well. but verify is just return null.
I understood verify as receipt-data. It's right?
How do I get a base64 encoded string receipt-data?
The documentation you also link to clearly states that you need to implement IInAppBillingVerifyPurchase yourself. There is no implementation of this in the plugin.
So you need to create your own class and register it in the IoC container:
[assembly: Dependency(typeof(MyIAPVerification))]
public class MyIAPVerification : IInAppBillingVerifyPurchase
{
// implementation here
}
Only then will your verify instance not be null.

Getting multiple Mono objects with reactive Mongo queries

I'm using the webflux framework for spring boot, the behavior I'm trying to implement is creating a new customer in the database, if it does not already exist (throw an exception if it does)
and also maintain another country code database (if the new customer is from a new country, add to the database, if the country is already saved, use the old information)
This is the function in the service :
public Mono<Customer> createNewCustomer(Customer customer) {
if(!customer.isValid()) {
return Mono.error(new BadRequestException("Bad email or birthdate format"));
}
Mono<Customer> customerFromDB = customerDB.findByEmail(customer.getEmail());
Mono<Country> countryFromDB = countryDB.findByCountryCode(customer.getCountryCode());
Mono<Customer> c = customerFromDB.zipWith(countryFromDB).doOnSuccess(new Consumer<Tuple2<Customer, Country>>() {
#Override
public void accept(Tuple2<Customer, Country> t) {
System.err.println("tuple " + t);
if(t == null) {
countryDB.save(new Country(customer.getCountryCode(), customer.getCountryName())).subscribe();
customerDB.save(customer).subscribe();
return;
}
Customer cus = t.getT1();
Country country = t.getT2();
if(cus != null) {
throw new CustomerAlreadyExistsException();
}
if(country == null) {
countryDB.save(new Country(customer.getCountryCode(), customer.getCountryName())).subscribe();
}
else {
customer.setCountryName(country.getCountryName());
}
customerDB.save(customer).subscribe();
}
}).thenReturn(customer);
return c;
}
My problem is, the tuple returns null if either country or customer are not found, while I need to know about them separately if they exist or not, so that I can save to the database correctly.
country == null is never true
I also tried to use customerFromDB.block() to get the actual value but I receive an error that it's not supported, so I guess that's not the way
Is there anyway to do two queries to get their values?
Solved it with the following solution:
public Mono<Customer> createNewCustomer(Customer customer) {
if(!customer.isValid()) {
return Mono.error(new BadRequestException("Bad email or birthdate format"));
}
return customerDB.findByEmail(customer.getEmail())
.defaultIfEmpty(new Customer("empty", "", "", "", "", ""))
.flatMap(cu -> {
if(!cu.getEmail().equals("empty")) {
return Mono.error(new CustomerAlreadyExistsException());
}
return countryDB.findByCountryCode(customer.getCountryCode())
.defaultIfEmpty(new Country(customer.getCountryCode(), customer.getCountryName()))
.flatMap(country -> {
customer.setCountryName(country.getCountryName());
customerDB.save(customer).subscribe();
countryDB.save(country).subscribe();
return Mono.just(customer);});
});
}
Instead of doing both queries simulatneaously, I queried for one result and then queries for the next, I think this is the reactive way of doing it, but I'm open for corrections.

how to return an exception from async in asp.net webapi

I have a WebAPI2 mvc app where I'm doing Get/Post to another api. My code looks like below
public Task<SomeEntity> AddAsync(SomeEntity someEntity)
{
try
{
var response = apiService.PostItem(url, someEntity);
if (response == null || response!="Successful")
{
throw new InvalidOperationException(response);
}
}
catch (Exception ex)
{
_logger.Error("Error " + ex.Message);
// how to return this error or exception;
}
return Task.FromResult(someEntity);
}
If the call to the internal api return an exception string then I need to forward it from this method call. Any ideas how can I do it? thanks
You can use IHttpActionResult or HttpResponseMessage as your return type and return proper HTTP-Status codes. In case of exception you can return [if you return IHttpActionResult ]
public IHttpActionResult Error()
{
var error = new HttpError();
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.BadRequest, error));
}
or as in your example, throw HttpResponseException with appropriate status code.
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var message = string.Format("Product with id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
}
else
{
return item;
}
}

Get HttpHeaders from HttpRequestException?

I have a Web API, When the incoming request is not valid then the API sends back a HttpStatusCode.BadRequest and API would also add a CorrelationId into Response's HttpHeader. Something like below
public class ValidateRequestAttribute : ActionFilterAttribute
{
public ValidateRequestAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid == false)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.HttpContext.Response.Headers.Add("x-correlationid", "someid");
context.Result = new ContentResult()
{
Content = "bad request."
};
}
}
}
On client side im using HttpClient to access the API. I am not sure how client would retrieve HttpStatusCode and HttpHeader here. Here is my client code
public bool Process(url)
{
bool result = false;
try
{
Task.Run(async () => await _httpClient.GetStringAsync(url).ConfigureAwait(false)).Result;
}
catch (Exception ex)
{
if(ex is AggregateException)
{
var aggregateException = ex as AggregateException;
foreach(var innerException in aggregateException.InnerExceptions)
{
if (innerException is HttpRequestException)
{
var httpRequestException = innerException as HttpRequestException;
// how do i get StatusCode and HttpHeader values here??
}
}
}
}
return result;
}
I have already gone through SO post here and MSDN article here and also Stephen Cleary's article here
Even though its recommended to make async all the way down, I this case Client and API are both disconnected from each other and client is synchronous. Note that Client's Process method is synchronous method.
Like this:
public bool Process(string url)
{
var result = _httpClient.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
if (result.StatusCode == HttpStatusCode.BadRequest)
{
IEnumerable<string> values;
if (result.Headers.TryGetValues("x-correlationid", out values))
{
// Should print out "someid"
Console.WriteLine(values.First());
}
}
return result.IsSuccessStatusCode;
}
Also note that doing .GetAwaiter().GetResult(); vs .Result; is recommended since it makes the code easier to work with because it does not throw an AggregateException.
If you want to read the response content as a string just do:
var content = result.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
If you want to make your code async though you should use the async/await keyword and skip the .GetAwaiter().GetResult();.

How do I Get with using string parameter?

I currently have a web api Get method using EF6 and it is accepting an int parameter called serial. Instead of the primary key serial I want to find extserial from the URI.
Here is my Get where I have localhost/api/AH?serial=1
// GET api/AH/5
[ResponseType(typeof(Transmital))]
public IHttpActionResult GetTransmital(int Serial)
{
Transmital transmital = db.Transmitals.Find(Serial);
if (transmital == null)
{
return NotFound();
}
return Ok(transmital);
}
I need to have it get by localhost/api/AH?ExtSerial=ABC123
For some reason it won't take the following
// GET api/AH/5
[ResponseType(typeof(Transmital))]
public IHttpActionResult GetTransmital(string ExtSerial) //or [FromUri]string ExtSerial
{
Transmital transmital = db.Transmitals.Find(ExtSerial);
if (transmital == null)
{
return NotFound();
}
return Ok(transmital);
}
You should use IHttpActionResult interface.
Try this:
public IHttpActionResult GetTransmitalsExtSerial([FromUri] string ExtSerial)
{
//return Ok(ExtSerial.ToString());
return Ok(db.Transmitals.Where(exs => exs.ExtSerial == ExtSerial));
}

Resources