Cannot read property 'type' of undefined - ember.js

I tried setting my app in ember#2.5.0, but every time when I use store and try to use
this.store.findAll("user");
I always get the error saying Cannot read property 'type' of undefined.
Initialized the store, adapter and the model and server too.
adapters/application.js
import JSONAPIAdapter from 'ember-data/adapters/json-api';
export default JSONAPIAdapter.extend({
defaultSerialiser: "-default"
});
models/user.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr'
export default Model.extend({
"name": attr()
});
and server side it is like
app.get("/users", function(req, res) {
res.send({"name": "Surya"});
});
Getting error
TypeError: Cannot read property 'type' of undefined
at _pushInternalModel (store.js:1524)
at push (store.js:1501)
at finders.js:148
at Object.Backburner.run (ember.debug.js:678)
at _adapterRun (store.js:1733)
at finders.js:145
at tryCatch (ember.debug.js:53806)
at invokeCallback (ember.debug.js:53821)
at publish (ember.debug.js:53789)
at ember.debug.js:32054

You use the JSONAPI serializer and adapter, but your response
{
"user": {
"name": "Surya"
}
}
is not a valid JSONAPI response. It should be
{
"data": {
"type": "user",
"id": "0",
"attributes": {
"name": "Surya"
}
}
}

Related

Ember JS: Assertion Failed: `AdapterError` expects json-api formatted errors array

I am making my first Ember/Phoenix app using JSONAPIAdapter. When doing a post request Ember responds with Assertion Failed: AdapterError expects json-api formatted errors array.
Below is the relevant code:
adapter/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import config from '../config/environment';
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
});
serializers/application.js
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
});
request payload:
{
"data": {
"attributes": {
"name": ""
},
"relationships": {
"user": {
"data": {
"type": "users",
"id": "1"
}
}
},
"type": "listings"
}
}
response payload:
{"errors":{"name":["can't be blank"]}}
Why does Ember keeps giving me this error?
Your response payload is not correct. You are using json-api. So your payloads have to follow the json-api specification. Your request-payload looks correct. But check out how errors have to be serialized.
A json-api error response must contain a root key "errors" holding an array of error-objects. Regarding the documenation an error may contain several members, but the two most important are detail and source.
Here's an example:
{
"errors":[
{
"detail": "can't be blank",
"source": {
"pointer": "data/attributes/name"
}
}
]
}
The source-key contains a json-object holding a json-api-pointer. With the help of this pointer information ember's JSONAPI-Adapter adds the errors to the corresponding attributes of your record. Note that your backend needs to send a 422 HTTP status code (Unprocessable Entity).
If that works you can do something like that at client:
{{#each model.errors.name as |error|}}
<div class="error">
{{error.message}}
</div>
{{/each}}
How do you serialize your errors at backend? Are you using ja_serializer? If not, I would recommend it, because ja_serializer can serialize json-api-errors by default.
The documentation already linked by wuarmin clearly states (capitals theirs, italics mine):
Error objects MUST be returned as an array keyed by errors
Your API response' errors key has a single object as value, not an array.

Ember model relationship not matching API

I have two models who look like this:
// models/database.js
export default DS.Model.extend({
title: DS.attr(),
/*...*/
documents: DS.hasMany('document')
});
// models/document.js
export default DS.model.extend({
name: DS.attr(),
/*...*/
database: DS.belongsTo('database')
});
Is also have some routes
Router.map(function() {
this.route('databases', function() {
this.route('database', { path: ":database_id" }, function() {
this.route('documents');
});
});
});
When I call /database/[ID]/documents if got nothing.
I think the problem is I'm working with an JSON HAL API and when I ask for databases on API I receive this kind of response.
{
"_embedded": {
"databases": [
{
"_links": {
"self": {
"href": "<API_URL>/databases/7ec39267b544424c/",
"reference": "7ec39267b544424c",
"title": "00000006"
}
},
"database": {
"name": "00000006",
"reference": "7ec39267b544424c",
"title": "****"
}
},
{
"_links": {
"self": {
"href": "<API_URL>/databases/aace19af004144a4/",
"reference": "aace19af004144a4",
"title": "00000007"
}
},
"database": {
"name": "00000007",
"reference": "aace19af004144a4",
"title": "******"
}
}
}]
}
As you can see there no documents attributes on JSON returned.
If I want a database's documents I've got to call [API_URL]/databases/[ID]/domains/[ID]/documents
There's still a way to link documents to a database by specifying that the documents are recoverable at this URL (/databases/[ID]/domains/[ID]/Documents)?
I found the solution.
I've override extractRelationships method in hal serializer like this:
extractRelationships(modelClass, resourceHash, included) {
resourceHash._links["documents"] = {
"href" : "/databases/" + resourceHash.id + "/domains/" + (resourceHash.name || resourceHash[modelClass.modelName].name) + "/documents/"
};
return this._super(modelClass, resourceHash, included);
}
I just add a link to documents for each databases returned by the API.
I've modified my route for documents like this
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model() {
return this.modelFor('databases.database').get('documents');
}
});
And now it works perfectly.
I think what you're looking for is a HAL API to JSON API converter. To avoid doing this yourself manually I'd recommend the http://github.com/201-created/ember-data-hal-9000 Ember plugin, which I've used myself to get Ember Data to play nice with Spring Boot.
If you wanted to see a simple example here's my client-side and server-side demo app.
Additionally, if you were curious what Ember, and JSON API don't use HAL you can read here JSON API - FAQ on HAL.

