Shopify not getting rates from custom CarrierService - ruby-on-rails

I'm building a private Shopify app that returns custom shipping rates. Following the API docs, and with some help from this tutorial, I created a functional, proof-of-concept that returns some sample shipping rates in my store.
However, that proof-of-concept app is built in PHP, and the final version must be in Ruby on Rails. So I created a Rails app that returns exactly the same content as the PHP app—but for some reason the rates simply don't show up in the Shopify backend.
The only thing I notice that's different is the HTTP headers (I've tried monkeying around with them to match the PHP app, but to no avail). Is there anything obvious I'm missing here?
Here's a comparison of the HTTP response headers:
PHP:
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 186
Content-Type: text/html; charset=UTF-8
Date: Tue, 16 May 2017 13:00:30 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.18 (Ubuntu)
Vary: Accept-Encoding
Rails:
Cache-Control: max-age=0, private, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Tue, 16 May 2017 12:57:38 GMT
ETag: W/"ce885edaa10636b3b7459dca958f44dd"
Server: nginx
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Request-Id: 54e2575e-c86a-4f44-a315-d0a3fbbc13f9
X-Runtime: 0.616974
Again, Shopify handles the PHP response fine, but fails silently on the Rails response. Is there anything in that second (Rails) block that Shopify might be rejecting?
Shopify unfortunately provides no error log or way to debug this type of issue—either they pull the rates from your app or not.
Here is my Rails rates_controller.rb:
class RatesController < ApplicationController
def index
ups_rates = {
rates: [
{
service_name: 'Endertech Overnight',
service_code: 'ETON',
total_price: '000',
currency: 'USD',
min_delivery_date: (DateTime.now + 1.days).strftime('%F %T %z'),
max_delivery_date: (DateTime.now + 2.days).strftime('%F %T %z')
},
{
service_name: 'Endertech Regular',
service_code: 'ETREG',
total_price: '000',
currency: 'USD',
min_delivery_date: (DateTime.now + 3.days).strftime('%F %T %z'),
max_delivery_date: (DateTime.now + 7.days).strftime('%F %T %z')
}
]
}
# Tested returning both application/json (default) or text/html
#render json: ups_rates
render body: ups_rates.to_json, content_type: "text/html"
end
end
I suspected maybe Shopify was caching very aggressively, so I've also tried destroying and recreating both my private app and the carrier service, as well as changing the callback_url. So far nothing has had any effect.

After a whole lot of digging, I found the answer: Shopify requests rates via POST, but my app was only responding to GET.
As a quick fix, I created a static route in routes.rb:
Rails.application.routes.draw do
post 'customrates', to: 'rates#index'
end
In retrospect, this was clearly stated in the documentation, I just hadn't noticed (after all, a rate request intuitively seems like a GET action).
For anyone else encountering this issue, try sending a POST via CURL to your callback_url, just to verify it's returning what it should:
curl -X POST http://yourcallbackurl.com

Related

Microsoft Edge PDF inline issue

Our Rails web app generates PDFs using wkhtmltopdf and sends them to the client. This works in every web browser we've tested it with except Edge.
We've tried rendering the response in a couple of different ways, this is how it was originally:
kit = PDFKit.new(#html_content)
render text: kit.to_pdf, content_type: 'application/pdf'
This opens the PDF viewer with the PDF displaying correctly in every browser that we tested with except Edge where the browser displays: Something's keeping this PDF from opening.
In our application logs, there is the POST request which is the form submission and I can see our app send the pdf file response, then there are subsequent GET requests to the form submission url which error because it's not expecting any GET request to that url. I've no idea what's going on here.
The response headers for the request are:
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 34865
Content-Type: application/pdf; charset=utf-8
Date: Thu, 18 Jun 2015 14:35:30 GMT
Etag: "4baf297d1866339e60e8e893300909a0"
Server: WEBrick/1.3.1 (Ruby/2.0.0/2013-06-27)
Set-Cookie: _APP_session=<long cookie>; path=/; HttpOnly
X-Request-Id: 617580a8-4d7d-43c4-8e49-aeaeafba7b79
X-Runtime: 21.868098
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-ua-compatible: chrome=1
I have also tried using send_data like this:
send_data kit.to_pdf, type: 'application/pdf', disposition: 'inline'
Which results in the following response headers but ultimately the same problem:
Cache-Control: private
Connection: Keep-Alive
Content-Disposition: inline
Content-Length: 34866
Content-Transfer-Encoding: binary
Content-Type: application/pdf
Date: Thu, 18 Jun 2015 14:39:42 GMT
Etag: "11db49f1a26444a38fa2b51f3c3336ed"
Server: WEBrick/1.3.1 (Ruby/2.0.0/2013-06-27)
Set-Cookie: _APP_session=<long cookie>; path=/; HttpOnly
X-Request-Id: 501d9832-b07e-4764-8ecc-f1c1e9a6421e
X-Runtime: 7.054236
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-ua-compatible: chrome=1
If I remove the Content-Disposition: inline header from the above it brings up the save file prompt and downloading the file works fine. We need it to load in the browser window though.
I don't believe it to be a duplicate of this question because it works in IE 9, 10 and 11 and is only a problem with Edge.
We've been having what sounds like the same problem with PDF reports that we generate on the server and dispatch inline - the new tab that opens for the viewer appears to re-issue a request for the content instead of displaying the content from the response. Since we use a synthetic one-time-use path (for largely historical reasons to ensure a new version of the report is fetched), the report isn't actually there for the new tab's GET request.
Since we're using 20.10240, I'm not convinced it was actually fixed in 10158.
As with the OP, this seems to apply only to "Content-Disposition: inline"; if we use "attachment" instead, a temporary file is saved locally and the temporary file is opened in the viewer.
It was a bug but Microsoft have fixed it in build 10158! :)

