How do I inspect the full URL generated by HTTParty? - ruby-on-rails

I want to look at the full URL the HTTParty gem has constructed from my parameters, either before or after it is submitted, it doesn’t matter.
I would also be happy grabbing this from the response object, but I can’t see a way to do that either.
(Bit of background)
I’m building a wrapper for an API using the HTTParty gem. It’s broadly working, but occasionally I get an unexpected response from the remote site, and I want to dig into why – is it something I’ve sent incorrectly? If so, what? Have I somehow malformed the request? Looking at the raw URL would be good for troubleshooting but I can’t see how.
For example:
HTTParty.get('http://example.com/resource', query: { foo: 'bar' })
Presumably generates:
http://example.com/resource?foo=bar
But how can I check this?
In one instance I did this:
HTTParty.get('http://example.com/resource', query: { id_numbers: [1, 2, 3] }
But it didn’t work. Through experimenting I was able to produce this which worked:
HTTParty.get('http://example.com/resource', query: { id_numbers: [1, 2, 3].join(',') }
So clearly HTTParty’s default approach to forming the query string didn’t align with the API designers’ preferred format. That’s fine, but it was awkward to figure out exactly what was needed.

You didn't pass the base URI in your example, so it wouldn't work.
Correcting that, you can get the entire URL like this:
res = HTTParty.get('http://example.com/resource', query: { foo: 'bar' })
res.request.last_uri.to_s
# => "http://example.com/resource?foo=bar"
Using a class:
class Example
include HTTParty
base_uri 'example.com'
def resource
self.class.get("/resource", query: { foo: 'bar' })
end
end
example = Example.new
res = example.resource
res.request.last_uri.to_s
# => "http://example.com/resource?foo=bar"

You can see all of the information of the requests HTTParty sends by first setting:
class Example
include HTTParty
debug_output STDOUT
end
Then it will print the request info, including URL, to the console.

As explained here, if you need to get the URL before making the request, you can do
HTTParty::Request.new(:get, '/my-resources/1', query: { thing: 3 }).uri.to_s

Related

GRAILS URL parameters short form

I know that in GRAILS/GROOVY
def content=urlrestservicestring.toURL().getBytes(requestProperties: ['User-Accepted': username])
is a short form to have all the byte content (for example for PDF donwload), but I don't know all the request properties available for URL for richer connections, for example for POST method (this is a GET call) with payload in json. Is it possible? In which way?
It looks like per requestProperties you can set request headers only which might help for simple cases.
On the other hand if you want to do something more complex, like a POST, you have to use a propper HTTP-client.
In Groovy there's an idiomatic HTTPBuilder which is very straight-forward and easy to use, or Grails own RESTBuilder
UPDATE:
Using HTTPBuilder the download could look like:
import static groovyx.net.http.HttpBuilder.configure
configure {
request.uri = "http://example.org/download"
request.contentType = 'application/json'
}.post {
request.headers.username = 'Scarpanti'
request.body = [ some:'json' ]
Download.toStream delegate, response.outputStream // from grails
// or
// Download.toStream delegate, file
}
see also ref-doc

Search with Relay doesn't include new results due to local cache

I've implemented a search-as-you-type component in React and Relay. It's roughly the same setup as search functionality using relay
It works as intended with one exception. New results from the server never appear when I retype a search I've already performed on the client. I looks like Relay always goes to the local cache in this case.
So, for example, say I've searched for 'foo' and didn't find any results. Now, seconds later, another user on the website creates this 'foo', but Relay will never query the server since the cached response to the 'foo' search was an empty result.
Is there a pattern or best practice for this scenario?
The query is as follows. I call this.props.relay.setVariables to perform the search:
initialVariables: {
search: '',
hasSearch: false
},
fragments: {
me: () => Relay.QL`
fragment on Viewer {
relationSearch(search: $search) #include(if: $hasSearch) {
... on User {
username
}
}
}
`
}
The answer seems to be to use this.props.relay.forceFetch with the search variables instead.
See https://facebook.github.io/relay/docs/api-reference-relay-container.html#forcefetch
Someone correct me if this isn't best practice.

React Native - Interact with API - Special Characters Causing Issues - What's the best way to do this?

I cannot consistently successfully send form variables that may/may not include special characters e.g. ? & #
Depending on where I try to escape the chars I encounter different errors when reading the data server-side.
I am aware that an update is due for React Native 0.7 to include formdata but wondered if I could safely post objects without needing this.
Someone has already posted a similar issue but no example code was posted to illustrate the POST working:
How to post a form using fetch in react native?
I have tried - amongst other things :
fetch(APIURL, {
method: 'POST',
body: JSON.stringify({
object1: {
param1a: "value 1a",
param1b: "value 1b - with bad chars & # ?",
},
object2:
{
param2a: "value 2a",
param2b: 0,
}
})
})
but it groups the data into a single unnamed parameter (changing the API to accept this is not an option).
also this:
fetch(APIURL, {
method: 'GET',
accessPackage: JSON.stringify({
accessToken: "abc123",
tokenType: 2,
}),
taggData: JSON.stringify({
title: "test",
wishlistID: 0,
anotherVar: "anotherVal"
})
})
I wish to receive the data as two strings that can be parsed as json objects at the other end.
Looking at the the fetch repo https://github.com/github/fetch hasn't helped as this assumes the post with be a full JSON post (which it isn't) or uses FormData which isn't available to React Native yet.
Another solution may be to safely encode/serialise all of the data to URL parameters but this has also proven inconsistent so far especially with the # char.
What's the best way to do this?
"it groups the data into a single unnamed parameter (changing the API
to accept this is not an option)."
It would, because you've set the post body. This is how it's supposed to work.
I wish to receive the data as two strings that can be parsed as json objects at the other end.
You can do whatever you want, but there's no magic happening here. You will receive a single string, the string you set body to. Likewise, the post body can contain anything but shouldn't get confused with "special" characters. Most likely it is your server-side that is causing the problems.
If you want to use FormData then I think it'll be in v0.7.0 which should be out any day now, or you could probably just include the JS file in your own project. You can find it here. Usage examples are in the UIExplorer demo.

How to create a bigquery table and import from cloud storage using the ruby api

Im trying to create a table on BigQuery - I have a single dataset and need to use the api to add a table and import data (json.tar.gz) from cloud storage. I need to be able to use the ruby client to automate the whole process. I have two questions:
I have read the docs and tried to get it to upload (code below) and have not been successful and have absolutely no idea what Im doing wrong. Could somebody please enlighten me or point me in the right direction?
Once I make the request, how do I know when the job has actually finished? From the API, I presume Im meant to use a jobs.get request? Having not completed the first part I have been unable to get to look at this aspect.
This is my code below.
config= {
'configuration'=> {
'load'=> {
'sourceUris'=> ["gs://person-bucket/person_json.tar.gz"],
'schema'=> {
'fields'=> [
{ 'name'=>'person_id', 'type'=>'integer' },
{ 'name'=> 'person_name', 'type'=>'string' },
{ 'name'=> 'logged_in_at', 'type'=>'timestamp' },
]
},
'destinationTable'=> {
'projectId'=> "XXXXXXXXX",
'datasetId'=> "personDataset",
'tableId'=> "person"
},
'createDisposition' => 'CREATE_IF_NEEDED',
'maxBadRecords'=> 10,
}
},
'jobReference'=>{'projectId'=>XXXXXXXXX}
}
multipart_boundary="xxx"
body = "--#{multipart_boundary}\n"
body += "Content-Type: application/json; charset=UTF-8\n\n"
body += "#{config.to_json}\n"
body += "--#{multipart_boundary}\n"
body +="Content-Type: application/octet-stream\n\n"
body += "--#{multipart_boundary}--\n"
param_hash = {:api_method=> bigquery.jobs.insert }
param_hash[:parameters] = {'projectId' => 'XXXXXXXX'}
param_hash[:body] = body
param_hash[:headers] = {'Content-Type' => "multipart/related; boundary=#{multipart_boundary}"}
result = #client.execute(param_hash)
puts JSON.parse(result.response.header)
I get the following error:
{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"wrongUrlForUpload", "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}], "code"=>400, "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}}
From the request header, it appears to be going to the same URI the error says it should go to, and I am quite at a loss for how to proceed. Any help would be much appreciated.
Thank you and have a great day!
Since this is a "media upload" request, there is a slightly different protocol for making the request. The ruby doc here http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload describes it in more detail. I'd use resumable upload rather than multipart because it is simpler.
Yes, as you suspected, the way to know when it is done is to do a jobs.get() to look up the status of the running job. The job id will be returned in the response from jobs.insert(). If you want more control, you can pass your own job id, so that in the event that the jobs.insert() call returns an error you can find out whether the job actually started.
Thank you for that. Answer resolved. Please see here :
How to import a json from a file on cloud storage to Bigquery
I think that the line of code in the docs for the resumable uploads section (http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload) should read:
result = client.execute(:api_method => drive.files.insert,
Otherwise, this line will throw an error with 'result' undefined:
upload = result.resumable_upload

Can't get views by averageViewDuration — YouTube Analytics API

So I'm using the 'google-api-client' gem with Rails, and I'm attempting to call the URL below in order to get video views by averageViewDuration. This is a call that appears to be allowable from the Available Reports documentation page.
Additionally, I found that I was able to make this call by using the API Explorer tool provided by Google.
URL:
https://www.googleapis.com/youtube/analytics/v1beta1/reports?metrics=averageViewDuration&ids=channel==CHANNEL_ID&dimensions=day&filter=video==VIDEO_ID&start-date=2013-01-15&end-date=2013-01-16&start-time=1970-01-01
Result:
{
:error=>
{
"errors"=>[
{
"domain"=>"global",
"reason"=>"invalid",
"message"=>"Unknown identifier (averageViewDuration) given in field parameters.metrics."
}
],
"code"=>400,
"message"=>"Unknown identifier (averageViewDuration) given in field parameters.metrics."
}
}
I'm not sure what extra data I can provide in the initial description of this bug, but as stated before I am making the call to the API with the Google::APIClient Ruby library. The actual code itself looks like this:
client.execute(
:api_method => api.reports.query,
:parameters => options
)
Could you try that again with v1 as the version instead of v1beta1?
Also, you have a start-time parameter at the end of your request URL, and that's not a valid parameter.
I just gave a similar query with those changes a try and it works.

Resources