Rails App Breaks with 404 Error when Last.fm API Call Returns Nothing - ruby-on-rails

I wonder if anyone can help, and if the issue is specific to Last.fm (perhaps not the greatest of APIs).
I've built an album search feature into my app that takes two parameters - album and artist. Now, this returns an album just fine if there's a result, but in the instances that there isn't a result - if just type gibberish into the fields - Rails breaks with a 404 error when trying to run URI.open(url).read.
What I don't quite understand (and I am fairly new at this), is that when I run the same API call url in my search engine, with the gibberish, I do get a JSON response:
// https://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=xxxxxxx&artist=akjsdhkasd&album=hdkuahd&format=json
{
"message": "Album not found",
"error": 6
}
So, I don't understand why I'm getting a 404 error when it runs in my code.
Is there any way that I can rescue this, so that I can just render a 'no result', rather than crashing the entire site?
Not sure my code adds much to the picture, but this is where I run the URI:
def get_album(artist, album)
album = ERB::Util.url_encode(album)
artist = ERB::Util.url_encode(artist)
url = "https://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=xxxx&artist=#{artist}&album=#{album}&format=json"
serialized = URI.open(url).read
JSON.parse(serialized, object_class: OpenStruct).album
end
Thanks for any pointers.

From what I understood, you are using open-uri to reach this service. If you want to rescue an exception in this process you can try something like this:
def get_album(artist, album)
album = ERB::Util.url_encode(album)
artist = ERB::Util.url_encode(artist)
url = "https://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=xxxx&artist=#{artist}&album=#{album}&format=json"
serialized = URI.open(url).read
JSON.parse(serialized, object_class: OpenStruct).album
rescue OpenURI::HTTPError
"Error when trying to fetch album information"
end
*I'm returning just a string but you can implement an appropriate return that fits your purpose.
I'm not sure if it's possible to rescue specific 404 - Not Found errors using this strategy. But, you can take a look into 'net/http' or other HTTP Client Libraries (httparty, typhoeus, etc..) to try different approaches if you want..

Related

How to access AWS Comprehend using aws-sdk-comprehend gem?

I'm working on getting my Rails app interacting with the AWS Comprehend service for text entity extraction. I'm using the aws-sdk-comprehend gem. I have successfully gotten my app working with the AWS Rekognition service for image analysis using the aws-sdk-rekognition gem.
I can't seem to get the AWS Comprehend authentication correct as all of my calls result in an Aws::Comprehend::Errors::InvalidRequestException.
I have all of the following ENV variables set:
AWSAccessKeyId
AWSSecretKey
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
My code looks something like this:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
#credentials = Aws::Credentials.new(ENV['AWSAccessKeyId'], ENV['AWSSecretKey'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
end
end
This resulted in Aws::Comprehend::Errors::InvalidRequestException. So I also tried:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
# use ENV credential format I've seen in examples...
#credentials = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
end
end
I found an example that didn't use the #credential approach. The example claimed "The initialize method will load the credentials environment variables by itself". So I tried this:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
# ignore setting the credentials
#client = Aws::Comprehend::Client.new(region: "us-west-1")
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"}).
end
end
This also resulted in Aws::Comprehend::Errors::InvalidRequestException.
Can you see anything I'm doing wrong? Has anyone had success in using this gem to interact with the Comprehend API?
Per the Documentation for Aws::Comprehend::Client#detect_entities
If the system detects a document-level error in your input document, the API returns an InvalidRequestException error response. For details about this exception, see Errors in semi-structured documents in the Comprehend Developer Guide.
So it appears your usage is not necessarily the issue but rather the input documents themselves.
The response however should include what the actual issue is according to the Developer Guide:
Document-level errors
If the ClassifyDocument or DetectEntities API operation detects a document-level error in your input document, the API returns an InvalidRequestException error response.
In the error response, the Reason field contains the value INVALID_DOCUMENT.
The Detail field contains one of the following values:
DOCUMENT_SIZE_EXCEEDED – Document size is too large. Check the size of your file and resubmit the request.
UNSUPPORTED_DOC_TYPE – Document type is not supported. Check the file type and resubmit the request.
PAGE_LIMIT_EXCEEDED – Too many pages in the document. Check the number of pages in your file and resubmit the request.
TEXTRACT_ACCESS_DENIED_EXCEPTION – Access denied to Amazon Textract. Verify that your account has permission to use the Amazon Textract DetectDocumentText and AnalyzeDocument API operations and resubmit the request.
The Aws::Comprehend::Errors::InvalidRequestException object is documented so it appears you could potentially figure out what is wrong via
def call
# use ENV credential format I've seen in examples...
#credentials = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
begin
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
rescue Aws::Comprehend::Errors::InvalidRequestException => e
# interrogate the error object here e.g.
puts {reason: e.reason, detail: e.detail}
end
end

Accessing Twitter with Akka Camel to return JSON

