The response to 'getList' must be like { data : [...] } , but the received data is not an array. React admin error - react-admin

The response to 'getList' must be like { data : [...] }, but the received data is not an array. The dataProvider is probably wrong for 'getList'
Response
{
"data": [
{
"id": 6,
"product_title": "Foam chair",
"product_description": "Fantastic Foam chair",
},
{
"id": 5,
"product_title": "Shinez cleaning liquid",
"product_description": "Shinez cleaning liquid shoes is good for electronics",
},
{
"id": 4,
"product_title": "Shinez cleaning liquid buy 1 get 1 free",
"product_description": "Shinez cleaning liquid shoes is a good for electronics and computers",
},
{
"id": 3,
"product_title": "Raj kiran Motor cycle",
"product_description": "Raj kiran Motor cycle old one",
},
{
"id": 2,
"product_title": "Ka ka cycle broken cycle",
"product_description": "Ka ka cycle broken into multiple pieces",
},
{
"id": 1,
"product_title": "ka ka police cap",
"product_description": "This is police cap used by ka team",
}
]
}
But still I get the
The response to 'getList' must be like { data : [...] }, but the received data is not an array. The dataProvider is probably wrong for 'getList'
here is the actual code
<BrowserRouter>
<Admin catchAll={NotFound}
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={myLoginPage} >
</Admin>
</BrowserRouter>
I am using django rest framework as backend and using 'ra-data-django-rest-framework'
Need help on this. Thanks a lot.
Had a look at the following questions
React-Admin "Get List" DataProvider
The response to 'GET_LIST' must be like { data : [...] }, but the received data is not an array
const fetchJson = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
// Not working even if add content-range
// Content-Range: posts 0-24/319,
//adding console.log , returns undefined here
console.log( fetchUtils.fetchJson );
return fetchUtils.fetchJson(url, options);
}
const dataProvider = drfProvider('http://127.0.0.1:8000/api', fetchJson);
Imp. info: I am receiving the response on request.
adding console.log , returns undefined.

The solution , it expects the response in this format
{
"count": 10,
"next": "http://127.0.0.1:8000/api/products/?page=2",
"previous": null,
"results": [
{
"id": 10,
"product_title": "Crompton pedastal fan",
"product_description": "Nice Crompton pedastal fan",
},
{
"id": 10,
"product_title": "Crompton pedastal fan",
"product_description": "Nice Crompton pedastal fan",
}
]
}
Digging deep opens up that, it works seamlessly with class-based views like generics view, I was using function-based view in Django. Now I changed to class based view, everything is working cool.
class ProductList (generics.ListCreateAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer

Related

Why is my Swift UI Api fetching code not working

I am very new to swift ui so this is probably something very dumb that i missed. I am trying to make a program that gets the current weather description from the “current weather” OpenWeatherMap api. I followed this api tutorial and was able to get it to function with the giphy api used in the video, but when I tried to adapt it for the weather api it stoped functioning. There are no errors, just the button does nothing. Thanks in advance:)
Api response:
{
"coord": {
"lon": -122.08,
"lat": 37.39
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 282.55,
"feels_like": 281.86,
"temp_min": 280.37,
"temp_max": 284.26,
"pressure": 1023,
"humidity": 100
},
"visibility": 16093,
"wind": {
"speed": 1.5,
"deg": 350
},
"clouds": {
"all": 1
},
"dt": 1560350645,
"sys": {
"type": 1,
"id": 5122,
"message": 0.0139,
"country": "US",
"sunrise": 1560343627,
"sunset": 1560396563
},
"timezone": -25200,
"id": 420006353,
"name": "Mountain View",
"cod": 200
}
My code:
import SwiftUI
struct ContentView: View {
#State var currentWeather = String()
var body: some View {
Text("\(currentWeather)")
Button("fetch weather"){fetchAPI()}
}
func fetchAPI() {
let url = URL(string:"api.openweathermap.org/data/2.5/weather?q=Raleigh&appid=(ApiKey)")
//api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}
URLSession.shared.dataTask(with: url!) { data, response, error in
if let data = data {
if let decodedWeather = try? JSONDecoder().decode(WeatherStructure.self, from: data){
self.currentWeather = decodedWeather.weather.discription
}
}
}.resume()
}
}
struct WeatherStructure: Decodable {
let weather: dataStructure
}
struct dataStructure: Decodable {
let discription: String
}
Api documentation
Problems:
weather should be an array, since the JSON has an array.
description was spelt incorrectly as discription.
The URL must start with https://.
You need to change your Decodable structs to this:
struct WeatherStructure: Decodable {
let weather: [DataStructure]
}
struct DataStructure: Decodable {
let description: String
}
Which also results in this line changing:
decodedWeather.weather.description
And the URL changed to:
let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=Raleigh&appid=APP_ID")
Note: I also renamed dataStructure to DataStructure, since in Swift you should start struct names with a capital letter.

