I am somehow trying to get the status (error,success) after paying through the UPI app. I already end up in the onAdditionalDetails() function but here I somehow don't have the possibility to query the status. Is there maybe something needed to get this information in the state object?
async initAdyen_newurl() {
let config = null;
config = {
...this.config.adyenConfig,
onPaymentCompleted: (result, component) => {
console.info("onPaymentCompleted");
console.info(result, component);
},
onError: (error, component) => {
console.error("onError");
console.error(error.name, error.message, error.stack, component);
},
onAdditionalDetails: (state, component) => {
const actionUrl = "hardcoded for the moment"
const obj = {
paymentMethodType: component.props.paymentMethodType,
url: actionUrl,
method: "post",
type: "redirect",
paymentData: component.props.paymentData
}
component.props.createFromAction(obj, {}).mount("#id");
},
};
AdyenCheckout(config)
.then((checkout) => {
// init stuff
})
.catch((error) => {
console.error(`url failure ${error.message}`);
});
},
I can also redirect to the next page using createFromAction(), but this just happens in both Success and Error. However, this should only happen in Success. I hope that was somehow understandable. Many Thanks
edited: i am using version 5.23.0
The flow involves an additional step (3DS) so the onAdditionalDetails handler is invoked. From there you can add an extra call to /payments/details to fetch the payment status.
The response includes the resultCode to inform the shopper of the payment status.
Here is an example:
...
onPaymentCompleted: (result, component) => {
handleServerResponse(result, component);
},
onAdditionalDetails: async (response, _component) => {
// call server
const paymentDetailsResponse = await callServer("/api/paymentDetails", response);
// obtain payment status
const result = paymentDetailsResponse.resultCode
},
onError: (error, component) => {
console.error(error.name, error.message, error.stack, component);
}
// Calls your server endpoints
async function callServer(url, data) {
const res = await fetch(url, {
method: "POST",
body: data ? JSON.stringify(data) : "",
headers: {
"Content-Type": "application/json",
},
});
In the backend perform the paymentsDetails call to obtain the Payment status from the Adyen platform:
// Check payment result
app.post("/api/paymentDetails", async (req, res) => {
try {
const response = await checkout.paymentsDetails({
details: req.body.data.details,
paymentData: req.body.data.paymentData,
});
res.json(response);
} catch (err) {
console.error(`Error: ${err.message}, error code: ${err.errorCode}`);
res.status(err.statusCode).json(err.message);
}
});
See Confirm an additional action on your server
Related
updateTagCurrentValue: builder.mutation<any, {path: string, body: updateTagCurrentValueBody}>({
query: (args) => {
const {path, body} = args
return ({
url: `/v2/tags/${path}/values/current`,
method: 'PUT',
body: body,
})
},
transformResponse: (response) => {
return response
}
})
I am new in RTK, this mutation is working well, but I can not understand how to get a response from server? I see it in inspect network tab, I see my added data in the server, but the response comes null
const [updateTagCurrentValue, {error, isSuccess}] = useUpdateTagCurrentValueMutation()
const onSubmit: SubmitHandler = async (data) => {
let body: updateTagCurrentValueBody = {
value: {value: JSON.stringify(data)}
}
try {
let response = await updateTagCurrentValue({path: 'test', body}).unwrap();
console.log(response)
} catch (err) {
console.log(err)
}
}
I searched for solutions, and some people said add .unwrap() at the end of the call, but it didn't help. transformResponse also changes nothing, isSuccess changes from false to true after the second submission...
I have an API (let's call it getToken) to generate a token in its response body. I then call that token and store in the header of another API (let's call it returnBody). It makes sense to use localStorage for the getToken API as this token is re-usable for multiple API's. However, I am having doubts using localStorage if I need to return / display the response body of the succeeding API's such as returnBody. Inside the API's function/command, it logs the response body. However, when I call it via the test file, it generates null.
Sample code below:
commands.js:
Cypress.Commands.add('getToken', () => { //API to generate token
cy.request({
method: 'POST',
url: 'https://someAPItoGenerateToken',
form: true, //sets to application/x-www-form-urlencoded
body: {
grant_type: 'credentials',
scope: 'all-apis'
},
auth: {
username: Cypress.env('api_username'),
password: Cypress.env('api_password')
}
})
.its('body')
.then(bearerToken => {
cy.setLocalStorage('bearerToken', JSON.stringify(bearerToken))
cy.log('Token generated: ' + bearerToken.token)
}
)
})
Cypress.Commands.add('returnBody', (url, token) => { //API to return some values
return cy.request({
method: 'GET',
url: url,
auth: {
bearer: token
}
})
.then((response) => {
// Stringify JSON the body.
let body = JSON.stringify(response.body)
cy.log(body)
})
})
test file:
describe('Return value of 2nd API', ()=> {
before(() => {
cy.getToken() //Run this once to generate token for the entire test suite
cy.saveLocalStorage()
})
beforeEach(() => {
cy.restoreLocalStorage()
})
it('Return value of 2nd API', () => {
cy.getLocalStorage('bearerToken').should('exist')
cy.getLocalStorage('bearerToken').then(bearerToken => {
const tokenJSON = JSON.parse(bearerToken)
const url = 'https://someAPItoReturnJSONbody'
cy.returnBody(url, tokenJSON.token).then((returned_value) => {
cy.log(returned_value)
})
})
})
})
body from the returnBody command returns the JSON response. However, returned_value from the test file displays null.
As commented in this issue: "You cannot return a 3rd party promise from a custom command because this breaks the chaining between cypress commands. This is because the .then methods are not the same."
So, simply return the request body as:
Cypress.Commands.add('returnBody', (url, token) => {
return cy.request({ /* options */ })
.its("body");
});
Then, in your test you can do:
it("should return foo value", () => {
cy.returnBody(url, token).then(returned_value => {
cy.log(returned_value);
expect(returned_value).to.deep.equal("foo-value");
})
})
You may need to return response body from your returnBody task:
Cypress.Commands.add('returnBody', (url, token) => {
return cy.request({ /* options */ })
.then(response => {
let body = JSON.stringify(response.body);
Cypress.log(body);
return body; // Add this line
});
});
An alternative would be to store the token on cypress side using fixtures.
fixture.json:
{"bearerToken":""
.
.
.}
commands.js:
cy.fixture('testData.json').as('testData')
.
.
.then(bearerToken => {
this.testData.bearerToken = JSON.stringify(bearerToken)
cy.log('Token generated: ' + bearerToken.token)
}
)
test.js
describe('Return value of 2nd API', ()=> {
before(() => {
cy.getToken() //Run this once to generate token for the entire test suite
})
it('Return value of 2nd API', () => {
cy.fixture('testData.json').as('testData')
.then(testData => {
const tokenJSON = JSON.parse(testData.bearerToken)
const url = 'https://someAPItoReturnJSONbody'
cy.returnBody(url, tokenJSON.token).then((returned_value) => {
cy.log(returned_value)
})
})
})
})
I am stuck on one of the mysterious issue. The problem goes like this:
What I Do??
Simply do login api call and if login success then I have to fetch amount of data from 5-6 api calls and store them in local database (Realm). Here is my code.
login(email, password) {
this.toggleLoadingFunction(true);
fetch(LoginURL, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
request_from: 'mobile'
}),
})
.then(async res => {
if (res.ok) {
let data = await res.json();
global.user = data['user']
global.token = data['token']
getAllMasterDataAndSaveInRealm().then(() => {
this.toggleLoadingFunction(false);
global.storage.save({ key: 'LoggedInData', data: data });
this.props.navigation.navigate('Project', data);
}).catch(() => {
this.toggleLoadingFunction(false);
Alert.alert("Master Data Failed !!!");
})
} else {
this.toggleLoadingFunction(false);
let data = await res.json();
Alert.alert("Login Failed!!!", data.message)
}
})
.catch(error => {
this.toggleLoadingFunction(false);
Alert.alert("Network Error. Please try again.")
})
Here getAllMasterDataAndSaveInRealm() is lies on helper function which calls 5-6 apis and response back if all work is done. Here is how it looks like:
export const getAllMasterDataAndSaveInRealm = () => {
const token = global.token;
return new Promise.all([
getMaterials(token),
getEquipments(token),
getObjective(token),
getCategories(token),
getNcData(token),
getPlans(token)]
);
}
Each function inside getAllMasterDataAndSaveInRealm() returns Promise after successfully stored data in local realm db. Here is one of the above function.
export const getActivityPlan = (token) => {
return new Promise((resolve, reject) => {
return fetch(FetchActivityPlanDataURL, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'access_token': `${token}`
}
}).then((response) => {
console.log("Activity Plans Api response", response);
return response.json()
})
.then((responseJson) => {
const { data } = responseJson
console.warn("Activity Plans Api", data);
global.realm.write(() => {
for (var item of data) {
item.id = item.id ? item.id : 0;
item.activity_id = item.activity_id ? item.activity_id.toString() : "";
item.activity_name = item.activity_name ? item.activity_name.toString() : "";
item.activity_cost = item.activity_cost ? item.activity_cost.toString() : "";
item.project_id = item.project_id ? item.project_id : 0;
global.realm.create("ActivityPlan", item, true);
}
})
resolve(data);
})
.catch((error) => {
reject(`Activity Plan Failed ${error}`)
});
})
}
All remaining functions are same as above ( what they do is simply fetch data from api and store it in realm and resolve or reject)
What I Expect:
getAllMasterDataAndSaveInRealm() function Just store all the required data in db and let me know all done and then navigate to the another screen, as Login and fetching data is done.
Problem:
When I do run the app and process for login, Sometimes it works fine but most of the time App stuck on showing loader since some of the api call among 6 api from above do not get response from the request ( I do log the response) on wifi. But when I use mobile data and VPN it always works.
When I log request on server console, response is sent with code 200, but app is unable to get response for the request.
I am new on react native. I do lots of searches over internet but unable to find the solution. I don't have any idea whats going wrong with the code. Please help me out.
Project Configurations:
"react": "16.8.6",
"react-native": "0.60.4",
"realm": "^2.29.2",
Node version: v9.0.0
I am building a todo-list like feature which adds a task when Enter is pressed on an input task field. The Enter calls an API (add Task) which takes approx 200ms to execute. Since this is blocking call it hinders my code to execute fully and affects the usability of my system. Here is a code example of what I am trying to achieve.
handleChange (event) {
if (e.key === 'Enter') {
targetTaskId = e.target.getAttribute("data-downlink")
this.props.addTask(this.props.currentProject.id, '', '', taskId, this.props.currentTasks) //this function calls an add Task API which halts my system momentarily
targetSelector = targetTaskId
$('#' + targetSelector).focus()
this.setState({activeTask: targetSelector})
highlightActiveComponent(targetTaskId)
}
}
//addTask
export function addTask (project_id, taskName, taskNotes, upLink, taskList) {
console.log('Add Task API call', project_id, taskName, taskNotes, upLink)
return (dispatch) => {
callApi('tasks?projectId=' + project_id + '&name=' + taskName + '¬es=' + taskNotes + '&upLink=' + upLink, 'post')
.then(res => {
console.log('Response new task ', res)
let newTask = {name: res.name, id: res.id, notes: res.notes, upLink: upLink, projectId: project_id, assignee: 0, completed: 0, tags: [], isLiked: false, stories: [], likes: [], downLink: res.downLink}
let newTaskList = addTaskToTaskList(taskList, upLink, newTask)
dispatch(updateTasks({currentTasks: newTaskList}))
dispatch({ type: 'SET_ACTIVE_TASK_ID', payload: res.id })
})
}
}
//Fetch
export const API_URL = 'https://clients.rohan.axcelmedia.ca/v1'
export default function callApi (endpoint, method = 'get', body) {
let headers = {
'Accept': 'application/json',
'Content-Type' : 'application/json'
}
if (auth.loggedIn()) {
headers = _.merge(headers, {
Authorization: `Bearer ${auth.getToken()}`
})
}
return fetch(`${API_URL}/${endpoint}`, {
headers,
method,
body: JSON.stringify(body)
}).then(response => {
return response
}).then(response => response.json().then(json => ({ json, response })))
.then(({ json, response }) => {
if (!response.ok) {
return Promise.reject(json)
}
return json
})
.then(
response => response,
error => error
)
}
Add Task to tasklist
export function addTaskToTaskList(tasks, upLink, newTask){
updateTaskDownLink(tasks, newTask.upLink, newTask.id)
updateTaskUpLink(tasks, newTask.downLink, newTask.id)
if(upLink == 0){
tasks.unshift(newTask)
// console.log("Added in the start", tasks)
return JSON.parse(JSON.stringify(tasks))
}
let myIndex = getIndexOfTaskById(tasks, upLink)
console.log("Added the new task from helper", myIndex)
if (myIndex) {
console.log("Added the new task")
tasks.splice(myIndex + 1, 0, newTask);
// console.log("New Task List", JSON.parse(JSON.stringify(tasks)))
}
return JSON.parse(JSON.stringify(tasks))
}
export function updateTaskUpLink(tasks, taskId, upLink){
tasks.forEach(function(element, index) {
if(element.id == taskId) { element.upLink = upLink }
});
return tasks
}
export function updateTaskDownLink(tasks, taskId, downLink){
tasks.forEach(function(element, index) {
if(element.id == taskId) { element.downLink = downLink }
});
return tasks
}
My question is, is there anyway to call this API in a non-blocking fashion so that my code continues to execute and when the response from the api is received my cursor moves to the new task in a seamless manner.
Any help would be appreciated. Thankyou
[EDIT] : Added fetch function to demonstrate the async calls
You should use something like Fetch API for call the API in a non-blocking way:
fetch("/api/v1/endpoint/5/", {
method: "get",
credentials: "same-origin",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
}).then(function(response) {
return response.json();
}).then(function(data) {
console.log("Data is ok", data);
}).catch(function(ex) {
console.log("parsing failed", ex);
});
console.log("Ciao!");
The code that shows data in the snippet will be executed only when some data is returned by the server.
This means that in my example the log "Ciao!" will be showed before "Data is ok: ..."
Hope this helps :)
credits for the snippet: https://gist.github.com/marteinn/3785ff3c1a3745ae955c
First of all return JSON.parse(JSON.stringify(tasks)) is redundant, you can just return tasks right there, that will probably fix your speed problem alone. But incase it doesn't.
Your code might be blocking due to this type of thing here
tasks.forEach(function(element, index) {
if(element.id == taskId) { element.upLink = upLink }
});
return tasks
You iterate over the tasks array for updateTaskDownLink, again for updateTaskUpLink and probably again for getIndexOfTaskById, this is a lot of needless iteration.
Instead of searching through an array of tasks over and over, you should structure your tasks in a map
tasks = {
"someTaskId": {
id: "someTaskId",
upLink: "uplink stuff",
downLink: "downlink stuff"
}
}
This way when you go to update the task its really simple and really fast
tasks[taskId].upLink = upLink or tasks[taskId].downLink = downLink
No iterating, no blocking, no problem.
Also, this data structure will make getIndexOfTaskById obsolete! because you already have the key needed to access that task! Hooray!
If you're wondering how to iterate over your tasks structured as a map like that see here
So I have a React Native app, making calls to my own external api via the fetch() native API. I am encountering a strange issue with my requests not being processed by fetch() correctly in only one context.
The calls are supposed to POST to /api/token_login.
Here is how I make my calls in the app:
#/src/services/post.js
import headers from './headers';
const APIURL = '******/api';
export default async (path, data, callback) => {
try {
const postData = {
method: 'POST',
credentials: 'include',
headers: new Headers(headers),
body: JSON.stringify(data)
};
const requestURL = `${APIURL}/${path}`;
const request = new Request(requestURL, postData);
const response = await fetch(request);
const res = await response.text();
if (response.ok) {
callback(null, res);
} else {
const error = res;
callback(error, null);
}
} catch (error) {
console.log('caught error: ', error);
}
};
#/src/services/auth.js
import post from './post';
export function TokenLogin(data, callback) {
post('token_login', data, callback);
}
...other functions
#/src/containers/Login.js
const data = {
user: {
auth_token: token,
},
};
return TokenLogin(data, (err, response) => {
const res = JSON.parse(response);
... do stuff
};
This function gets called on componentDidMount under certain conditions, which is the expected behavior. However, every day or so it suddenly stops sending the request to the passed in path, and sends a GET to /api/login instead. Changing the path passed into the function changes the behavior back to the expected one (i.e., passing in flurgl sends a POST request to .../api/flurgl with the body passed in correctly. Here is some debugging info:
// the logs:
=> Request method: POST url: https://*****/api/token_auth
=> Response object:
=> Response {type: "default", status: 404, ok: false, statusText: undefined, headers: Headers, …}
bodyUsed: true
headers: Headers {map: {…}}
ok: false
status: 404
statusText: undefined
type: "default"
url: "https://*******/api/login"