How to fix "Unexpected end of JSON" - ruby-on-rails

I had my users page displaying users but then when I stopped working on the code for a while and came back to it I am getting an error which says
Error while processing route: users Unexpected end of JSON input SyntaxError: Unexpected end of JSON input
and also
Uncaught SyntaxError: Unexpected end of JSON input
I don't know where to start on trying to fix this issue.
Here is the front-end code in the route file users.js:
model() {
return this.get("store").findAll("user");
},
Here is the api code in the users controller:
# GET /users
def index
render jsonapi: User.all
end
When I go to http://localhost:3000/users I get the following json:
{
data: [
{
id: "1",
type: "users",
attributes: {
name: "Katie",
email: "katie#gmail.com"
}
},
{
id: "2",
type: "users",
attributes: {
name: "Katie",
email: "katie#gmail.com"
}
},
{
id: "3",
type: "users",
attributes: {
name: "Katie",
email: "katie#gmail.com"
}
},
{
id: "4",
type: "users",
attributes: {
name: "K",
email: "k"
}
},
{
id: "5",
type: "users",
attributes: {
name: "R",
email: "r"
}
}
],
jsonapi: {
version: "1.0"
}
}
I also get this warning: WARNING: The server returned an empty string for GET http://localhost:3000/users, which cannot be parsed into a valid JSON. Return either null or {}.

/users route is not providing the valid JSON output is the reason for this error. You can check /users output using POSTMAN or writing the below code,
let url ="/users";
Ember.$.getJSON(url).then((result) => {
console.log(' Result ', result);
});

Related

Using rswag in Rails - what is the syntax for index responses (arrays)?

Unfortunately the "documentation" for rswag seems pretty lacking and doesn't give an example of how to implement an index action. My "create" spec displays the Schema and Example Value in the Swagger UI, but my "index" method isn't displaying either of those in the UI.
What do I need to change here? I've played around with it based on the limited examples I've found and none of them seem to work.
path '/api/v1/users' do
get('list users') do
tags 'Users'
response(200, 'successful') do
schema type: :array,
properties: {
id: { type: :integer },
title: { type: :string },
created_at: { type: :datetime},
updated_at: { type: :datetime}
}
after do |example|
example.metadata[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end
end
post('create user') do
tags 'Users'
consumes 'application/json'
parameter name: :user, in: :body, schema: {
type: :object,
properties: {
title: { type: :string }
},
required: [ 'title', 'description' ]
}
response(200, 'successful') do
after do |example|
example.metadata[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end
end
end
I have also tried to format the schema like so, based on another example I found, which didn't do anything either (schema/example just aren't displaying):-
schema type: :object,
properties: {
collection: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
title: { type: :string },
created_at: { type: :datetime},
updated_at: { type: :datetime}
}
}
}
}
Check your swagger_helper file. If you've followed the documentation, it's probably something like that:
RSpec.configure do |config|
config.swagger_root = Rails.root.to_s + '/swagger'
config.swagger_docs = {
'v1/swagger.json' => {
openapi: '3.0.1',
info: {
title: 'API V1',
version: 'v1',
description: 'This is the first version of my API'
},
servers: [
{
url: 'https://{defaultHost}',
variables: {
defaultHost: {
default: 'www.example.com'
}
}
}
]
}
}
end
Just replace opeanapi: '3.0.1' for swagger: '2.0'. I've faced this same issue and this is the only workaround I've found so far.
What worked for me was using the produces method, like:
get 'Retrieves the lists' do
tags 'Lists'
produces 'application/json'
response '200', 'Lists found' do
schema type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
title: { type: :string },
created_at: { type: :datetime},
updated_at: { type: :datetime}
}
}
run_test!
end
end
#s89_

Migrating from Mandrill to SparkPost -- Rails API

I am migrating from Mandrill to SparkPost and have a Rails back-end.
The data structure I currently have is the following --
message = {
subject: "Welcome",
merge_vars: [{
rcpt: user.email,
vars: email_vars(user)
}],
to:[{
email: user.email,
name: user.name
}],
track_clicks: true,
track_opens: true,
inline_css: true,
}
This sends the response --
m = Mandrill::API.new
template_content = []
result = m.messages.send_template 'email-confirmation', template_content, message
Would I need to update the JSON data structure at all?
Once JSON is good, how do I pass values to specific template with SparkPost?
I attempted the following --
m = SparkPost::Client.new()
template_content = []
result = m.messages.send_template 'email-confirmation', template_content, message
But I have also seen this --
host = 'https://api.sparkpost.com'
SparkPost::Request.request("#{host}/api/v1/transmissions", API_KEY, {
recipients: [
{
address: { email: user.email },
substitution_data: {
first_name: user.name,
email: user.email
}
}
],
content: {
template_id: 'email-confirmation'
},
substitution_data: {
name: user.name,
email: user.email
}
})
Appreciate the help!
If you're using the official gem, it has a convenient method called send_payload which you can use to send a prepared payload.
The substitution_data inside recipients collection is a per recipient substitution.
For example, I've following templates.
To send using this template, this is my complete code
sp = SparkPost::Client.new() # pass api key or get api key from ENV
payload = {
recipients: [
{
address: { email: 'RECIPIENT1' },
substitution_data: {
name: 'User one',
username: 'userone'
}
}, {
address: { email: 'RECIPIENT2' },
substitution_data: {
name: 'User two',
username: 'user2'
}
}
],
content: {
template_id: 'test-template'
},
substitution_data: {
company: 'Awesome company'
}
}
response = sp.transmission.send_payload(payload)
p response
The email will look like
Hello User one, Your username, userone, is created. Thanks Awesome company

