Zapier custom response object - javascript

Working on creating a custom zapier integration using zapier CLI. My API endpoint is not technically a create, but it uses the POST method so I made it under the create definition in zapier. I set my output fields to empty, but it breaks on my empty response object.
outputFields: []
The error message:
We had trouble sending your test through.
Unexpected end of JSON input
Hide details
Troubleshooting Errors | Contact Support
What happened (You are seeing this because you are an admin):
Starting POST request to https://api.fake.com/v2/demo-finance/live/csh-search
Received 202 code from https://api.fake.com/v2/demo-finance/live/csh-search after 596ms
Received content ""
Unexpected end of JSON input
Everything is working as expected the request went through it is just not happy with the empty string response not being valid JSON. Is there some way to tell zapier this is an acceptable response object?

David here, from the Zapier Platform team.
It's fine if your API works that way, but you still need to return something json serializable from your function. Try something like this:
const performCreate = async (z, bundle) => {
const response = await z.request('https://api.fake.com/v2/demo-finance/live/csh-search')
if (response.statusCode === 202) {
return {}
}
// handle errors, other cases, whatever
// just make sure to return an object
}
As a side note, just because the request uses a POST request doesn't mean it needs to be a Create; it should be whatever type makes the most sense for the operation. If it's a search (like the fake url suggests) a search is probably the way to go.

Related

POST Request to PUT Request

"
An open source course that I am taking has the following prompt for fullstack development:
3.17: Phonebook database, step5
If the user tries to create a new phonebook entry for a person whose name is already in the phonebook, the frontend will try to update the phone number of the existing entry by making an HTTP PUT request to the entry's unique URL.
Modify the backend to support this request.
Verify that the frontend works after making your changes."*
It appears that this would call for an express app.put request called inside on an app.post request. Is there something that I'm missing here? How you handle this kind of logic with mongoDB/mongoose/expresss? My current post code is pasted below.
Thanks
app.post('/api/persons',(req,res) => {
const body = req.body
const containsNameNumber = body.name && body.number
if(!containsNameNumber){
return res.status(400).json({
error:"must specify a name and a number"
})
}
const phone = new Person({
name: body.name,
number:body.number
})
phone.save().then(savedPerson => {
res.json(savedPerson)
})
})
I think you are missunderstanding one thing, check PUT definition from RFC7231
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload
Is importante the part "be created". So with a PUT if the resource exists it will be updated but if not exists will be created.
If the target resource does not have a current representation and the
PUT successfully creates one, then the origin server MUST inform the
user agent by sending a 201 (Created) response.
So you only have to do a PUT call and check if exists to update (return 200 Ok) or not exists to create (return 201 Created).

How to return multiple updates of a JSON using expressjs and nodejs

I have a server side task that takes some time to compute, and I'd like to periodically send updates to the client. I store and send the information as an object (via JSON), and it isn't an array where I can send data sequentially. Rather, I want to send some new information, and update others as the calculation continues.
From other posts on here I realize that:
response.json(object) is a nice and easy way to send an object json in one go, with headers set and everything. However, this - like response.send() - terminates the connection:
var app = express()
app.get('/', (request, response) => {
response.json( { hello:world } );
})
Alternatively, one could set the headers manually, and then use response.write with JSON.stringify
response.setHeader('Content-Type', 'application/json');
response.write(JSON.stringify({ hello:world } ));
response.end();
The above two methods work for sending an object in one go, but ideally what I'd like to do is send incremental updates to my object. E.g.
response.setHeader('Content-Type', 'application/json');
response.write( JSON.stringify( { hello:[world], foo:bar } ) );
// perform some operations
response.write( JSON.stringify( { hello:[world, anotherWorld], foo:cat } ) );
response.end()
However, what is happening on the clientside is:
After the first response.write, the client receives { hello:[world], foo:bar } but does not trigger my callback
After the second response.write, I can see the data received is { hello:[world], foo:bar }{ hello:[world, anotherWorld], foo:cat } still does not trigger my callback
My callback is only called after response.end(), and then I get an exception when trying to parse it as JSON, because it isn't a valid JSON anymore, but a bunch of JSONs stuck back to back with no comma or anything: Uncaught (in promise) SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column XXX of the JSON data.
Ideally my client callback would be triggered upon receiving each write, and it would remove that bit of data from the buffer so to speak, so the next incoming json would be standalone.
Is what I want to do possible? If so, how?
My fetch code btw:
fetch(url)
.then(response => response.json()) // parse the JSON from the server
.then(returnInfo => {
onReturn(returnInfo);
});
For your use-case, you can consider using WebSockets to deliver incremental updates to your UI. There are 3 stages of WebSockets connections. Connect, message and disconnect. One page load your front-end maintains persistent connection with backend. You can send first JSON data on connect and then when your backend has updates, send data in your message call back. I have written a blog post that implements WebSockets using Python and Javascript. However, you can implement similar logic using NodeJS
https://blog.zahidmak.com/create-standalone-websocket-server-using-tornado/

why is that making GET request with search param won't return 404 even when the no resources have been found