Promise error because of bad format

I created a new RestAdapter like so.
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: 'api',
host: 'http://localhost:8081'
});
if i look at the network calls the api gets called properly and returns this data.
{
"environments": [
{
"Id": 1,
"LocalePath": "C:\\XML_DEPOT",
"Name": "Acceptation 1",
"RemotePath": "D:\\XML_DEPOT",
"DatabaseServerName": "somedata",
"DatabaseName": "somedata",
"Port": 60903
},
{
"Id": 2,
"LocalePath": "bob",
"Name": "Acceptation 2",
"RemotePath": "bob",
"DatabaseServerName": "somedata\\somedata",
"DatabaseName": "somedata",
"Port": 60904
}
]
}
and then i get an error saying that
Assertion Failed: normalizeResponse must return a valid JSON API
document
but from what i understand the adapter is not a JSONAPIAdapter so it shouldnt try to serialize it has a jsonapi ??
Ember Data is using JSON Api spec internally since version 1.13 as described in release notes. normalizeResponse method of DS.RestAdapter "is used to normalize a payload from the server to a JSON-API Document."
Your payload does not look like what ember data RestAdapater excepts as default. RestAdapter expects camelCase keys but yours are CamelCase. You have to customize your serializer keyForAttribute method to get it working.

Ember save() throws JSON.parse error: "unexpected end of data at line 1 column 1 of the JSON data"