When does Rails respond with 'transfer-encoding' vs. 'content-length'?

I'm building an API on Rails version 4.1.7/Nginx that responds to request from an iOS app. We're seeing some weird caching on the client and we think it has something to do with a small difference in the response that Rails is sending back. My questions...
1) I want to understand why, for the exact same request (with only the Authorization header value changed), Rails sends back transfer-encoding: chunked sometimes and Content-Length: <number> sometimes? I thought that maybe it had something to do with the response size, but in the example responses whose headers I've pasted below, the data returned in the body is EXACTLY the same.
2) Is there a way to force it to use Content-Length? We think that that will fix our caching issues in our iOS app.
Response #1
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Wed, 18 Mar 2015 00:59:31 GMT
ETag: "86f277ea63295460d4f3bed9a073eaa2"
Server: nginx/1.6.2
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: dd36f139-1986-4da6-9645-4438d41e74b0
X-Runtime: 0.123865
X-XSS-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive
Request #2
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Wed, 18 Mar 2015 00:59:36 GMT
ETag: "86f277ea63295460d4f3bed9a073eaa2"
Server: nginx/1.6.2
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 0cfd7705-157b-41b5-aa36-739bc6f8302e
X-Runtime: 0.092672
X-XSS-Protection: 1; mode=block
Content-Length: 2234
Connection: keep-alive
Both responses are valid according to HTTP 1.1, so you need to fix your client code that it can handle both. It is a bad idea to try to fix the server so that that it behave in a way that it does not trigger a bug in the client.
The next version of nginx may behave differently, you users may even have proxies that change the transfer, maybe only when they do roaming and use a different provider.
If you want to do some finger-printing on the header, the ETag-header may help you, as the ETag should stay constant when the content of the response is not changed, regardless of the transfer.
The server typically sends in chunks when it calls a dynamic page, because it then does not need to create a buffer for the whole page and wait till all of the page is generated.
The server often send the response in one go if it has the buffer already, for example because it is in cache or the content is on a file and is not to big. Sending in one go is more efficient, on the other hand, an extra copy of the data to buffer the output needs more memory and is less efficient. So the server may even decide this according to the available memory.

Can Savon allow redirects? 302 "Error"

Is it possible to make Savon allow redirects? I am currently receiving a 302 HTTP Error, but in reality this should just be a redirect instead of an error.
You can setup Savon to follow redirect setting up follow_redirects option to true.
Eg: client = Savon.client(wsdl: url, ssl_verify_mode: :none, follow_redirects: true)
Found here: https://github.com/savonrb/savon/issues/243
Savon uses httpi for the connection. httpi itself is a wrapper around curb, em_http, excon, httpclient, net_http and rack.
The file em_http.rb contains the comment that
automatic redirect following
is not supported by httpi.
So what I would try to send the call to the redirection target right away if that's possible.
To find the "real" URL you can use a tool like curl, for example:
curl -I www.yahoo.in
gives you
HTTP/1.1 301 Moved Permanently
Date: Thu, 18 Aug 2016 18:50:05 GMT
...
Cache-Control: max-age=3600, public
Location: http://in.yahoo.com/
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
Age: 0
Connection: keep-alive
Server: ATS
The Location: key shows the address you want to try next. You might get another redirect. You'll have to try until the 200 OK is returned.

