Rails API response body is string not json - ruby-on-rails

I have the following REST API call in my code which if wrong returns this error
def get_token
responseObject = {
message: "Error",
errors: ["User does not exist"]
}
render status: 403, json: responseObject
end
Problem is in my response.json(), i get this instead
So when i try to do this in my code response.json().errors, i always get undefined because somehow it doesnt see my response in my body as json.
Actually not sure how to solve this mess.
Thanks

Related

How to make Postman or Postman Collection Runner send a POST request with CSV file, rails strong parameters

In a Rails 6 api, I want to test a controller with strong parameters with Postman.
In the controller:
class ProcessorController < ApplicationController
...
def create
file = processor_params[:file]
...
end
private
def processor_params
params.require(:upload).permit(:file)
end
end
There is a simple .csv file I have to upload that is required by this request.
First line in the CSV is the column header names (comma separated). About 30 lines of csv data
CSV Headers are: date, hours worked, employee id, job group
Here is an example fixture that works that I want to reproduce in postman:
post '/processor', params: {
upload: {
file: fixture_file_upload('report.csv', 'text/csv')
}
}
How do I correctly post the params and body so that the rails API returns a HTTP 200 response?
I have tried setting up the postman request a few ways, including (1) through a form-data body,
(2) and
(3) this raw json:
{
"upload": {
"file": {
"date": "{{date}}",
"hours worked": {{hours worked}},
"employee id": {{employee id}},
"job group": {{job group}}
}
}
}
It's not working. I am always getting errors such as
"status": 500,
"error": "Internal Server Error",
#<NoMethodError: undefined method `permit' for \"file\":String>",
{
"status": 400,
"error": "Bad Request",
"exception": "#<ActionController::ParameterMissing: param is missing or the value is empty: upload>"

Rspec - Compare two json values

I got a response from render json: { success: 'Success' }, I met a problem when I want to test if the response received the content like this. My unit test is:
let(:success) do
{
success: "Success"
}
end
it 'responds with json containing the success message' do
expect(JSON.parse(response.body)).to eq(success)
end
I got a failure from my test, which is:
expected: {:success=>"Success"}
got: {"success"=>"Success"}
I tried to add double quote to success:'Success' so that it changed to 'success':'Success' but still have the same problem. I have two questions, the first is why there's a colon before the success, and the second is how could I remove it?
JSON.parse will have string-y keys by default.
my_hash = JSON.parse(response.body)
p my_hash.keys.first.class # String
If you want it to symbolize the keys,
my_hash = JSON.parse(response.body, symbolize_names: true)
p my_hash.keys.first.class # Symbol
Note: the option is called symbolize_names and not symbolize_keys.
Remember that a symbol is not a string:
p :success == 'success' # false
I guess you are trying to test API response with JSON format. You could try json_spec gem with many other helpful features https://github.com/collectiveidea/json_spec

Ruby On Rails ---- try to send error message in json

I'm trying to send error messages(like following things in console when i did a wrong sql) back to frontend in json.
Traceback (most recent call last):
NameError (undefined local variable or method `posts' for main:Object)
So i wrote this in controller:
begin
#results = Post.find_by_sql(params[:sql])
if #results.first.nil?
render json: { fail: "No such tuple"}
else
render json: { html: render_to_string(:template => 'all/findit') }
end
rescue
render json: { fails: #results.errors}
But from the console in browser, it still only gives a 500 error and the ajax shows "fail".
How to fix this bug? Thanks!!
Post::find_by_sql returns an array so you wouldn't be able to call #errors on it.
"The results will be returned as an array, with the requested columns encapsulated as attributes of the model you call this method from."
Source: https://api.rubyonrails.org/classes/ActiveRecord/Querying.html#method-i-find_by_sql

How to handle possible params on Rails 4?

I'm doing an API for my app.
Currently, you can call api/v1/clients and get the Clients JSON back, as expected. You can also do api/v1/clients?client_id=1 and get the JSON representation of the Client object with id 1.
Here's my API::V1::ClientsController:
class API::V1::ClientsController < ApplicationController
def index
if params[:client_id]
#client = Client.find(params[:client_id])
render template: 'api/v1/clients/show'
else
#clients = Client.all
end
end
end
I want that if, for example, you have a typo on the endpoint (api/v1/clients?clent_id=1), the app returns a JSON object with an error:
{
error: {
error_code: 10,
error_description: "Bad endpoint"
}
}
Is there a way to, say, make a switch statement on the params to handle the possible cases?
My suggestion:
Make a private method in your controller, this one will check your params:
If params is empty it returns false
If params contains 'client_id' and its value is a numeric it returns the value
Otherwise it raises an exception.
Then in you action method you use this result:
If the result is false you display all results
Otherwise it display the record based on the id returned by your private method
As for the exception: you use a rescue_from to display the "Bad endpoint" JSON response

Rails: validation error codes in JSON

So, I am writing Rails web application which has JSON API for mobile apps. For example, it sends POST JSON request to example.com/api/orders to create order.
{id: 1, order: { product_name: "Pizza", price: 10000}}
In case of validation errors I can response with HTTP 422 error code and order.errors.full_messages in json. But it seems better for me to have specific error code in JSON response. Unfortunately, it seems like Rails does not provide ability to set error code for validation error. How to solve this problem?
You can pass a custom status code by using the status option when rendering the response.
def create
#order = ...
if #order.save
render json: #order
else
render json: { message: "Validation failed", errors: #order.errors }, status: 400
end
end
I usually tend to return HTTP 400 on validation errors. The message is a readable status response, the errors are also attached.
This is a respons example
{
message: "Validation failed",
errors: [
...
]
}
You can also embed additional attributes.
I was after something similar, so what I did was extend String eg
class ErrorCodeString < String
def init(value, error_code)
#error_code = error_code
super(value)
end
def error_code
#error_code
end
end
Then in a custom validation (this won't work on standard validation) I'd do
errors.add(:email, ErrorCodeString.new('cannot be blank', 50)
Now when you return your JSON you can check to see if the error value is an ErrorCodeString and add the error_code value to the output. As ErrorString inherits String, you shouldn't be breaking anything else along the way.
Rails 5 has error.details that can be used for exactly that.
In the model
errors.add(:price, 1023, message: "Transaction value #{price} is above limit (#{maximum_price}).")
In the controller
format.json { render json: #order.errors.details, status: :unprocessable_entity }
error details can be anything, eg. you could also use :above_limit instead of 1023.
The API response body will then look like
pp JSON.parse(response)
{"price"=>[{"error"=>1023}]}
This feature has been backported to Rails 4, see also http://blog.bigbinary.com/2016/05/03/rails-5-adds-a-way-to-get-information-about-types-of-failed-validations.html
Also: Is there a way to return error code in addition to error message in rails active record validation?

Resources