I encountered this weird problem when experimenting with JavaScript's URL object
here is the demo : https://codesandbox.io/s/fervent-wilbur-15kyt?file=/src/index.js
so the endpoint is https://jsonplaceholsdsdsdder.typicode.com/todos/,
The key id can be integer as its value. So https://jsonplaceholder.typicode.com/todos/?id=4 is valid. and https://jsonplaceholder.typicode.com/todos/?id=dsdsd is not valid.
I found that using Fetch to make the request https://jsonplaceholder.typicode.com/todos/?id=4 will still return a response with a status code 200.
const inputEl = document.querySelector("#input");
const endpoint = new URL("https://jsonplaceholder.typicode.com/todos/");
inputEl.addEventListener("input", async e => {
const { value: text } = e.target;
endpoint.searchParams.set("id", text);
const repsonse = await fetch(endpoint).catch(console.error);
const data = await repsonse.json();
console.log(repsonse.status); // 200
console.log(data); // []
});
However if we construct the URL directly like this
https://jsonplaceholsdsdsdder.typicode.com/todos/dd. this will actually return a response with 404 status code.
search params are not a part of the resource location. They are optional and have to be manually accessed by the server processing the request.
https://jsonplaceholder.typicode.com/todos/ is a valid resource location that has been set up by jsonplaceholder.com.
https://jsonplaceholder.typicode.com/todos/?id=4 is a valid resource location because anything after the question mark (?) is a parameter and parameters are not considered to be apart of the resource location so it is still valid.
https://jsonplaceholsdsdsdder.typicode.com/todos/dd is not a valid resource location because jsonplaceholder.com has not exposed a resource with that path.
This is because of the way the API works server side.
If you try and use that route, you'll get the 404 error because that specific route wasn't found.
If you use the searchParams.set method, it's just a parameter that the backend will use to filter the full list of todos, in which case the call was made successfully, hence the 200 response code. but the response results were empty, hence the empty array [].

Missing field in Apollo GraphQL Query

I'm using react with Apollo and a F# backend.
When i make a query i get an error similar to this but i'm not sure why as it seems like stories is present in the response.
Missing field stories in "{\"stories\":[{\"name\":\"Story1\",\"__typename\":\"Story\"},{\"name\":\"Story2\",\"__typename\":\
My code for making the query is:
const client = new ApolloClient({
uri: '/graphql',
});
client
.query({
query: gql`
query testStoryQuery
{
stories
{
name
}
}
`
})
.then(result => console.log(result));
Finally the raw response returned by the server is:
{"data":"{\"stories\":[{\"name\":\"Story1\",\"__typename\":\"Story\"},{\"name\":\"Story2\",\"__typename\":\"Story\"},{\"name\":\"Story3\",\"__typename\":\"Story\"}]}"}
The only thing I've tried so far is jsonifying the response (i.e. the ") around fields, but it doesn't seem to find the field either way.
Update (extra info)
The full stack trace
Any help would be appreciated, i'll continue working on it in the meantime.
Thank you :)
Bad response format:
{"data":____"____{\"stories\":[{\"name\":\"Story1\",\"__typename\":\"Story\"},{\"name\":\"Story2\",\"__typename\":\"Story\"},{\"name\":\"Story3\",\"__typename\":\"Story\"}]}____"____}
This way data is a string, not object.
Also bad names \r\n\t\t\t\t__typename in a stack trace.
For more details run some working example (any apollo client project) and compare arguments passed to writeToStore.ts methods using browser debugger breakpoints.

SyntaxError: Unexpected token < in JSON Aurelia

I'm using Aurelia to build a web application. I want to display a detail page passing a parameter (id) from the list view. This is my (simplified, "Detail" is basic data class) controler code:
[HttpGet("[action]")]
public IActionResult GetDetail(int _id)
{
var b = new Detail()
var customjson = JsonConvert.SerializeObject(b, Formatting.Indented);
return Ok(customjson);
}
The detail is fetched through the activate() method in the detail.ts class:
constructor(http: HttpClient) {
this.http = http;
}
activate(params: any) {
this.http.fetch("api/Begroting/GetBegroting/" + params.id)
.then(result => result.json as Promise<Begroting>)
.then(data => {
this.begroting = data;
console.log(data);
});
}
However when the detail page is loaded via the list page it gives this error:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0. Testing the API via Swagger yields valid json and a status code 200.
implying that there is something wrong with the API(call).
OP already solved his problem, but to clarify for future readers what was likely going on:
SyntaxError: Unexpected token < in JSON is an error that typically occurs when you request a non-existing resource. The server returns a standard 404 HTML error response.
The client will then fail when it tries to parse the HTML document as JSON (it's the first < of the <html> tag that it fails on).
The client needs a status code instead of an error page
The deeper issue here is that the server should really return a 404 status code response so the client knows that the request failed, and won't try to process it as if it succeeded. A 404 error html page is accompanied by a 200 status code, after all.
So besides fixing the request url on the client side (or the route on the server side), the server and/or client should be configured such that proper status codes are returned as well. I believe Accept: application/json takes care of this although I haven't tested that.
And an alternative solution for OP:
The idea behind RESTful services is that your URI's represent resources; the query string is nice for sorting/filtering/paging parameters and such on lists. An ID kind of belongs in the path, not in the query string.
Change your route attribute to: [HttpGet("[action]/{_id}")] and your initial client code should work again.
We made a call to api/Begroting/GetBegroting/_id instead of specifying id as a GET parameter. The result was that the call to the api rerouted us back to index.html. Hence the unexpected token < in JSON Aurelia error.
To fix it, change the API call to api/Begroting/GetBegroting/?_id= + params.id

Categories

Resources