Is it possible to extend graphql response other than just data for pagination?

In GraphQL response normally looks like followings.
{
"data": [{
"id": 1,
"username": "Jon Snow",
"email": "crow#northofthew.all",
"age": 20
}, {
"id": 2,
"username": "Tyrion Lannister",
"email": "drunk#i.mp",
"age": 34
}, {
"id": 3,
"username": "Sansa Stark",
"email": "redhead#why.me",
"age": 17
}]
}
Is it possible to add meta data to your response such as pagination like this.
{
"pagination": {
"total": 14,
"count": 230,
},
"data": [{
"id": 1,
"username": "Jon Snow",
"email": "crow#northofthew.all",
"age": 20
}, {
"id": 2,
"username": "Tyrion Lannister",
"email": "drunk#i.mp",
"age": 34
}]
}
I'm using express-graphql and currently put those pagination to custom response header, which is fine but it can be better. Since GraphQL response is already wrapped with "data", it is not very strange to add more "data" to its response.
Reenforcing what #CommonsWare already stated, according to the specification that would a be an invalid GraphQL response. Regarding pagination, Relay has its own pagination approach called connections, but indeed, several other approaches are possible and even more suitable in some situtations (connections aren't a silver bullet).
I want to augment what was already said by adding that the hierarchical nature of GraphQL incites related data to be at the same level. An example is worth a thousands words, so here it goes:
query Q {
pagination_info { # what is this info related to? completely unclear
total
count
}
user {
friends {
id
}
}
}
Instead...
query Q {
user {
friends {
pagination_info { # fairly obvious that this is related to friends
total
count
}
friend {
id
}
}
}
}

How to use dojox/data/JsonRestStore with dojox/grid/LazyTreeGrid?

