I have two API calls, one is an input for the second, I'm defining them as two actions now, but I wonder if I can merge them together in one action, I couldn't find that in the documentation, is that possible? and how?
My case is that I have an action that creates an invoice and returns back its id, the id then is being passed to another API to confirm that invoice and returns back a pdf.
Should I encapsulate the APIs from the back-end? or does it work if I called the second API inside the "then" method:
const options = {
url: 'https://my.fastbill.com/api/1.0/api.php',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
params: {
},
body: {
'SERVICE': 'invoice.complete',
'DATA' : {
'INVOICE_ID': bundle.inputData.INVOICE_ID
}
}
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const results = response.json;
// Call the second API here
return results;
});
Yes you can use a hidden trigger to call the first action and pass the input into a dynamic dropdown , then use it along the other inputs to submit the final action.
https://platform.zapier.com/cli_tutorials/dynamic-dropdowns
Related
I am working on a trigger where I need to pull data from two API end points. The first endpoint is a contact from a database that retrieves an email address, then to obtain the details for that contact (email) I need to use another end point. once is /Subscriber and the other is /Subsriber/ {email}/ Properties.
I am wondering if I can use a variable to obtain all the data in one trigger, as I have is set up in separate triggers right now.
Here is the code for both
Subscriber:
url: 'https://edapi.campaigner.com/v1/Subscribers?PageSize=1',
method: 'GET',
headers: {
'Accept': 'application/json',
'X-API-KEY': bundle.authData.ApiKey
},
params: {
'ApiKey': bundle.authData.ApiKey
}
};
return z.request(options).then((response) => {
response.throwForStatus();
const result = z.JSON.parse(response.content);
result.id = result.Items;
return [result];
});
And Subscriber Properties
const options = {
url: `https://edapi.campaigner.com/v1/Subscribers/${bundle.inputData.email_address}/Properties`,
method: 'GET',
headers: {
'Accept': 'application/json',
'X-API-KEY': bundle.authData.ApiKey
},
params: {
'email_address': bundle.inputData.email_address,
'ApiKey': bundle.authData.ApiKey
}
}
return z.request(options).then((response) => {
response.throwForStatus();
const result = z.JSON.parse(response.content);
result.id = result.CustomFields;
return [result];
});
Any help is appreciated.
Yes, definitely possible! Unless your subscriber data actually needs to be a separate trigger (which is unlikely, since you probably just trigger off new contacts), it can just be a function. Try something like:
const subscriberPerform = async (z, bundle) => {
const emailResponse = await z.request({
url: "https://edapi.campaigner.com/v1/Subscribers?PageSize=1",
method: "GET",
headers: {
Accept: "application/json",
"X-API-KEY": bundle.authData.ApiKey, // does this need to be both places?
},
params: {
ApiKey: bundle.authData.ApiKey, // does this need to be both places?
},
});
// requires core version 10+
const email = emailResponse.data.email;
const emailDataResponse = await z.request({
url: `https://edapi.campaigner.com/v1/Subscribers/${email}/Properties`,
method: "GET",
headers: {
Accept: "application/json",
"X-API-KEY": bundle.authData.ApiKey,
},
params: {
email_address: bundle.inputData.email_address, // lots of duplicated data here
ApiKey: bundle.authData.ApiKey,
},
});
return [emailDataResponse.data.SOMETHING];
};
That's the general idea. These JS functions may not need to be triggers at all, depending on how you're using them.
One last note - you don't want to perform this extra lookup every time you poll for new contacts; that's wasteful. If you're doing that, check out dehydration.
I am creating an app in Rails with Reactjs. I want to pass the value of input field to the controller as a variable so that I can use that variable in def create. How can I do that with fetch?
Use fetch's POST request to your API backend endpoint of your :create method. Make sure that you include your variables in a params payload when POSTing.
Then in your controller, you can access your variables through params
EDIT:
From the fetch api docs example in using POST (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
postData('/your/api/endpoint', { data: 'yourData' }).then(res=> { console.log(res) });
Then in your controller, access { data: 'yourData' } through params like so:
def create
#data = params[:data]
// Do what you want with #data here
end
It's also best to whitelist your params first before using them in your controller.
I have a simple zapier integration built and it works perfectly. However, I'm adding dynamic fields. Again it all seems to work perfectly when I test the zap. My dynamic form fields appear just as I expected.
The problem is sending the value of those dynamic forms to my API. I am using the zapier console and when I configure the API request I am using the following:
Where body['custom_fields'] is supposed to send all my dynamic fields or even all of the fields. But when it hits my API custom_fields parameter is blank.
const options = {
url: 'https://example_url/endpoint',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.auth_token}`
},
body: {
'email': bundle.inputData.email,
'custom_fields': bundle.inputData
/**
I've tried the following with no luck:
'custom_fields': bundle.inputData.fields
'custom_fields': bundle.inputData.undefined
'custom_fields': bundle.inputData
*/
}
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const results = response.json;
// You can do any parsing you need for results here before returning them
return results;
});
Ok after a few days, it's the simplest answer.
Obviously an object can't be sent over params.
so instead of having
'custom_fields': bundle.inputData
I just add the whole object to the params and it takes care of all keys and values
params: bundle.inputData
Here is the full body
const options = {
url: 'https://apiendpoint.com',
method: 'POST',
headers: {
'Authorization': `Bearer ${bundle.authData.auth_token}`
},
params: bundle.inputData,
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const results = response.json;
// You can do any parsing you need for results here before returning them
return results;
});
You can use the spread operator ...bundle.inputData like explained in the doc:
https://platform.zapier.com/docs/input-designer#how-to-include-dynamic-fields-in-api-calls
const options = {
url: 'https://example_url/endpoint',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.auth_token}`
},
body: { ...bundle.inputData }
}
You can even namespace your request data like that:
body: {
request: { ...bundle.inputData }
}
NB : the spread operator raises a syntax error in Zapier code editor, but it works.
I'm integrating PayPal checkout with an e-com solution, where upon PayPal successfully creating PayPal order/payment, I carry out some server side processing which eventually returns a RedirectResult (with a URL for payment failed or success accordingly) from my controller, back to the client/frontend.
I have the following code below, and was expecting it to redirect automatically, but no redirect occurrs.
paypal.Buttons({
createOrder: function (data, actions) {
return actions.order.create({
intent: "CAPTURE",
purchase_units: [{
amount: {
value: '5.20',
}
}]
});
},
onApprove: function (data, actions) {
return actions.order.capture().then(function (details) {
return fetch('/umbraco/surface/PayPalPayment/process', {
method: 'post',
redirect: 'follow',
body: JSON.stringify({
OrderID: data.orderID,
PayerID: data.payerID,
}),
headers: {
'content-type': 'application/json'
}
});
}).catch(error=>console.log("Error capturing order!", error));
}
}).render('#paypal-button-container');
If I explicitly redirect with the code below, then the action carries out.
onApprove: function (data, actions) {
return actions.order.capture().then(function (details) {
return fetch('/umbraco/surface/PayPalPayment/process', {
method: 'post',
redirect: 'follow',
body: JSON.stringify({
OrderID: data.orderID,
PayerID: data.payerID,
}),
headers: {
'content-type': 'application/json'
}
}).then(function () { window.location.replace('https://www.google.co.uk') });
}).catch(function (error) {
console.log("Error capturing order!", error);
window.location.replace('https://www.bbc.co.uk');
});
}
Basically, I'm wondering why fetch redirect does not follow the Redirect that is returned form my controller. Controller redirect for full completeness:
return new RedirectResult("/checkout/thank-you") ;
Let me try to rephrase your question
You want to know why the browser did not redirect after you made a fetch - even though fetch api response
was a RedirectResult
The reason is simple, you made a request in fetch, which means you are making ajax request (hence browser will not change)
you set the redirect to follow, which means after the first request (i.e after get response from
/umbraco/surface/PayPalPayment/process), it will follow to the url /checkout/thank-you
so, what you get in the then() will be the response of /checkout/thank-you
so overall, it did follow the response but maybe not the way you expected (follow within the ajax request, not browser changing the page)
If what you want is a redirect to specific page, after the success call to /umbraco/surface/PayPalPayment/process
Then do:
Modify your backend to return JsonResult of the url instead of RedirectResult
return Json(new {redirectUrl = "/checkout/thank-you"});
use then to redirect
// other code omitted
.then(function (response) { return response.json(); })
.then(function (data) {window.location.replace(data.redirectUrl)});
When I use dojo.xhrGet , I use it this way to send more than one parameter via the GET
dojo.xhrGet
({
url:"MyServerPageURL?Param_A="+"ValueA"+"&Param_2="+"Value2",
load: function(data)
{
//do something
},
preventCache: true,
sync: true,
error: function(err)
{
alert("error="+err);
}
});
How could I do similar thing (send more than one parameter) when I have to use the dojo.xhrPost instead?
You do not want to use postData parameter unless you want to send a raw POST string. You normally want to use the 'content' parameter. For example:
dojo.xhrPost({
url: 'http://whatever...',
contents: {
ParamA: 'valueA',
ParamB: 'valueB'
},
load: function(response) {
// ...
}
});
Note: Use 'contents' works for xhrGet also, eliminating the need to build up the query string yourself and append to the URL.
Try to use postData parameter.
E.g:
var myParameters= {"Param_A":"Value_A", "Param_B":"Value_B"};
var xhrArgs = {
url: "postIt",
postData: dojo.toJson(myParameters),
handleAs: "text",
headers: { "Content-Type": "application/json", "Accept": "application/json" },
load: function(data) {
},
error: function(error) {
}
}
var deferred = dojo.xhrPost(xhrArgs);
For xhrPOst, it's possible to mention the form name to be posted. thus all your form elements get posted. If you want to pass some additional parameter then use hidden variable in the form that is posted.