I'm putting a GraphQL wrapper over an exiting REST API as described in Zero to GraphQL in 30 minutes. I've got an API endpoint for a product with one property that points to a nested object:
// API Response
{
entity_id: 1,
nested_object: {
key1: val1,
key2: val2,
...
}
}
Is it possible to define the schema so that I can get this entire nested object without explicitly defining the nested object and all of its properties? I want my query to just specify that I want the nested object, and not need to specify all the properties I want from the nested object:
// What I want
{
product(id: "1") {
entityId
nestedObject
}
}
// What I don't want
{
product(id: "1") {
entityId
nestedObject {
key1
key2
...
}
}
}
I can do the second version, but it requires lots of extra code, including creating a NestedObjectType
and specifying all the nested properties. I've also figured out how to automatically get a list of all the keys, like so:
const ProductType = new GraphQLObjectType({
...
fields: () => ({
nestedObject: {
type: new GraphQLList(GraphQLString),
resolve: product => Object.keys(product.nested_object)
}
})
})
I haven't figured out a way to automatically return the entire object, though.
We can parse a nested JSON object using the getString(index) method of JSONArray. This is a convenience method for the getJSONString(index). getString() method and it returns a string value at the specified position.
The __typename field returns the object type's name as a String (e.g., Book or Author ). GraphQL clients use an object's __typename for many purposes, such as to determine which type was returned by a field that can return multiple types (i.e., a union or interface).
When setting up a field whose value is a custom type, we have to define a function that tells GraphQL how to get that custom type. In our case, we want to tell GraphQL how to get the posts if we have the author. We do that by defining a new root property inside resolvers.
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
You may try to use scalar JSON type. You can find more here (based on apollographql).
scalar JSON
to a schema definition;{JSON: GraphQLJSON}
to a resolve functions;
scalar JSON
type Query {
getObject: JSON
}
query {
getObject
}
{
"data": {
"getObject": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
}
Basic code:
const express = require("express");
const graphqlHTTP = require("express-graphql");
const { buildSchema } = require("graphql");
const GraphQLJSON = require("graphql-type-json");
const schema = buildSchema(`
scalar JSON
type Query {
getObject: JSON
}
`);
const root = {
JSON: GraphQLJSON,
getObject: () => {
return {
key1: "value1",
key2: "value2",
key3: "value3"
};
}
};
const app = express();
app.use(
"/graphql",
graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
})
);
app.listen(4000);
console.log("Running a GraphQL API server at localhost:4000/graphql");
I can do the second version, but it requires lots of extra code, including creating a NestedObjectType and specifying all the nested properties.
Do it! It will be great. That's the way to go in order to use GraphQL to its full potential.
Aside from preventing over-fetching, it also gives you a lot of other benefits like type validation, and more readable and maintainable code since your schema gives a fuller description of your data. You'll thank yourself later for doing the extra work up front.
If for some reason you really don't want to go that route though and fully understand the consequences, you could encode the nested objects as strings using JSON.stringify
.
But like I said, I recommend you don't!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With