ASP.NET Web API and MonoDroid

I am trying to call a ASP.NET Web API that I have hosted in IIS from MonoDroid. The service is fine and I can call it from different endpoints. The problem is that in MonoDroid I get invalid cast exception when I try to do this.
var s = response.GetResponseStream();
var j = (JsonObject)JsonObject.Load(s);
System.InvalidCastException: comes back on the load part.
I have done some reading and people seem to say to try to switch the Web API to use JsonNetFormatter class. I tried that and still no luck.
Anybody have any ideas on what I can try?
UPDATE
Here is payload
<ArrayOfAlbum xmlns:xsi="w3.org/2001/XMLSchema-instance";
xmlns:xsd="w3.org/2001/XMLSchema">;
<Album>
<AlbumPK>f09d14cf-3bab-44c8-b614-2b7cf728efd4</AlbumPK>
<Name>Colorado</Name>
<UserName>firstUser</UserName>
<ParentAlbumFK xsi:nil="true" />
<DateCreated>2012-03-12T19:47:54.493</DateCreated>
</Album>
</ArrayOfAlbum>
And
[{"AlbumPK":"f09d14cf-3bab-44c8-b614-2b7cf728efd4","Name":"Colorado",
"UserName":"emorin","ParentAlbumFK":null,
"DateCr‌​eated":"2012-03-12T19:47:54.493"}]
Response from Fiddler changing the accept header to JSON.
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 17 Apr 2012 19:45:47 GMT
97
[{ "AlbumPK":"f09d14cf-3bab-44c8-614-2b7cf728efd4","Name":"Colorado",
"UserName":"emorin","ParentAlbumFK":null,
"DateCreated":"2012-03-12T19:47:54.493"}]
0
It seems that your server is sending data in the chunked encoding and perhaps the MonoDroid is having problem understanding chunked encoding. Try turning it off in IIS.

Facebook 'like' - redirect path to the wrong URL

I'm trying to get the Facebook 'like' button working on a site that has some job listings for different companies - each company can have various incoming links (such as http://apply.co/xentrix_studios or http://apply.co/xentrix_studios/facebook that are redirected to a general list of that company's jobs at http://apply.co/jobs.
Here's the Facebook debug for one of the links: https://developers.facebook.com/tools/debug/og/object?q=apply.co%2Fxentrix_studios
Look at the redirect path. Facebook is going from /xentrix_studios to /jobs to the root at http://apply.co. So, the readings it's giving us are for the root url, which is obviously not what we want.
How can I get Facebook to just stay at the right page after it follows the incoming link?
Your server is returning a 301 redirect for that URL. If you want Facebook to treat a URL as being a real URL, it needs to return content including the meta tags that tell Facebook what image/description/etc to use.
I checked this with
curl -A "facebookexternalhit/1.1" -i "http://apply.co/xentrix_studios"
The response was
HTTP/1.1 302 Moved Temporarily
Server: nginx/0.7.67
Date: Wed, 23 Nov 2011 10:10:55 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Location: http://apply.co/jobs
Cache-Control: no-cache
X-Ua-Compatible: IE=Edge,chrome=1
Set-Cookie: _rubyjobs_session=BAh7DUkiD3Nlc3Npb25faWQGOgZFRiIlZjk3NDk0YTI0ZGIxMDNhODA2YWE0YTgxOGUyNmZkNTNJIg5qb2JfcmVhZHMGOwBGWwBJIg5qb2Jfc2F2ZXMGOwBGWwBJIhB2aXNpdF9jb3VudAY7AEZbAEkiCXBhdGgGOwBGSSIUeGVudHJpeF9zdHVkaW9zBjsAVEkiDGxpbmtfaWQGOwBGaQBJIghhbGkGOwBGaQKbAUkiCHRsaQY7AEZpAnUE--996d80cb1a2b170c46b6e8f09dcef447fb882917; path=/; HttpOnly
X-Runtime: 0.036089
Content-Length: 86
X-Varnish: 1415265483
Age: 0
Via: 1.1 varnish
<html><body>You are being redirected.</body></html>

Resources