Api errors customization for Rails 3 like Github api v3 - ruby

I am adding an API on a Rails3 app and its pretty going good.
But I saw the following Github api v3 at http://developer.github.com/v3/
HTTP/1.1 422 Unprocessable Entity
Content-Length: 149
{
"message": "Validation Failed",
"errors": [
{
"resource": "Issue",
"field": "title",
"code": "missing_field"
}
]
}
I liked the error messages structure. But couldn't get it to reproduce.
How can I make my apis to make the response like it?

You could quite easily achieve that error format by adding an ActionController::Responder for your JSON format. See http://api.rubyonrails.org/classes/ActionController/Responder.html for the (extremely vague) documentation on this class, but in a nutshell, you need to override the to_json method.
In the example below I'm calling a private method in an ActionController:Responder which will construct the json response, including the customised error response of your choice; all you have to do is fill in the gaps, really:
def to_json
json, status = response_data
render :json => json, :status => status
end
def response_data
status = options[:status] || 200
message = options[:notice] || ''
data = options[:data] || []
if data.blank? && !resource.blank?
if has_errors?
# Do whatever you need to your response to make this happen.
# You'll generally just want to munge resource.errors here into the format you want.
else
# Do something here for other types of responses.
end
end
hash_for_json = { :data => data, :message => message }
[hash_for_json, status]
end

Related

Reading a JSON object in Ruby on Rails