I was using an HTTP POST method using the URL
"https://stream.twitter.com/1.1/statuses/filter.json" and in the body I was posting the key/value I wanted to get tweets from - for example "track=london". This was working fine.
Now I am trying to switch to AKKA-CAMEL and I am using their twitter consumer. I am using an endpoint URL of:
def endpointUri: String = s"twitter:////search?type=direct&keywords=${Settings.queryList()}&consumerKey=${tweeterCredentials.consumerKey}&consumerSecret=${tweeterCredentials.consumerSecret}&accessToken=${tweeterCredentials.accessToken}&accessTokenSecret=${tweeterCredentials.accessTokenSecret}"
I get a response from twitter but it is not in JSON and it is not the same information about the tweet as before. It just return the tweet text but before I was getting the whole metadata which I need to analyze.
Does somebody knows how to configure Camel URI to return JSON and the whole metadata as before?
Thanks
I got this to work by using the following syntax:
def endpointUri: String = s"twitter://streaming/filter?type=event&keywords=${Settings.queryList()}&consumerKey=${tweeterCredentials.consumerKey}&consumerSecret=${tweeterCredentials.consumerSecret}&accessToken=${tweeterCredentials.accessToken}&accessTokenSecret=${tweeterCredentials.accessTokenSecret}"
Where: Settings.queryList return a comma separated list of keyworkds. The object tweeterCredentials holds the keys from Tweeter to access the site.
Also it is necessary to set autoAck like this in Camel:
override def autoAck = true
This prevents a timeout exception.

can't download file from google drive with ruby

I'm trying to get my rails controller set up to download a file from google drive following the code at - https://developers.google.com/drive/v2/reference/files/get
I have the following rails code
def download_file(client, file)
if file.download_url
result = client.execute(:uri => file.download_url)
if result.status == 200
return result.body
else
puts "An error occurred: #{result.data['error']['message']}"
return nil
end
end
end
def attachExternalResume
# read remote url to file
file_id = params[:fileId]
client = Google::APIClient.new
drive = client.discovered_api('drive', 'v2')
result = client.execute(
:api_method => drive.files.get,
:parameters => { 'fileId' => file_id}
)
if (result.status == 200)
p download_file client, result.data
end
end
This is being called from my javascript front end using the google picker. The user authorizes my app through the google picker and selects a file which results in my angular javascript posting the file id to my rails method. In the rails code I'm getting the following error - Missing access token.
It seems like even though the user has authorized the app on the front end, that authorization isn't making its way through to the rails side. Anyone know how I can get the authorization all the way through the process?
"I'm getting the following error - Missing access token." probably means that you're missing an access token. In the code snippet you posted, I can't see anywhere where you request an access token, so that makes it even more likely. I don't know enough about the Google Ruby library to give you the code you're missing, but look for something that takes scope(s) and application/client ID as arguments.

Koala::Facebook::ClientError Exception: type: GraphMethodException, code: 100, message: Unsupported get request

I did research on this issue, however, nothing worked for me.
I am using Facebook Realtime subscription and graph API to track my facebook page (using page token).
When a user posts a photo/video I am getting following data pushed by fb to my server:
{"field"=>"feed",
"value"=>
{"item"=>"photo",
"verb"=>"add",
"photo_id"=>302522856593533,
"post_id"=>"824413870916335_302522856593533",
"sender_id"=>100005074631221}}
When I use post_id (824413870916335_302522856593533) to make call to graph API for fetching details of the post, I am encountering following error:
*** Koala::Facebook::ClientError Exception: type: GraphMethodException, code: 100, message: Unsupported get request.
Please read the Graph API documentation at
https://developers.facebook.com/docs/graph-api [HTTP 400]
However, if user posts without photo/video, I am able to get post details successfully. In case, admin posts photo/video, I am able to get details of that post too.
I am sure about the correctness of page token and code. I think, there must be something related to settings.
I have multiple pages to fetch. Tested with both of these methods Koala wiki provides
#graph = Koala::Facebook::GraphAPI.new # pre 1.2beta
#graph = Koala::Facebook::API.new # 1.2beta and beyond
Some pages have ids and some have not in their uris so in a page like this:
https://www.facebook.com/pages/Istanbul-Kuafor/241559912664906
fc.get_object("Istanbul-Kuafor")
gives me the error message you mentioned so I use
fc.get_object("241559912664906")
if page doesn't have an id(some pages don't, somehow), I use the page name and it works this time.

First Google Drive API files.list request returning an array of Hashes, after that, subsequent requests returning an array of File Resources. Why?

I'm querying the Google API to list all files in the drive using the Google API official gem for ruby. I'm using the example given in the Google developers page - https://developers.google.com/drive/v2/reference/files/list
The first request I made returns in the "items" an array of ruby "Hashes". The next requests return in the "items" an array of either "Google::APIClient::Schema::Drive::V2::File" or "Google::APIClient::Schema::Drive::V2::ParentReference" (the reason behind each type also buggs me).
Does anyone know why this happens? At the reference page of "files.list" none is said about changing the type of the results.
def self.retrieve_all_files(client)
drive = client.discovered_api('drive', 'v2')
result = Array.new
page_token = nil
begin
parameters = {}
if page_token.to_s != ''
parameters['pageToken'] = page_token
end
api_result = client.execute(
:api_method => drive.files.list,
:parameters => parameters)
if api_result.status == 200
files = api_result.data
result.concat(files.items)
page_token = files.next_page_token
else
puts "An error occurred: #{result.data['error']['message']}"
page_token = nil
end
end while page_token.to_s != ''
result
end
EDIT:
I couldn't solve the problem yet, but I manage to understand it better:
When the first request to the API is made, after the authorization is granted by the user, the "file.list" returns an array of Hashes at "Items" attribute of the File resource. Each of this Hashes is like a File resource, with all the attributes of the File, the difference is just in the type of the access. For example: the title of the file can be accessed like this "File['title']".
After the first request is made, all the subsequent requests return an array of File resources, that can be accessed like this "File.title".
FYI, this was a bug in the client lib. Using the latest version should fix it.

Resources