Recent searches


No recent searches

How Apps framework client.request works



Posted Mar 17, 2021

This is a continuing discussion about the article Making API requests from a Zendesk app in the developer documentation.


0

20

20 comments

Hi,

Thanks so much for this information.

For some reason, when I try to use the proxy service (by not specifying cors:true in the request), it doesn't work.

I can see in the network pane of the browser that indeed a request was made to the proxy service, but in my server I can see the incoming request and it does include an "origin" header.

What am I doing wrong?

Thanks,

Amos

0


This was moved to a ticket but to close out this conversation for others, headers that the browser passes to the proxy service are passed on to the eventual endpoint. So in this case, Chrome was passing ORIGIN to the proxy, which then passed it on.

0


Thanks Bryan for clearing this out, but I think I'm not following.

Wasn't the purpose of the proxy to allow us to make server side requests? So we can avoid the CORS issue?

I guess what I'm asking is:

1. What's the point of CORS:false if it still sends the origin header?

2. How do we make non-cors, server-side requests?

Thanks,

Amos

0


A CORS call is interesting (and can be confusing) in that it is actually the browser that determines if the final response received should be rendered. 

In other words, it is the browser that determines if the call's response should be rendered or not based on primarily these two points 1) different origin was called 2) Access-Control-* headers received in the response and their values.

With cors:false, the call is made via a backend proxy, not directly from the browser. Thus, the proxy does not care about where the call is going or what Access-Control-* headers it gets back. It just makes the call, receives the response, then passes it back to the browser. Kind of like if you were making the call from a tool such as cURL on the command line -- there is no concept of origin in that context. 

And since the call from the browser to the proxy (when setting cors:false) is *same origin*, there is no possibility of a CORS failure. So with this feature, you can make calls to other services that typically wouldn't allow a direct cross-origin call from a browser.

As a side note, if you are making API calls directly from a browser (and not through a proxy), this article might also be helpful: CORS Troubleshooting

The bottom line is that, if you have a remote server that typically doesn't allow cross-origin calls, you might be able to work around the limitation by going through a proxy. The free proxy that Zendesk Apps framework provides helps facilitate that kind of scenario.

0


Hi @...,

I don't understand the point of the proxy if it mimics the browser request.

The whole idea of the proxy is to be able to avoid CORS checks. This is what this article is all about.

Correct me if I'm wrong, but the origin header is what makes the request a CORS request. It doesn't matter who sends it - whether it's the browser or a server. The server that receives the request thinks it comes from a browser if it has that origin header.

If Zendesk server also send this header - how can we avoid or get around CORS?

Thanks,

Amos

0


@... - In addition, when the browser is detecting a post request to a different domain, it first preflight the request with an OPTIONS verb request - does that mean Zendesk proxy is doing the same?

Again, from my understanding, the purpose of the proxy (cors:false) is to get over a cors request. But if the proxy does exactly what the browser is doing (adding origin header and sending an OPTIONS request) - how is this helping in that?

I think the point is that when we're using ZAF's request option, and tell it all the details of our request, it should be sent to the proxy and from there to the our endpoint as we asked it to be - so if we asked for a POST request without an origin header, don't add one... no?

0


Hi Amos. It's browsers on their own that will create OPTIONS calls. Since the API call is coming from our backend proxy service (not a browser), there will be no OPTIONS call.

Also, the proxy just passes the ORIGIN header through if it receives it. It won't add it on its own. I think the point to clarify is that the initial call to our proxy is coming from a browser. So despite an ORIGIN header not being explicitly added in your code, the browser will add it automatically. That's not Zendesk doing it, it's the browser.

Edit: And as far as the call from the front-end browser to the back-end proxy, those are in the same domain. The browser will not generate an OPTIONS call on the same domain.

0


OK, so please tell me if I got this right or if I missed something - the request from the browser to the proxy is SAME ORIGIN, *but* if you use a "post" request, then, according to the specs, this now becomes a CORS request. The browser won't send the OPTIONS preflight, but it will add the ORIGIN header.

Your server will send this to the remote server, which might only support backend requests and not CORS request. So when the request will get back to the proxy and to the browser, it will not have the CORS needed headers, and the browser will block it.

Am I correct in all this?

How can we then make non-CORS POST requests? Can Zendesk ignore the ORIGIN header when cors:false is used (even though the browser do send one)? And if so - will that solve the problem?

Thanks,

Amos

0


>>>>>>>

And because it is always a same origin call, the browser is not looking for or expecting cross-origin Access-Control-* headers in the response.

<<<<<<<

This is where I think you're wrong, and correct me if I'm wrong, cause I'm no CORS expert. But from what I read in the specs, if it's a POST call, then even if it's to same origin, the browser *is* looking for the cors headers.

If I'm right, I guess that means that the zendesk proxy *should* return the CORS headers for same origin POST calls, as it indeed approves them.

No?

0


>>>>

tell me if I got this right...the request from the browser to the proxy is SAME ORIGIN

<<<<

That is correct. When calling the proxy, it is always same origin, regardless of action. That's because the proxy is always called under the same domain as the account.

This is the format of the call to the proxy (also mentioned in the above article):

https://yoursubdomain.zendesk.com/proxy/to/https://api.github.com