I have now this code:
define([
"dojo/_base/declare",
"dojox/data/JsonRestStore",
"dojox/grid/LazyTreeGrid",
"dojox/grid/LazyTreeGridStoreModel"
], function(
declare,
JsonRestStore,
LazyTreeGrid,
LazyTreeGridStoreModel
) {
var layout = { ... },
store = new JsonRestStore({
target: "/api/items" // for example
limitParam: "limit",
offsetParam: "offset"
}),
model = new LazyTreeGridStoreModel({
serverStore: true,
store: store,
childrenAttrs: [ "children" ]
});
return declare("CustomTreeGrid", [ LazyTreeGrid ], {
treeModel: model,
structure: layout
});
});
My widget send thousand requests to target URL after startup and freeze my browser. How to fix wrong behavior and save compatibility with RESTful API?
Solution with QueryReadStore work, but not in my situation - Django REST Framework return page with API declaration on GET requests.
Server return data in JSON format:
{
"items": [ ] //Array of items
"identifier": "id",
"numRows": 12 // Total count of items
}
Also I change the server response for returning array. Response headers also contain key "Content-Range: 0-2/3" (for example) and it's not work for me.
Server response headers:
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Range: items 0-1/2
Content-Type: application/json
Vary: accept
Server response body:
[
{
"id": 1,
"children": false,
"name": "name1"
},
{
"id": 2,
"children": false,
"name": "name2"
}
]
It is pretty hard to make a jsfiddle out of it because you need the server part as well.
I found this implementation: https://github.com/jeremyg484/dojo-json-rest-store
It uses a combination of : dojo.store.Cache, dojo.store.JsonRest, dojo.store.Memory and dojo.data.ObjectStore
Maybe you can do something with it...
See how it is used :
myStore = dojo.store.Cache(dojo.store.JsonRest({target:"usstates/"}), dojo.store.Memory());
grid = new dojox.grid.DataGrid({store: dataStore = dojo.data.ObjectStore({objectStore: myStore})

Ember-data hasMany relationship not working (JSONAPIAdapter)

I'm using Ember-Data v.1.13.9 with Ember-CLI v.1.13.8. I'm using the JSONAPIAdapter adapter.
I have a problem with a hasMany relationship. I can see from the Ember inspector that both the main record and the related record are being loaded into the store. However, the relationship doesn't seem to be there since I cannot access the related records details in my template.
models/invoice.js
export default DS.Model.extend(
{
invNum : DS.attr('string'),
created : DS.attr('date', {defaultValue: function() { return new Date(); }}),
clientId : DS.attr('number'),
userId : DS.attr('number'),
details : DS.hasMany('invoice-detail', {async : true}),
});
models/invoice-detail.js
export default DS.Model.extend(
{
invoice : DS.belongsTo('invoice', {async : true}),
detail : DS.attr('string'),
amount : DS.attr('number'),
vat : DS.attr('number'),
});
my JSON data: (URL: /accounts/invoices/1)
{
"data": {
"id": 1,
"attributes": {
"inv-num": "A0011000001",
"created": "November, 01 2000 00:00:00",
"user-id": 2,
"client-id": 14,
"relationships": {
"details": {
"data": [
{
"id": 1,
"type": "invoice-detail"
}
]
}
}
},
"type": "invoice"
},
"included": [
{
"id": 1,
"attributes": {
"amount": 3000,
"detail": "Stage 1 delivery of 3Com Reseller Locator to\r\nFoundation Network LTD",
"vat": 525
},
"type": "invoice-detail"
}
]
}
I've tried accessing the details related array directly:
{{#each model.details as |detail index|}}
{{index}} : {{detail.detail}} £{{detail.amount}} (£{{detail.vat}} vat)
{{/each}}
And by using a controller: invoice/controller.js
export default Ember.Controller.extend({
invoiceDetails : function()
{
var invoice = this.get("model");
var details = invoice.get("details");
Ember.Logger.log("invoiceDetails",invoice,details);
return details;
}.property('model.details'),
});
and
{{#each invoiceDetails as |detail index|}}
{{index}} : {{detail.detail}} £{{detail.amount}} (£{{detail.vat}} vat)
{{/each}}
Neither is providing me with the data that I require.
What am I doing wrong?
A second related issue I am having is that I can't get it to reload data from the server. the {reload:true} makes no difference. Looking at the network traffic I can see that no call to the server is made for second and subsequent visits to this route.
invoice/route.js
export default Ember.Route.extend({
model: function(params) {
return this.store.findRecord('invoice', params.id, { reload: true });
}
})
What I actually want to do here is have one route which retrieves a list of invoices (without the details part - so it's quick to retrieve since I do not need the details on the list page). Then, when I drill down to a specific invoice, make a call to the server to get the full details for that invoice. My plan was to use the shouldReloadRecord function to check if I have details attached to this record or not. If so, use the copy from the store, if not, go to the server and then overwrite the limited "list" record I got initially. As a stepping stone in that direction I figured that just setting {reload:true} in the route would force all requests to go back to the server.
I guess I've misunderstood something somewhere...?

How do you get all the email body parts? And how do you know how many parts exist?

I'm trying to read emails responded by the Gmail API.
I have trouble accessing all the "parts". And don't have great ways to traverse through the response. I'm also lost as to how many parts can exist so that I can make sure I read the different email responses properly. I've shortened the response below...
{ "payload": { "mimeType": "multipart/mixed", "filename": "",
], "body": { "size": 0 }, "parts": [ {
"body": {
"size": 0
},
"parts": [
{
"partId": "0.0",
"mimeType": "text/plain",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/plain; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 2317,
"data": "RGVhciBNSVQgQ2x1YiBWb2x1bnRlZXJzIGluIEFzaWEsDQoNCkJ5IG5vdyBlYWNoIG9mIHlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBpbnZpdGF0aW9ucyB0byB0aGUgcmVjZXB0aW9ucyBpbiBib3RoIFNpbmdhcG9yZSBhbmQgSG9uZyBLb25nIHdpdGggUHJlc2lkZW50IFJlaWYgb24gTm92ZW1iZXIgNyBhbmQgTm92ZW1iZXIg"
}
},
{
"partId": "0.1",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 9116,
"data": "PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2UvMjA"
}
}
] }, {
"partId": "1",
"mimeType": "text/plain",
"filename": "",
"body": {
"size": 411,
"data": "X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NClRoYW5rIHlvdSBmb3IgYWxsb3dpbmcgdXMgdG8gcmVhY2ggeW91IGJ5IGVtYWlsLCB0aGUgbW9zdCBpbW1lZGlhdGUgbWVhbnMgZm9yIHNoYXJpbmcgaW5mb3JtYXRpb24gd2l0aCBNSVQgYWx1bW5pLiANCklmIHlvdSB3b3VsZCBsaWtlIHRvIHVuc3Vic2NyaWJlIGZyb20gdGhpcyBtYWlsaW5nIGxpc3Qgc2VuZCBhIGJsYW5rIGVtYWlsIHRvIGxpc3RfdW5zdWJzY3JpYmVAYWx1bS5taXQuZWR1IGFuZCBwdXQgdGhlIGxpc3QgbmFtZSBpbiB0aGUgc3ViamVjdCBsaW5lLg0KRm9yIGV4YW1wbGU6DQpUbzogbGlzdF91bnN1YnNjcmliZUBhbHVtLm1pdC5lZHUNCkNjOg0KU3ViamVjdDogYXNpYW9mZg0K"
} } ] } }
Is there something I'm missing?
A MIME message is not just an array it's a full blown tree structure. So you'll have to traverse it to correctly handle it. Luckily JSON parsers are plentiful and the problem can easily be handled with recursion. In many languages there exist very useful email parsing libraries that can make accessing traditional parts (e.g. the text/plain or text/html displayable part, or attachments) not too laborious.
You'll have to set up walker functions to traverse through the json and pick out the bits you are after. Here is a part of what I wrote. This may help you jumpstart your code. NOTE: this is used inside of wordpress...hence the special jQuery call. Not needed if you do not need to use jquery inside wordpress.
function makeApiCall() {
gapi.client.load('gmail', 'v1', function() {
//console.log('inside call: '+myquery);
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'q': myquery
});
request.execute(function(resp) {
jQuery(document).ready(function($) {
//console.log(resp);
//$('.ASAP-emailhouse').height(300);
$.each(resp.messages, function(index, value){
messageId = value.id;
var messagerequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': messageId
});//end var message request
messagerequest.execute(function(messageresp) {
//console.log(messageresp);
$.each(messageresp, responsewalker);
function responsewalker(key, response){
messagedeets={};
$.each(messageresp.payload.headers, headerwalker);
function headerwalker(headerkey, header){
if(header.name =='Date'){
d = new Date(header.value);
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1; //Months are zero based
var curr_year = d.getFullYear();
var formatteddate = curr_month+'/'+curr_date+'/'+curr_year;
messagedeets['date']=formatteddate;
//$('.ASAP-emailhouse').append('<p>'+header.value+'</p>');
}
if(header.name =='Subject'){
//console.log(header.value);
messagedeets.subject=header.value;
}
}
messagedeets.body = {};
$.each(messageresp.payload.parts, walker);
function walker(partskey, value) {
//console.log(value.body);
if (value.body.data !== "undefined") {
//console.log(value.body);
var messagebody = atob(value.body.data);
messagedeets.body.partskey = messagebody;
}
console.log(messagedeets);
$('.ASAP-emailhouse').append('<div class="messagedeets"><p class="message-date">'+messagedeets.date+': <span class="message-subject">'+messagedeets.subject+'</span></p><p>'+messagedeets.body.partskey+'</p></div>');
}//end responsewalker
//$('.ASAP-emailhouse').append('</li>');
}
//$('.ASAP-emailhouse').append('</ul>');
});//end message request
});//end each message id
});//end jquery wrapper for wordpress
});//end request execute list messages
});//end gapi client load gmail
}
The MIME parts you are looking for are in an array. JSON does not tell you up front how many items are in an array. Even MIME itself does not provide a way of knowing how many parts are present without looking at the entire message. You will just have to traverse the entire array to know how many parts are in it, and process each part as you encounter it.
To know how much parts exists, you can just use the Length property.
Example :
json.payload.parts.length
For your example, this property is 2 because there are 2 parts.