I'm using RxAlamorefire to handle network task in my app.
My problem is: When I make a request and it return json. If json has a key "error" I need emit error notification instead of onNext notification.
My code is like this one:
let observable = RxAlamofire.json(.get, url, parameters: nil, encoding: URLEncoding.default, headers: header)
.map { (json) -> SomeObject? in
//Should check json maybe not in ".map" to see if the json contain "error" then emit onError notification.
return Mapper<SomeObject>().map(JSONObject: json)
}
Within map, you can use the throw keyword to send out and error
let observable = request.map { (json) -> SomeObject in
if let error = json["error"] as? [AnyHashable: Any] {
throw Mapper<ErrorObject>().map(JSONObject: error)
} else {
// regular deserialization
}
}
This will result in an observable emitting an error of type ErrorObject when the json contains the error key.
Related
We have a site example.com behind ssl that runs a page with ApplePay.
We've got a server side that returns a Merchant Session that looks like the following:
{"epochTimestamp":1581975586106,"expiresAt":1581979186106,"merchantSessionIdentifier":"SSH8E666B0...","nonce":"1239e567","merchantIdentifier":"...8557220BAF491419A...","domainName":"example.com","displayName":"ApplePay","signature":"...20101310f300d06096086480165030402010500308..."}
We receive this response in session.onvalidatemerchant as a string and convert it to a Json Object and pass to session.completeMerchantValidation.
As a result we get the following error:
Code: "InvalidAccessError"
Message: "The object does not support the operation or argument"
We run the following code on our page:
.....
session.onvalidatemerchant = (event) => {
const validationURL = event.validationURL;
getApplePaySession(validationURL).then(function (response) {
try {
let resp = JSON.parse(response);
session.completeMerchantValidation(resp);
} catch (e) {
console.error(JSON.stringify(e));
}
});
};
....
Additional questions:
Is the object described above a "correct" Merchant Session opaque that needs to be passed to completeMerchantValidation or it's missing some fields?
Is this object needs to be passed as is or it needs to be base64 encoded?
Does it need to be wrapped into another object?
Any help or lead is greatly appreciated.
I'm having trouble promises and observables. I have a handful of http requests which are defined in a package using promises. In the rest of my code I am using observables for various things, including other http calls. In one particular section I am checking to see if the user's bearer token is expired and if so then I get a new token and then proceed with the rest of the call.
if (!token || token.exp < Math.round((new Date()).getTime() / 1000)) {
from(this._store.refreshBearerToken())
.pipe(flatMap(resp => {
let newToken = resp.data;
newToken.exp = (new Date()).getTime() / 1000 + newToken.expires_in;
localStorage.setItem('token', JSON.stringify(newToken))
options = options || {};
options.headers = new HttpHeaders({
"Authorization": `${newToken.token_type} ${newToken.access_token}`,
"Content-Type": "application/json"
});
return this._http$.request<T>(method, url, options as Object).pipe(share());
}));
}
Bearer Token method:
async refreshBearerToken() {
const response = await this._q2.sources.requestExtensionData({
route: "refreshBearerToken"
});
console.log(response);
return response;
}
Since this._store.refreshBearerToken returns a promise I wrapped the call in a from to convert it to an observable. This compiles but when it runs I get "Cannot read property 'pipe' of undefined".
How can I convert this promise to an observable so that I can refresh the token and then continue with the rest of the call?
Edit:
I am importing from via import { Observable, from } from "rxjs";.
So, I thought the error was coming from the line .pipe(flatMap(resp =>... but I was wrong. The error is coming from the method which is calling this.
GetInitialLinkList(): Observable<Institution[]>
{
let base = { 'MemberId': localStorage.getItem('memberId') };
let ins = localStorage.getItem("initialInstitutionList");
if (ins)
{
return of(JSON.parse(ins));
}
return this._settingsService.get().pipe(
flatMap(settings =>
{
this._settings = settings;
return this._api.request<Institution[]>("Post", `${this._settings.mea}/GetInitialLinkList`, { body: base })
.pipe(
retry(1),
catchError(this.handleError)
)
.pipe(flatMap(instList =>
{
localStorage.setItem("initialInstitutionList", JSON.stringify(instList));
return of(instList);
}))
}));
}
and that is being subscribed to inside my component:
private GetLinkList()
{
this.showWaiting.emit(true);
this._data.GetInitialLinkList().subscribe((result) =>
{
this.initialList = result;
this.showWaiting.emit(false);
});
}
From what Brandon said (I forgot to return /facepalm...) I added the return so I have return from(this._store.refreshBearerToken()) which changed my error to
ERROR Error Code: undefined
Message: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
defaultErrorLogger # core.js:6014
Can you show the actual error and the line in the code that the error occurs on? Also show where and how you import from.
I notice your code snippet does not return the observable it builds up via from(...).pipe(...) nor does it subscribe to it. It might help to show how your code actually uses this observable.
I can't find info about it in anywhere...
Consider this very simple scenario...
<Mutation mutation={LOGIN_MUTATION}>
{(login, { data, loading, error }) => {
if (error) {
console.log(error)
}
I am receiving a string error message like...
Error: GraphQL error: ERROR_INVALID_LOGIN_PROVIDER
at new ApolloError (bundle.umd.js:92)
at MutationData.onMutationCompleted (react-hooks.cjs.js:636)
at react-hooks.cjs.js:559
at tryCallOne (core.js:37)
at core.js:123
at JSTimers.js:289
at _callTimer (JSTimers.js:146)
at _callImmediatesPass (JSTimers.js:194)
at Object.callImmediates (JSTimers.js:458)
at MessageQueue.__callImmediates (MessageQueue.js:366)
I can't take actions based on the error message formated in this way. ERROR_INVALID_LOGIN_PROVIDER could be ERROR_INVALID_PASSWORD, for example...
I need to take decisions based on the error messages. but I just receive a string containing the graphql error, the modules inside the js and a lot of information that's not important. Is there any way to receive the error message formatted imn a way that I can extract only the server error ?
This should be possible
error in your example should be an ApolloError with the possible GraphQLErrors or a NetworkError
(login, { data, loading, error }) => {
if (error) {
if (error.graphQlErrors && error.graphQLErrors.length > 0) {
// There are graphQL errors and there may be multiple but its always an array.
// You should handle it properly
const { message } = error.graphQLErrors[0]
console.log(message) // e.g. ERROR_INVALID_LOGIN_PROVIDER
} else if (error.networkError) {
// There may be a network error
const { message } = error.networkError
console.log(message) // e.g. NetworkError when attempting to fetch resource.
}
}
I have some web-enabled actions that are exposed through API Connect in IBM Cloud Serverless Functions.
Some of my actions use request-promises to call external REST services and I need to be able to catch an error and respond with an appropriate status-code to the caller.
Since the actions are web-enabled, the documentation indicates that I can use an annotated JSON to set the headers, status-code and body of the response. But it seems that, seems the API expects to always get a Content-Type=application/json, the response processor is failing to understand my annotations in the case of an error.
I tried the following without success:
let rp = require('request-promise');
function main(params){
//setup options
return rp(options).then(
res => {
return res;
}
).catch(
err => {
return { error: { statusCode:err.statusCode } }
}
);
}
Another variation:
let rp = require('request-promise');
function main(params){
//setup options
return rp(options).then(
res => {
return res;
}
).catch(
err => {
return { statusCode:err.statusCode }
}
);
}
The problem is that the status-code I always get is 200... I also tried to change the runtime to node8.0 without success.
Thanks!
I found the answer myself :)
In order to get the status-code and headers, one must set the field Response Content Type to `Use "Content-Type" header from action", while setting up the mapping between the API call and the action....
I am using Cycle library to access to my web service. This is the function I use for POST method:
func register(requestObj: AnyObject, completion: (result: Int) -> ()){
Cycle.post("someURL",
requestObject: requestObj,
requestProcessors: [JSONProcessor()],
completionHandler: {(cycle, error) in
var status = cycle.response.statusCode!
completion(result: status)
})
}
As you can see, I tried to pass the callback to get the status code. I tried to get the result in the below test function:
func test_RegRequest_UT002(){
var obj = ["email" : "testHTTP#gmail.com", "password" : "Test#123", "confirmpassword" : "Test#123"]
UserService.register(obj){ result in //Unexpected found nil while unwrapping an Optional value
println("This is the response code: \(result)")
}
}
I got it right when I first try function register in test with the help of expectationWithDescription. I guess the error above occurs when the test code trying to get the value but the closure has not received the response from server yet.
Please suggest me what should I do next in this situation? It is good if there is something can make the main thread wait until receiving response from web service.