The remote API endpoint the proxy will call is always tacked to the end of proxy endpoint.

And because it is always a same origin call, the browser is not looking for or expecting cross-origin Access-Control-* headers in the response.

0


Hi @..., thanks for covering all the different options we have in Zendesk!

With a server that is not accepting cors, I am using the Method 3 and pass the following GET request header through client.request(): 'x-csrf-token': 'Fetch'. Unfortunately the header is not being sent at all.

Would you have any idea why this happens? I can see it when setting client.request to cors: true or using $.ajax, etc. but cannot use it since the server is not cors-compliant.

Thanks!

0


Hi Amos. You can actually try this out by setting up a third-party service and endpoint using something like glitch.com. You can make a POST call to it via client.request with cors:false, receive the request in your remote server, and not send back any Access-Control-* headers, just a response payload. You'll get the payload and the browser will not complain about the lack of Access-Control-* headers. Can you give the link to the specification reference where a POST expects Access-Control-* headers?

0


Hi Alex. client.request will not send x-csrf-token — this is a reserved header that Zendesk Support uses when managing requests. In fact, it's not something a client would typically set. It comes from the server, to be sent back by the client during normal communication though a browser-to-server communication. If you're going through a proxy, you are really approaching things from a different angle.

0


Hi, I'm sorry if I'm posting this in the wrong place, I just can't find anywhere specific for my problem.. 

I'm trying to send a request to monday.com's GraphQL API but I'm getting a few different responses depending on the various settings I have tried.

Sometimes I get an empty responseText and statusText: "error", sometimes something like "Internal Proxy error", and sometimes, when the request does return a 200 response, I get "No query string was present".. I have tried a few different variations to my data parameter but nothing seems to work.. Is there a specific way of sending a GraphQL payload to client request, or am I missing some extra parameter in muy request?

Here's my request:

client.request({
url: 'https://api.monday.com/v2/',
headers: {
"Authorization": "Bearer {{setting.token}}"
},
cors: false, // <== I have tried with cors: true and without cors param
secure: true,
contentType: 'application/json',
method: 'POST',
data: JSON.stringify({
query: 'query {\n boards {\n id\n }\n}'
})
}).then(results => {
console.log("zd client request results", results)
}).catch(error => {
console.log("zd client request error:", error)
})

0


Ok, leaving this here in case someone else runs into the same issue.

The way I solved the request above is by using the `print` method from graphql package, and stringifying my query variables, like this:

import { print } from 'graphql/language/printer'
...
client.request({
url: 'https://api.monday.com/v2/',
headers: {
"Authorization": "Bearer {{setting.token}}"
},
cors: false,
secure: true,
contentType: 'application/json',
method: 'POST',
data: {
query: print(require('../graphql/MyBoardsQuery.gql')), // <== using gql to make it cleaner
variables: JSON.stringify({ ids: [this.boardId] })
})
}).then(results => {
console.log("zd client request results", results)
}).catch(error => {
console.log("zd client request error:", error)
})

0


I can't really wrap my head around the "data" attribute and the fact it is setting a body as query parameters. Is this the only way to send a body? My target endpoint returns a parsing error (400) only with client.request(), which we need to send a secure setting. It works fine with GET since there is no body.

var settings = {
method: 'PUT',
url: `url`,
contentType: 'application/json;charset=utf-8',
headers: {
"Accept": "application/json",
"Authorization": "Basic {{setting.token}}"
},
data: JSON.stringify({
Description: `${desc}`,
Owner: `${owner}`
}),
cors: false,
dataType: "json",
secure: true,
httpCompleteResponse: true
}

0


Hi Alex. Since it's the remote web site returning the error, the best place to start is there. I'd suggest looking there to see what it's receiving and repeating the same request in something such as Postman or cURL to see if the same request works in these other tools.

Secure settings also have a number of things that need to be set up to work. I'd cross-reference and compare your code against a couple of example apps to see if there may be anything missing (i.e. make sure you have the token setting specified as "secure" in manifest.json, make sure you have a domainWhitelist specified in manifest.json, etc).

Examples:

https://github.com/zendesk/demo_apps/tree/master/v2/support/secure_settings_sample_app

https://github.com/bryan-flynn-zd/examples/tree/master/demo_app_secure_settings

Hopefully one of the above points will help. If not, you will probably have to contact Zendesk Customer Support as there will probably be private account specific information needed to take this further.

One minor side note in your above snippet: you don't need the 'Accept" header since you have the "dataType" attribute set. 

0


Yes, everything works fine outside of Zendesk or with a non-secure parameter.

However, we followed one of your examples and simply replaced the "method" attribute with "type" in our code snippet.

...and it is now working! (also, thanks for the side note :)

0


Hi,

I added the below on document_head.hbs but I'm still not able to use it. I think it's not loading the ZAFClient properly. Can you please point out what I did wrong?

<script type="text/javascript" src="https://static.zdassets.com/zendesk_app_framework_sdk/2/zaf_sdk.min.js"></script>

 

 

0


image avatar

Greg Katechis

Zendesk Developer Advocacy

Hi Bonaliza! Could you let me know what you're trying to do here? As far as I am aware, ZAF is not available in our help center, but I'd like to understand your use-case first.

0


Please sign in to leave a comment.

Didn't find what you're looking for?

New post