I'm a Ruby on Rails beginner and I'm trying to convert a static website I've made into Rails app where I can store customers and quote data. I'm trying to do this as a RESTful API where my site sends a JSON object containing the customer's information. I check to see if the email in the JSON object matches any of the emails I have in my database and if it does I send back the id of that customer. If not then I create a new customer and send back that id. The problem I'm having is that no matter how I write it, my rails app is not reading the JSON data, so if I have nothing in my database it creates a customer with all null attributes and when I run it again it goes "Oh, I have customer with a null email" and returns that customer.
{
"fname": "William",
"lname": "Shakespeare",
"email": "wshakespeare#test.com",
"bname": "MyCompany",
"primary": "555-555-5555",
"secondary": ""
}
Here's an example of my JSON object.
Here's how my controller is looking:
class CustomersController < ApplicationController
skip_before_action :verify_authenticity_token
wrap_parameters format: [:json, :xml, :url_encoded_form, :multipart_form]
def create
#query = Customer.where(:email === params[:email])
if #query.empty? == true
redirect_to action: "new", status: 301
else
#theid = #query.first.id
render json: {status: 'SUCCESS', message: 'Existing customer', theid:#theid}
end
end
def new
Customer.create(fname: params[:fname], lname: params[:lname], email: params[:email], bname: params[:bname], primary: params[:primary], secondary: params[:secondary])
render json: {status: 'SUCCESS', message: 'New customer', theid: Customer.last.id}
end
Any help would be greatly appreciated. Thanks.

ActiveModel serializer ignores root key when posts or post is empty or nil

I am using active model serializer V0.10.0 with Rails 5 api only application. During implementation I noticed the AMS is completely ignoring the root key when the posts/post is empty or nil respectively. This behavior actually breaks my mobile app as it always expects root key data in all response.
So what I want to achieve here is no matter what I always want data as root element of my Rails app response for all requests.
Response for SHOW API when the post is empty
SHOW render json: #post, root: 'data'
Expected
{
"data": {}
}
Actual
null
Response for INDEX API when the posts are empty
INDEX render json: #posts, root: 'data'
Expected
{
"data": []
}
Actual
{
"posts": []
}
class ApplicationSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
ActiveModelSerializers.config.adapter = :json
def host
Rails.application.secrets.dig(:host_url)
end
end
class PostSerializer < ApplicationSerializer
attributes :id
has_many :comments
end

Sending a patch request to edit video using vimeo api not working

I am trying to send a patch request to edit a video using vimeo api using ruby. The request is successful but vimeo is not able to read my the payload(the title and description), that is, the the title and the description is not getting changed. I have used HTTParty, RestClient as well as Net::HTTP but none of it works. Below are my code that i have implemented to send a patch request,
RestClient
payload = {"description" => "Test Description", "name" => "Test Video"}
res = RestClient.patch(
vimeo_edit_url,
payload.to_s,
{ "Authorization" => auth })
NET::HTTP
options = {'description' => "Test Description", 'name' => "Test Video"}
edit_req = Net::HTTP::Patch.new(vimeo_edit_url, initheader = { "Authorization" => auth})
edit_req.data = options.to_s
edit_uri = URI(vimeo_edit_url)
edit_http = Net::HTTP.new(edit_uri.host, edit_uri.port)
edit_http.use_ssl = true
edit_http.verify_mode = OpenSSL::SSL::VERIFY_PEER
edit_response = edit_http.request(edit_req)
Usually the response will be a 200 OK with the updated video details but I get a 200 OK with video details(title and description not being changed). It is as if like vimeo is not able to read my payload.
You probably want to be passing payload, not payload.to_s.
That .to_s is turning your nicely arranged hash into a weird rubyified string, and all of the HTTP libraries you mentioned will accept a hash and handle the conversion for you.
Here's what some different representations look like in an irb session:
>> payload = {"description" => "Test Description", "name" => "Test Video"}
>> payload
=> {"description"=>"Test Description", "name"=>"Test Video"}
>> payload.to_s
=> "{"description"=>"Test Description", "name"=>"Test Video"}"
>> require 'json'
=> true
>> payload.to_json
=> "{"description":"Test Description","name":"Test Video"}"

Why do I get a 401 error when using Ruby to execute a Google Fusion Tables API command?

I'm using the Ruby gem 'google-api-client', and I make sure to add in all my credentials, but for some reason, I keep getting a 401 error from Google.
Here's my code:
['google/api_client','json'].each{|g| require g}
client_secrets = File.open('client_secrets.json','r').read # My client secrets are stored in this .JSON file
client_secrets_hsh = JSON.parse(client_secrets)
client = Google::APIClient.new
client.authorization.client_id = client_secrets_hsh['installed']['client_id']
client.authorization.client_secret = client_secrets_hsh['installed']['client_secret']
client.authorization.redirect_uri = client_secrets_hsh['installed']['redirect_uris'][0]
client.authorization.access_token = 'MY_ACCESS_TOKEN'
client.authorization.username = 'MY_USER_NAME#gmail.com'
client.authorization.password = 'MY_GOOGLE_ACCOUNT_PASSWORD'
client.authorization.scope = 'https://www.googleapis.com/auth/fusiontables'
request_body = ''
headers = []
headers << ['Content-Type','application/json']
api = client.discovered_api('fusiontables','v1')
result = client.execute(
:api_method => api.to_h['fusiontables.table.list'],
:parameters => {'maxResults' => 1000},
:merged_body => request_body,
:headers => headers
)
puts result.response.body
And here's the response I get back from the puts results.response.body line:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}
Username and password should not be supplied. Try dropping those to start. You only need the access token in order to make API calls. Which, incidentally, I'm not sure where you got that from. Usually you'd need to make a call to fetch_access_token! somewhere. It's normally not something you set via an accessor. There are advanced cases where you would – but you're probably not one of them.

How to respond_with multiple objects in Rails 3.1

I have a route for example
POST /interaction.json
where the client posts a new interaction. Normally my controller would look like
class InteractionController < ApplicationController
def create
respond_with #log
end
end
and I will get back a json response
{ "log" : { "id" : 20, .... } }
and the location header set to
http://foo.com/log/20
However if I wish to return more objects in my :json response than just the #log. For example to notify the client that some thing has changed with respects to this interaction the normal. Perhaps the user has won a prize for making this interaction. It would be nice to be able to do
response_with #log, #prize
and get the response
{ "log": { "id": 20, ... },
"prize": { "id": 50, ...}
}
but that is not the way respond_with works. It treats #prize as a nested resource of #log. Can anyone suggest an idea for this?
Merging two independent objects is dangerous and will override any existing attributes in the caller.
Instead you could always wrap the objects and respond with the wrapper instead:
#response = {:log => #log, :price => #price}
respond_with #response
Assuming that #log and #prize are both hashes, you could merge both hashes and return the merge.
respond_with #log.merge(#prize)
I'm thinking it might overwrite the #log.id with #prize.id though. Can try something else if it does.

Resources