So I have a Spring Boot api returning a bunch of records in a list, like that:
[
{
"uid": 16587783,
"createdAt": 1391708660000,
"name": "FRaaS",
"fullName": "caarlos0/FRaaS",
"description": "Fake RT as a Service",
"homepage": "http://fraas.herokuapp.com/",
"owner": "caarlos0",
"organization": null,
"joined": false,
"private": false
},
....
more records
]
but when I try to read it in the template, I get the following error
WARNING: Encountered "0" in payload, but no model was found for model name "0" (resolved model name using chathub-ember#serializer:-rest:.modelNameFromPayloadKey("0"))
Here is my current adapter
import DS from 'ember-data';
import Ember from 'ember';
export default DS.RESTAdapter.extend({
host: 'http://127.0.0.1:8080/v1',
primaryKey: 'uid',
headers: Ember.computed('session.data.authenticated.currentUser.backendAccessToken', function() {
return {
"Auth-Token": this.get("session.data.authenticated.currentUser.backendAccessToken"),
};
})
});
what can I do in ember to allow it to read the data as I sent? I can change the API if needed, but I would rather not to
You need to use RESTSerializer. And primaryKey is for serializer not adapter. I think you use json serializer in your app.
UPDATE
Add below to your application serializer
normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) {
let typeKey = primaryModelClass.modelName;
let ret = {};
ret[typeKey] = payload;
return this._normalizeResponse(store, primaryModelClass, ret, id, requestType, true);
},
normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
let pluralTypeKey = Ember.Inflector.inflector.pluralize(primaryModelClass.modelName);
let ret = {};
ret[pluralTypeKey] = payload;
return this._normalizeResponse(store, primaryModelClass, ret, id, requestType, false);
}
Related
i use com.github.ChiliLabs:ChiliPhotoPicker:0.3.1 to select photos to upload. It gives me such a path to the photo
file:///storage/emulated/0/KatePhotos/1641933129.jpg
my code for uploading the image to the server
fun formData(uri: ArrayList<Uri>) {
// Create Retrofit
val retrofit = Retrofit.Builder()
.baseUrl("https://httpbin.org")
.build()
// Create Service
val service = retrofit.create(APIService::class.java)
// List of all MIME Types you can upload: https://www.freeformatter.com/mime-types-list.html
// Get file from assets folder
val imgFile = File(uri[0].path)
val fields: HashMap<String?, RequestBody?> = HashMap()
fields["email"] = ("test#test.com").toRequestBody("text/plain".toMediaTypeOrNull())
val filename = imgFile.name
fields["file\"; filename=\"$filename\" "] =
(imgFile).asRequestBody("image/*".toMediaTypeOrNull())
CoroutineScope(Dispatchers.IO).launch {
// Do the POST request and get response
val response = service.uploadEmployeeData(fields)
withContext(Dispatchers.Main) {
if (response.isSuccessful) {
// Convert raw JSON to pretty JSON using GSON library
val gson = GsonBuilder().setPrettyPrinting().create()
val prettyJson = gson.toJson(
JsonParser.parseString(
response.body()
?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
)
)
println(prettyJson)
} else {
Log.e("RETROFIT_ERROR", response.code().toString())
}
}
}
}
The problem is that when I use decoding on the server, I only get a piece of the image. Tell me what I'm doing wrong and how can I fix it?
Its my response:
{
"args": {},
"data": "",
"files": {
"file": "data:image/*;base64,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
},
"form": {
"email": "test#test.com"
},
"headers": {
"Accept-Encoding": "gzip",
"Content-Length": "387553",
"Content-Type": "multipart/form-data; boundary\u003da3942d3b-e13b-43de-9abd-642750914c37",
"Host": "httpbin.org",
"User-Agent": "okhttp/4.9.0",
"X-Amzn-Trace-Id": "Root\u003d1-61ddfc53-4b83816821e2302e6f2b8951"
},
"origin": "",
"url": "https://httpbin.org/post"
}
and so I see what php saves, even notepad considers it to be text.
In decode i see
I want to define a model class in angular8 for the below nested JSON response.
JSON Response:
{
"message": "All Users fetched",
"status": "Success",
"data": [
{
"userid": "abc22",
"password": "abc22",
"role": 1,
"sessionid": "AWS1",
"sessiontype": "RC01",
"status": null
}
]
}
I am not sure how to do it for the nested JSON response. Could someone help me with it.
Lets assume that all the datatypes of the above fields are String. Thanks in advance
I assume you often have the response with message and status fields, but that the structure of the data field is different for different requests. In that case, I'd recommend you do a generic interface like this:
export interface ApiResponse<T> {
message: string,
status: "Success" | "Error", // Add more possible status responses if needed
data: T
}
The user model would look something like this:
export interface User {
userId: string,
password: string,
role: number,
sessionid: string
sessiontype: string,
status: string // Or whatever type this should be
}
Now you can create a type alias like this:
type UserResponse = ApiResponse<User[]>
And use it with Angular's http service like this:
this.http.get<UserResponse>('/api/endpoint/to/userlist')
.subscribe(resp => {
console.log(resp.data) // This should print out the list of users
})
*Edit*
It should be noted that I'm using interfaces instead of classes, because that's usually what you want to do in angular. Interfaces don't generate any javascript code when compiled, they just help you with the typechecking during development. There will be no checking of the data structure during runtime, so if your response doesn't actually look like that you may run into problems.
You could do something like this:
class User {
userId: string;
password: string;
role: number;
sessionid: string;
sessiontype: string;
status: string;
}
class Response {
message: string;
status: string;
data: User[];
}
const jsonData = {
"message": "All Users fetched",
"status": "Success",
"data": [
{
"userid": "abc22",
"password": "abc22",
"role": 1,
"sessionid": "AWS1",
"sessiontype": "RC01",
"status": null
}
]
}
const response = new Response();
response.message = jsonData.message;
response.status = jsonData.status;
response.data = jsonData.data.map(userData => {
const user = new User();
user.userId = userData.userId;
});
I am accessing the api of world weather online. I have configured the url and it is displayed below-
http://api.worldweatheronline.com/premium/v1/marine.ashx?key=XXXXXXXXXXXXXXXX&q=-34.48,150.92&format=json
Note: my API key is displayed as XXXXXXXXXXXX and this is returning the following:
{
"data": {
"request": [],
"weather": [
{
"date": "2016-11-20",
"astronomy": [],
"maxtempC": "27",
"maxtempF": "80",
"mintempC": "15",
"mintempF": "58",
"hourly": [
{
"time": "0",
"tempC": "15",
...
I want to GET this json in JS and then log the value of TempC.
How can this be done?
The simplest way would be using request. You can install it with npm install request
const request = require('request')
const apiKey = 'XXXXXXXX'
let url = 'http://api.worldweatheronline.com/premium/v1/marine.ashx'
let qs = {
q: '-34.48,150.92',
format: 'json',
key: apiKey
}
request({ url, qs }, (err, response, body) => {
if (err)
return console.error(err)
if (response.statusCode != 200)
return console.error('status:', response.statusCode, body)
body = JSON.parse(body)
console.log(body.data.weather[0].hourly[0].tempC)
})
I receive the following error when I use Ember Data to create records from a JSON response. What gives? I am following what the docs state.
Uncaught Error: Assertion Failed: Ember Data expected a number or string to represent the record(s) in the `user` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `user` property in your serializer's attrs object.
JSON being parsed:
[
{
"id": 76,
"title": "Title",
"shipped": 0,
"date": "2015-05-21T05:00:00.000Z",
"user": {
"firstName": "First Name",
"lastName": "Last Name",
"email": "hellothere#gmail.com",
"id": 1
}
}
]
Shipment Model:
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
user: DS.belongsTo('user', { async: false })
});
Route:
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel: function() {
if(!localStorage.accessToken) {
this.transitionTo('login');
}
},
model: function() {
var shipmentObjects = [];
var App = this;
Ember.$.getJSON('http://localhost:1337/subscription/1/shipments/upcoming', function(shipments) {
shipments.forEach(function(data) {
var shipment = App.store.push('shipment', data);
shipmentObjects.pushObject(shipment);
});
});
return shipmentObjects;
}
});
You can create a custom serializer, if you can't modify your json response and manage to arrange data in other way
App.MODELNAMESerializer = DS.ActiveModelSerializer.extend({
extract: function(store, type, payload, id, requestType){
var shipments = [];
//CREATE A NEW PAYLOAD THAT EMBER CAN READ
var _payload = { };
return this._super(store, type, _payload, id, requestType);
}
});
Your json should look something like this
{
shipments: [
{
"id": 76,
"title": "Title",
"shipped": 0,
"date": "2015-05-21T05:00:00.000Z",
"user_id": 1,
}
],
"users": [
{
"firstName": "First Name",
"lastName": "Last Name",
"email": "hellothere#gmail.com",
"id": 1
}
]
}
Read the error message. It could hardly be clearer. By default, Ember Data expects an association to be represented by an ID. If the association is instead embedded, you must tell Ember Data that. You'll need something like:
// serializers/shipment.js
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
user: { embedded: 'always' }
}
});
And remove the {async: false}, since the data is embedded right there.
See http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html.
I receive a JSON from our API that has the following format
[
{
"id": 45,
"name": "Pasta",
"_order": 0,
"is_hidden": null,
"is_list": false
},
{
"id": 46,
"name": "Salads",
"_order": 1,
"is_hidden": null,
"is_list": false
},
{
"id": 47,
"name": "Dessert",
"_order": 2,
"is_hidden": null,
"is_list": false
}
];
I see that it has invalid format for standard RESTAdapter and I need to put the name of the model first. In my example it should probably be like:
{
"category":
[
{
"id": 45,
"name": "Pasta",
"_order": 0,
"is_hidden": null,
"is_list": false
},
{
"id": 46,
"name": "Salads",
"_order": 1,
"is_hidden": null,
"is_list": false
},
{
"id": 47,
"name": "Dessert",
"_order": 2,
"is_hidden": null,
"is_list": false
}
]
}
So how to make it look this way in my adapter? It seems like I should use DS.RESTSerializer, but I can't figure out which method I should override...
I ran into this issue earlier today. A nice clean way to fix it is to define a
normalizePayload method for your ApplicationSerializer. It's made to be overwritten, so you aren't affecting anything else.
E.g.
App.ApplicationSerializer = DS.RESTSerializer.extend({
normalizePayload: function(type, payload) {
return { category: payload };
}
}
If you want to do this on only some of the payloads processed then you just add a conditional inside it.
App.ApplicationSerializer = DS.RESTSerializer.extend({
normalizePayload: function(type, payload) {
if (type.toString() === 'App.Category') {
return { category: payload };
}
}
}
For more info on the normalizePayload method see http://emberjs.com/api/data/classes/DS.RESTSerializer.html#method_normalizePayload
In general, you'll probably want to implement a couple of methods in your serializer if you have to tweak your JSON:
App.ApplicationSerializer = DS.RESTSerializer.extend({
normalize: function(type, hash, prop) {
// change your incoming JSON to ember-style here
},
serialize: function(record, options) {
// change your outgoing ember-data record to your server's JSON here
}
});
EDIT:
You may also in your case need to override extractArray as well: http://emberjs.com/api/data/classes/DS.RESTSerializer.html#method_extractArray
Neither normalizePayload nor normalize is working for me. What I am doing is:
// app/serializers/application.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
extractArray: function(store, type, payload) {
var payloadTemp = {}
payloadTemp[type.typeKey] = payload;
return this._super(store, type, payloadTemp);
},
extractSingle: function(store, type, payload, id) {
var payloadTemp = {}
payloadTemp[type.typeKey] = [payload];
return this._super(store, type, payloadTemp, id);
}
});
Just nest the object represented by your JSON string inside a new object which adds the new property needed and then convert back to JSON. Like this:
var yourInitialJSONString; // your JSON from API
var obj = JSON.parse(yourInitialJSONString);
var newObj = {
category: obj
};
var finalJSON = JSON.stringify(newObj);
Alternatively, though probably only best for simple case and not as universally useful as working with actual objects, you could simply concatenate to your JSON:
var yourInitialJSONString; // your JSON from API
var finalJSON = '{"category":' + yourInitialJSONString + '}';
These might prove faster for simple use cases as you avoid deserialization and serialization. I just don't like it as much as I would rather work with actual objects represented by the data. If you need to do a more complex transformation it would probably prove to be more understandable in real word terms than doing a bunch of string concatenation/manipulation.