What must my Kendo datasource schema look like? - kendo-ui

given this json?
[
{
"CompanyId":20,
"CompanyName":"Walmart",
"CompanyContacts":[
{
"CompanyId":20,
"FirstName":"Bob",
"LastName":"Green",
"Email":"bob#test.com",
"Phone":"1234567",
"IsActive":false
}
]
}
]

The KendoUI datasource schema.Model does not currently support nested json or json with related entities. It needs flat data. Hopefully in the future the schema.Model will support mapping complex json to flat in the model definition. However you can still use complex data in the grid you just can't define it in a schema.Model definition.
The mapping is actually done in the field definitions of the grid.
In addition see schema docs you can parse your data using the schema.parse or schema.data functions to manually transform your nested data into flat data.
Here is a fiddle example with your data
{
field : "CompanyContacts[0].FirstName",
title: "First Name"
}
Also note, if you don't need parent record CompanyName and CompanyID since you have CompanyID in your CompanyContacts in the way your data is currently defined then you can use the data attribute of the schema to indicate the starting point of your records like so
schema : {
model: mySchema,
data: "CompanyContacts"
},

Related

GraphQL: No child/nested data available in response when parent is null?

I am facing problems with nullable fields when trying to use the data returned when executing my query.
Schema
A simplified schema for demonstration purpose:
type Query {
members: [Instrument!]!
}
type Instrument {
series: SeriesType!
...
}
type SeriesType {
dividendYield: SeriesMethods
...
}
type SeriesMethods{
latest: Float!
...
}
There is nullable data that is resolved at dividendYield and a typical response I get when executing the query is shown in the following section.
Typical Response
A picture of the query and response can be seen here.
So what is the problem???
We are using this data to for visuals on a web app. The data is read in as an object such that you are able to access the data by data.series.dividendYield.latest. The problem comes in when dividendYield returns null as there is there no longer exists a latest field anymore.
For the client side it will always be necessary for the field to be present in the data, even if the parent resolver is null. Is it possible for the resolvers to be setup such that all children fields also return null rather than not appearing in the data response? Any other solutions would also be appreciated.

GraphQL Schema Language Handle Map Type from Uncontrolled API [duplicate]

Let's say my graphql server wants to fetch the following data as JSON where person3 and person5 are some id's:
"persons": {
"person3": {
"id": "person3",
"name": "Mike"
},
"person5": {
"id": "person5",
"name": "Lisa"
}
}
Question: How to create the schema type definition with apollo?
The keys person3 and person5 here are dynamically generated depending on my query (i.e. the area used in the query). So at another time I might get person1, person2, person3 returned.
As you see persons is not an Iterable, so the following won't work as a graphql type definition I did with apollo:
type Person {
id: String
name: String
}
type Query {
persons(area: String): [Person]
}
The keys in the persons object may always be different.
One solution of course would be to transform the incoming JSON data to use an array for persons, but is there no way to work with the data as such?
GraphQL relies on both the server and the client knowing ahead of time what fields are available available for each type. In some cases, the client can discover those fields (via introspection), but for the server, they always need to be known ahead of time. So to somehow dynamically generate those fields based on the returned data is not really possible.
You could utilize a custom JSON scalar (graphql-type-json module) and return that for your query:
type Query {
persons(area: String): JSON
}
By utilizing JSON, you bypass the requirement for the returned data to fit any specific structure, so you can send back whatever you want as long it's properly formatted JSON.
Of course, there's significant disadvantages in doing this. For example, you lose the safety net provided by the type(s) you would have previously used (literally any structure could be returned, and if you're returning the wrong one, you won't find out about it until the client tries to use it and fails). You also lose the ability to use resolvers for any fields within the returned data.
But... your funeral :)
As an aside, I would consider flattening out the data into an array (like you suggested in your question) before sending it back to the client. If you're writing the client code, and working with a dynamically-sized list of customers, chances are an array will be much easier to work with rather than an object keyed by id. If you're using React, for example, and displaying a component for each customer, you'll end up converting that object to an array to map it anyway. In designing your API, I would make client usability a higher consideration than avoiding additional processing of your data.
You can write your own GraphQLScalarType and precisely describe your object and your dynamic keys, what you allow and what you do not allow or transform.
See https://graphql.org/graphql-js/type/#graphqlscalartype
You can have a look at taion/graphql-type-json where he creates a Scalar that allows and transforms any kind of content:
https://github.com/taion/graphql-type-json/blob/master/src/index.js
I had a similar problem with dynamic keys in a schema, and ended up going with a solution like this:
query lookupPersons {
persons {
personKeys
person3: personValue(key: "person3") {
id
name
}
}
}
returns:
{
data: {
persons: {
personKeys: ["person1", "person2", "person3"]
person3: {
id: "person3"
name: "Mike"
}
}
}
}
by shifting the complexity to the query, it simplifies the response shape.
the advantage compared to the JSON approach is it doesn't need any deserialisation from the client
Additional info for Venryx: a possible schema to fit my query looks like this:
type Person {
id: String
name: String
}
type PersonsResult {
personKeys: [String]
personValue(key: String): Person
}
type Query {
persons(area: String): PersonsResult
}
As an aside, if your data set for persons gets large enough, you're going to probably want pagination on personKeys as well, at which point, you should look into https://relay.dev/graphql/connections.htm

