Reputation: 1964
Is there a library to ease the creation of an object using typical Type defaults (string = '', number = 0, boolean = false etc), based on a graphql query and a schema (to hint the generated default). Given a query, it should be able to create a JS object representation of the data that WILL be returned from the server, but just using reasonable type defaults based on the schema. This has nothing to do with data returned from the server, I want a mirror object with default scalar values created from a Graqhql query that has not even been sent to the server, just a simple conversion.
Let's say there is a schema for the following query being introspected from some server:
graphql query eg:
query fetchProfile ($id: ID!){
profile(id: $id){
contact {
addresses {
line1
line2
street {
name
location {
name
city {
name
}
}
}
}
mobiles {
number
}
fixed {
number
}
faxes {
number
}
emailaddresses {
address
}
}
}
}
I want that query to be converted to the following automatically before use (this isn't the response from the server, it's just the object which is going to be merged with server results. And we are able to use this default obj without server response or a server at all and not crash the app.) [edit]: this is what I am already doing manually as Vue data props for v-models etc. and is what I want automatically generated from a query I write above. I just generalised this a bit to disambiguate the issue:
let profile = {
contact: {
addresses: [
{
line1: '',
line2: '',
street: {
name: '',
location: {
name: '',
city: {
name: '',
},
},
},
},
],
mobiles: [
{ number: 0 },
],
fixed: [
{ number: 0 },
],
faxes: [
{ number: 0 },
],
emailAddresses: [
{ address: '' },
],
},
}
Notice that the code is nearly identical. This is where the pain is. Imagine making schema changes and trying to fix those changes in many places in the code query and defaults.
I am currently doing that already manually and it works, coupled with a small util I made to merge in defaults on each query response in case some results or the entire query returns null. So I end up with two things: the query and the default obj I can immediately act on before I make the query to the server. It's so painful writing the query and the defaults, which is basically the same thing.
So I want to be able to write a query once, then use that query to make a js object I can use even before the server query is done (using reactivity in Vue). I don't want to do this:
if(profile && profile.contact && profile.contact.mobiles.length){
// do something cool-after checking :(
profile.contact.mobiles.map(m=>m.number).join(', ')
}
// or this, this doesn't work with Vue reactive props and v-model
_.get(profile, 'contact.mobiles', []).map(m=>m.number).join(', ')
to avoid ... of undefined
errors, I just DO :
// do something cool-directly without checking :)
profile.contact.mobiles.map(m=>m.number).join(', ')
Note that even putting nulls on scalar values is ok, which may not even need any schema introspection:
profile: {
contact: {
addresses: [
{
line1: null,
line2: null,
street: {
name: null,
location: {
name: null,
city: {
name: null,
},
},
},
},
],
mobiles: [
{ number: null },
],
fixed: [
{ number: null },
],
faxes: [
{ number: null },
],
emailAddresses: [
{ address: null },
],
},
}
So, is there a lib to do this or how do I do this?
Upvotes: 1
Views: 1839
Reputation: 4348
let me see if I can help you with this question.
You are definitively not the first person trying to generate default objects out of Query definitions (been there, done that). And I must say that I did not find any answer to this rather than write your own builder for this, I mean:
You will need to get the introspection schema(or maybe you already have it around your files, I will usually have a script to add the introspection schema as part of the build), then parse this file to get the Types and later create a parser that can create this default object in run time (so parse the query you wanna run and then base on your introspection schema, assign default values for each and then generate an object.
Sadly, there is NOT such a library at the moment (this is also good news, you could be the person that creates this Query to JS Object ultracool library). I think that even tho you want to do all this in the client side, the easiest and probably more effective solution is for your DataFetchers to return a default value in case is empty. The other option as you are already doing is to manually create default objects, if you were to make this easier, you could use typescript, together with gql-code-generator or something similar to get the correct definitions.
Upvotes: 2