Wrap parameters in AngularJS service for update API request

I'm trying to do update with AngularJS and API
Service: expense.js
angular
.module('timeTrackerApp.services',[])
.service('Expense', ['$resource', function ($resource) {
return $resource('/api/v1/expenses/:id', {id:'#id'}, {
'update': {
method: 'PUT'
},
'destroy': {
method: 'DELETE'
}
})
}])
Controller: expenses_controller.rb
def permitted_params
params.require(:expense).permit(:name, :price)
end
So expected JSON format is { expense: { name: "value", price: value } }
but i'm getting { name: "value", price: value }
So can anyone help me wrap this into root node ( expense ) ?
Rails automatically does wrap parameters when controller name matches a model name. Check doc.
If ever it fails, you can do it manually, in your controller:
wrap_parameters :expense, include: [:name, :price]
so if you receive:
{ name: 'name', price: 'price' }
Controller will give you:
{ name: 'name', price: 'price', expense: { name: 'name', price: 'price' } }
So do this server side since its neat and simple.

"The response from a findAll must be an Array, not undefined" - potentially incorrect serialisation?

Just getting started with Ember, and I'm following this tutorial.
I've got the Ember app set up, the Route and the Model, except when I hit the Route, I get a large number of warnings printed to the console, followed by the error in the title.
My Model looks like:
App = DS.Model.extend
firstName: DS.attr('string')
lastName: DS.attr('string')
email: DS.attr('string')
phone: DS.attr('string')
status: DS.attr('string', defaultValue: 'new')
notes: DS.attr('string')
And my Route:
App.LeadsRoute = Ember.Route.extend
model: -> #store.find 'lead'
My Store.js:
App.ApplicationStore = DS.Store.extend({
})
# Override the default adapter with the `DS.ActiveModelAdapter` which
# is built to work nicely with the ActiveModel::Serializers gem.
App.ApplicationAdapter = DS.ActiveModelAdapter.extend({
})
The JSON my Rails app is returning looks like this.
The warnings are:
WARNING: Encountered "0" in payload, but no model was found for model name "0" (resolved model name using DS.ActiveModelSerializer.typeForRoot("0"))
(I get one warning for each Lead in the Database)
And the error is:
Error while processing route: leads Assertion Failed: The response from a findAll must be an Array, not undefined Error: Assertion Failed: The response from a findAll must be an Array, not undefined
Which seems to be a pretty common one, if StackOverflow search is anything to go by :)
Help greatly appreciated!
Thanks,
Nik
Ok, so I figured this one out... for list responses, ember-data/ActiveModelAdapter is expecting responses formatted like this:
{ "leads" : [ { id: 123, name: "Test", ... }, { id: 456, name: "Test 2", ... } ] }
Whereas I was sending
[ { "lead": { id: 123, name: "Test", ... } }, { "lead": { id: 456, name: "Test 2", ... }} ] }

Iterate through properties of current context objects in Dust.js

Given the JSON object:
errors =
{
hashed_password: {
message: 'Validator "Password cannot be blank" failed for path hashed_password',
name: 'ValidatorError',
path: 'hashed_password',
type: 'Password cannot be blank' },
username: {
message: 'Validator "Username cannot be blank" failed for path username',
name: 'ValidatorError',
path: 'username',
type: 'Username cannot be blank' },
email: {
message: 'Validator "Email cannot be blank" failed for path email',
name: 'ValidatorError',
path: 'email',
type: 'Email cannot be blank' },
name: {
message: 'Validator "Name cannot be blank" failed for path name',
name: 'ValidatorError',
path: 'name',
type: 'Name cannot be blank' }
}
How do I iterate through the properties of each "current context" object?
I would think you do something like this:
{#errors}
{#.}
{type}
{/.}
{/errors}
If you really have to put meaningful data into object keys, consider writing a contextual helper, as per:
https://github.com/akdubya/dustjs/issues/9
Dust.js output JSON key
It is not possible to iterate through members of an object in Dust. Part of the reason is that you cannot know the order of the members. Another part is that this is seen as bringing too much logic into Dust.
Instead, you can change the JSON to look more like this:
{
errors: [
{
hashed_password: {
message: 'Validator "Password cannot be blank" failed for path hashed_password',
name: 'ValidatorError',
path: 'hashed_password',
type: 'Password cannot be blank'
}
},
{
username: {
message: 'Validator "Username cannot be blank" failed for path username',
name: 'ValidatorError',
path: 'username',
type: 'Username cannot be blank'
}
},
{
email: {
message: 'Validator "Email cannot be blank" failed for path email',
name: 'ValidatorError',
path: 'email',
type: 'Email cannot be blank'
}
},
{
name: {
message: 'Validator "Name cannot be blank" failed for path name',
name: 'ValidatorError',
path: 'name',
type: 'Name cannot be blank'
}
]
}
You can iterate over an object using a helper.
For example, you could define a helper like this one:
dust.helpers.iter = function(chunk, context, bodies, params) {
var obj = dust.helpers.tap(params.obj, chunk, context);
var iterable = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var value = obj[key];
iterable.push({
'$key': key,
'$value': value,
'$type': typeof value
});
}
}
return chunk.section(iterable, context, bodies);
};
Then, in your template, you would loop through like this:
{#iter obj=errors}
{$value.type}
{/iter}

Resources