When do I use nested fields in GraphQL and when do I flatten them?

With GraphQL schemas, when should I provide a type relation's field as a root-level field for its associated type?
Example
In many examples, I almost always see schemas that require the client to create queries that explicitly traverse the graph to get a nested field.
For a Rock Band Table-like component in the front end (or client), the GraphQL service that provides that component's data may have a schema that looks like this:
type Artist {
name: String!
instrument: String!
}
type RockBand {
leadSinger: Artist,
drummer: Artist,
leadGuitar: Artist,
}
type Query {
rockBand: RockBand
}
If the table component specified a column called, "Lead Singer Name", given the current schema, a possible query to fetch table data would look like this:
{
rockBand {
leadSinger {
name
}
}
}
For the same Rock Band Table, with the same column and needs, why not design a schema like this:
type RockBand {
leadSinger: Artist,
leadSingerName: String,
drummer: Artist,
leadGuitar: Artist,
}
That way a possible query can be like this?
{
rockBand {
leadSingerName
}
}
Does the choice to include the "leader singer's name", and similar relation fields, entirely depend on the client's need? Is modifying the schema to serve data for this use-case too specific a schema? Are there benefits to flattening the fields outside of making it easier for the client? Are there benefits to forcing traversal through the relation to get at a specific field?

Apollo/GraphQL field type for object with dynamic keys

Let's say my graphql server wants to fetch the following data as JSON where person3 and person5 are some id's:
"persons": {
"person3": {
"id": "person3",
"name": "Mike"
},
"person5": {
"id": "person5",
"name": "Lisa"
}
}
Question: How to create the schema type definition with apollo?
The keys person3 and person5 here are dynamically generated depending on my query (i.e. the area used in the query). So at another time I might get person1, person2, person3 returned.
As you see persons is not an Iterable, so the following won't work as a graphql type definition I did with apollo:
type Person {
id: String
name: String
}
type Query {
persons(area: String): [Person]
}
The keys in the persons object may always be different.
One solution of course would be to transform the incoming JSON data to use an array for persons, but is there no way to work with the data as such?
GraphQL relies on both the server and the client knowing ahead of time what fields are available available for each type. In some cases, the client can discover those fields (via introspection), but for the server, they always need to be known ahead of time. So to somehow dynamically generate those fields based on the returned data is not really possible.
You could utilize a custom JSON scalar (graphql-type-json module) and return that for your query:
type Query {
persons(area: String): JSON
}
By utilizing JSON, you bypass the requirement for the returned data to fit any specific structure, so you can send back whatever you want as long it's properly formatted JSON.
Of course, there's significant disadvantages in doing this. For example, you lose the safety net provided by the type(s) you would have previously used (literally any structure could be returned, and if you're returning the wrong one, you won't find out about it until the client tries to use it and fails). You also lose the ability to use resolvers for any fields within the returned data.
But... your funeral :)
As an aside, I would consider flattening out the data into an array (like you suggested in your question) before sending it back to the client. If you're writing the client code, and working with a dynamically-sized list of customers, chances are an array will be much easier to work with rather than an object keyed by id. If you're using React, for example, and displaying a component for each customer, you'll end up converting that object to an array to map it anyway. In designing your API, I would make client usability a higher consideration than avoiding additional processing of your data.
You can write your own GraphQLScalarType and precisely describe your object and your dynamic keys, what you allow and what you do not allow or transform.
See https://graphql.org/graphql-js/type/#graphqlscalartype
You can have a look at taion/graphql-type-json where he creates a Scalar that allows and transforms any kind of content:
https://github.com/taion/graphql-type-json/blob/master/src/index.js
I had a similar problem with dynamic keys in a schema, and ended up going with a solution like this:
query lookupPersons {
persons {
personKeys
person3: personValue(key: "person3") {
id
name
}
}
}
returns:
{
data: {
persons: {
personKeys: ["person1", "person2", "person3"]
person3: {
id: "person3"
name: "Mike"
}
}
}
}
by shifting the complexity to the query, it simplifies the response shape.
the advantage compared to the JSON approach is it doesn't need any deserialisation from the client
Additional info for Venryx: a possible schema to fit my query looks like this:
type Person {
id: String
name: String
}
type PersonsResult {
personKeys: [String]
personValue(key: String): Person
}
type Query {
persons(area: String): PersonsResult
}
As an aside, if your data set for persons gets large enough, you're going to probably want pagination on personKeys as well, at which point, you should look into https://relay.dev/graphql/connections.htm

Meta data values of "Enum"

I created a field in a model named "Listing". The field in here is "category". This is set to enum of some values (screenshot below). Does graphql allow to query to fetch the enum list?
This is possible using a GraphQL introspection query.
Enum types on Graphcool are named "MODEL_FIELD", so in your case you can run this query:
{
__type(name: "LISTING_CATEGORY") {
name
enumValues {
name
}
}
}
You can find more information in this answer to a similar question.
An easier approach, when using Nexus.js, is to just create a new root type, and have it resolve to your array of ENUM values. This works because with Nexus.js you're writing your schema with code (TypeScript), which means you're able to import your array of ENUM values into the resolver — it's just code.

Resources