I have a model record created and being saved through a route and controller. When I save the record through the controller (via a savePlace action), I am seeing this error in the JS console:
SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
I've tried not setting anything on the model as well as setting dummy data on the model, but I get the same error. I am also user ember-cli http-mocks as a test backend to handle JSON responses. I realize it may be the response, but I'm not sure how else to configure the response.
Here's the relevant code:
routes/places/new.js:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('place');
},
});
controllers/places/new.js:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
saveGeom(geom) {
this.get('model').set('geometry', geom);
},
savePlace(data) {
this.get('model').set('name', this.get('name')).set('description', this.get('description'));
this.get('model').save().then(function() {
alert("SUCCESS");
}, function(error) {
console.log(error);
});
}
}
});
server/mocks/place.js:
placeRouter.post('/places', function(req, res) {
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.send({
"places": {
id: 1,
name: "Triangle",
description: "Ryan Christiani",
geometry: {
"type": "Polygon",
"coordinates": [
[
[-84.32281494140625,34.9895035675793],
[-81.73690795898438,36.41354670392876],
[-83.616943359375, 34.99850370014629],
[-84.05639648437499,34.985003130171066],
[-84.22119140625, 34.985003130171066],
[-84.32281494140625,34.9895035675793]
]
]
}
}
});
});
Thanks!
I think you are using the wrong brackets in the wrong places in your JSON Object.
Check out this page
http://www.tutorialspoint.com/json/json_syntax.htm
The http-mocks configuration is wrong. It should be this the code snippet below. The server was instead responded with an array of objects (the response for 'GET /'). Not sure why that would trigger a JSON.parse error, but this is the correct configuration.
placeRouter.post('/', function(req, res) {
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.send({
'places': [
{
id: 1,
name: "Using Ember CLI to create a Fixture Adapter.",
description: "Ryan Christiani",
geometry: {
"type": "Polygon",
"coordinates": [
[
[-84.32281494140625,34.9895035675793],
[-81.73690795898438,36.41354670392876],
[-83.616943359375, 34.99850370014629],
[-84.05639648437499,34.985003130171066],
[-84.22119140625, 34.985003130171066],
[-84.32281494140625,34.9895035675793]
]
]
}
}]});
});

How to get the return data of a save with Ember Data?

I'm using Ember.js with ember-data to make a GUI for a self made API.
I've been following this tutorial to handle authentication but I want to use ember-data instead of custom jQuery requests.
One thing I have to do is to call the API to create a new session, by sending email and password, and the API sends me back an API Key object.
Here is my LoginController handling the loginUser action (it's CoffeeScript) :
App.LoginController = Ember.ObjectController.extend
actions:
loginUser: ->
session = #store.createRecord 'session',
email: #get 'email'
password: #get 'password'
session.save()
Here is the result I get when creating a session:
{
"users": [
{
"id": "525fa0286c696c0b14040000",
"email": "john.doe#mydomain.com",
"first_name": "John",
"surname": "Doe"
}
],
"api_key": {
"id": "526e464c6c696c07d2000000",
"type": "session",
"key": "6b824d6a-a065-4b6f-bb28-5c19389760f8",
"expires_at": "2013-10-28T11:41:08+00:00",
"user_id": "525fa0286c696c0b14040000"
}
}
I have Session, ApiKey and User models. I can create the session, but the thing I don't understand is how to access the return value of the save() method.
I know that my ApiKey and User are loaded somewhere because I get an error after save() if their respective Ember model don't exist but I don't know how to access them.
I've tried to use save() callbacks like then() or didCreate event but there's a lack of documentation about arguments passed to these callbacks and how to use them.
Ember.js 1.1.2
Ember Data 1.0.0.beta.3
EDIT:
I've tried to create an actuel Session model on my API, resulting in this JSON output:
{
"api_keys": [
{
"id": "526f69526c696c07d2110000",
"type": "session",
"key": "4c26af37-2b21-49c2-aef5-5850a396da0b",
"expires_at": "2013-10-29T08:22:50+00:00",
"user_id": "525fa0286c696c0b14040000"
}
],
"users": [
{
"id": "525fa0286c696c0b14040000",
"email": "john.doe#coreye.fr",
"first_name": "John",
"surname": "Doe"
}
],
"session": {
"id": "526f6e666c696c18c0010000",
"api_key_id": "526f69526c696c07d2110000"
}
}
(note the root element is now session)
It doesn't work better because now my save action leads to the following error (not in the console but then points to error callback):
Object function () { [...] } has no method 'eachTransformedAttribute'
I get this error, the relation between Session and ApiKey being declared in Ember Data models or not...
Your second example JSON looks better: since you are saving a Session, I would expect a session node in the response and other models to be side loaded. You can access the saved session after it's saved by using a promise callback:
session.save().then (savedSession) =>
console.log savedSession.api_key.key
Since you have _id relationship keys in your JSON, I assume you are using the ActiveModel adapter and its default serializer:
App.ApplicationAdapter = DS.ActiveModelAdapter.extend()