How to update Saleor's Graphql responses with newly added DB table fields? - graphql

First, Saleor with GraphQL is fantastic. Just love it.
The products we are selling have additional metadata we need to get from Graphql. Out of the box, the Graphql queries work fine, such as:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description
}
}
What I need to do is expose data from my products table with additional columns, such as productInfo1, productInfo2, and productInfo3. This part is easy of course.
However, I am struggling with how to update the Saleor Graphql so I can run a query like the following:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description {
productInfo1
productInfo2
productInfo3
}
}
}
I have been through the Saleor docs, Stack Overflow, and a variety of blogs... I've attempted some logical approaches myself, without any success.
I'm eager to start working on these types of updates for our needs here. Any suggestions or links to "how to" locations would be greatly appreciated!

If you'd like to add subfields to description there is a couple of things you have to do:
Create new description object type which contains the subfields you want, e.g.:
class ProductDescription(graphene.ObjectType):
productInfo1 = graphene.String()
productInfo2 = graphene.String()
productInfo3 = graphene.String()
Set the description field with the new type under Product type:
class Product(CountableDjangoObjectType):
...
description = graphene.Field(ProductDescription)
Add resolver for description under Product type:
def resolve_description(self, info):
return ProductDescription(
productInfo1=self.description,
productInfo2='Some additional info',
productInfo3='Some more additional info',
)
Saleor's GraphQL API is based on the Graphene framework. You can find more about resolvers and object types here: https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers.

Related

How to workaround non existent types in Graphql query in Gatsby

I'm building a website with a blog section, and on deployment to production the blog will be empty. I'm having problems allowing an empty blog on my Gatsby site.
When I run npm run develop it will only work if I have some blogs - I want it to work before the blogs have been added.
The main issues I'm encountering is trying to accomidate fields not existing like allStrapiBlog and strapiBlog because there are no blogs.
I get errors like this on blog components, and on my nav component (where i have a query that a conditional uses).
15:17 error Cannot query field "allStrapiBlog" on type "Query" graphql/template-strings
Cannot query field "strapiBlog" on type "Query"
This is what the query looks like for my navigation component. But it throws an error - is there a way to make it just return null?
query NavigationQuery {
allStrapiBlog {
nodes {
title
strapi_id
}
totalCount
}
}
How do I make unsuccessful GraphQL queries not break the build, so I can build a gatsby site with a empty blog?
But it throws an error - is there a way to make it just return null?
Indeed, you need to configure your GraphQL schema to allow nullable fields.
You have a boilerplate that you can tweak to match your data types at https://www.virtualbadge.io/blog-articles/nullable-relational-fields-strapi-gatsbyjs-graphql.
The idea relies on using the createSchemaCustomization API in your gatsbt-node.js to add your own type definitions.
Something like:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type StrapiBlogPost implements Node {
title: String!
content: String
thumbnail: File
}
`;
createTypes(typeDefs);
};
In this case, the title is required (because of the !, which means that the type is non-nullable) while content and thumbnail can be null.
Afterward, you will only need to adapt your component to avoid code-breaking logics when null data is fetched.

GraphQL dynamic query strategy best practices

What is a good strategy for dynamically building a query schema for objects and fields with Apollo Client and GraphQL?
We have T-Shirt, Pants, and Shoes objects in our schema. Each of these vary on the types of fields readily available.
There are two input fields, a single entity drop down for TShirt, Pants, and Shoes, and a multi-select drop down to select from the fields available from the schema.
The query schema is produced based on the user's input.
const schema = gql
`query {
tshirt {
logo
brand
}
pants {
length
wasteSize
}
shoes {
lacesStyle
color
}
}
}`
query {
tshirt($logoSkipVal: Boolean! = false, $brandSkipVal: Boolean! = false) {
logo #skip(if: $logoSkipVal)
brand #skip(if: $brandSkipVal)
}
}
I have it working with interpolation manipulation. However, you could imagine as the fields grow in abundance so does the amount of skip directives. Is there maybe a way to use #skip or #include to check if a GraphQL variable with a list of strings includes the field name?
Is there any reason you aren't using Fragments to accomplish this? It seems to be the most applicable solution for combining shared logic between queries and mutations.

How are arguments added to GraphQL, do they need to be defined before?

Hi Everyone I am just trying to learn graphql as I am using Gatsby. I want to know does each field in graphql take an argument or does it need to be defined somehow before. So for example if you visit this link graphql search results
https://graphql.org/swapi-graphql?query=%7B%0A%09allPeople%20%7B%0A%09%20%20people%20%7B%0A%09%20%20%20%20id%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20birthYear%0A%20%20%20%20%20%20eyeColor%0A%09%20%20%7D%0A%09%7D%0A%7D%0A
If i wanted to limit people by eye color how would I do that. In the docs it seems easy as you would just do something like people(eyecolor: 'brown') but that doesn't seem possible. Am I missing something? I basically want to do a SQL style search for all people where eye color is brown.
Thanks.
Arguments need to be defined in the schema and implemented in the resolver. If you're consuming a 3rd party API (like the link you provided), you're limited to their schema. You can tell by looking at their schema (by clicking Docs on the right side of the page) which fields take arguments. For example, person takes id and personID arguments:
people doesn't take any arguments, as seen in the schema:
If you're building your own schema, you can add arguments to any field, and when you implement the resolver for that field you can use the arguments for logic in that resolver.
If you're working with a schema that you don't control, you'll have to add filtering on the frontend:
const {people} = data.allPeople;
const brownEyedPeople = people.filter(({eyeColor}) => eyeColor === 'brown');
When you start developing in Gatsby and actually pull your data into Gatsby, there will be a filter query option that automatically becomes available in the query arguments.
https://www.gatsbyjs.org/docs/graphql-reference/#filter
You can expect to be able to filter your people by eyeColor by using the below query:
{
allPeople(filter: { eyeColor: { eq: "brown" } }) {
edges {
node {
id
name
birthYear
eyeColor
}
}
}
}

How to use same generated ID in two fields prisma-graphql

I'm implementing a graphql prisma datamodel. Here I have a type called BankAccount . I may need to update and delete them as well. I'm implementing this as immutable object. So, when updating I'm adding updating the existing record as IsDeleted and add a new record. And when updating an existing record I need to keep the id of the previous record to know which record is updated. So, I've came up with a type like this
type BankAccount {
id: ID! #unique
parentbankAccount: String!
bankName: String!
bankAccountNo: String!
isDeleted: Boolean! #default(value: "false")
}
Here the parentBankAccount keeps the id of previous BankAccount. I'm thinking when creating a bank account, setting the parentBankAccount as same as the id as it doesn't have a parent. The thing is I'm not sure it's possible. I'm bit new to GraphQL. So, any help would be appreciated.
Thanks
In GraphQL, generally if one object refers to another, you should directly refer to that object; you wouldn't embed its ID. You can also make fields nullable, to support the case where some relationship just doesn't exist. For this specific field, then, this would look like
type BankAccount {
parentBankAccount: BankAccount
...
}
and that field would be null whenever an account doesn't have a parent.
At an API level, the layout you describe seems a little weird. If I call
query MyBankAccount {
me { accounts { id } }
}
I'll get back some unique ID. I'd be a little surprised to later call
query MyBalance($id: ID!) {
node(id: $id) {
... on BankAccount {
name
isDeleted
balance
}
}
}
and find out that my account has been "deleted" and that the balance is from a week ago.
Using immutable objects in the underlying data store makes some sense, particularly for auditability reasons, but that tends to not be something you can expose out through a GraphQL API directly (or most other API layers: this would be equally surprising in a REST framework where the object URL is supposed to be permanent).

Apollo/React mutating two related tables

Say I have two tables, one containing products and the other containing prices.
In Graphql the query might look like this:
option {
id
price {
id
optionID
price
date
}
description
}
I present the user with a single form (in React) where they can enter the product detail and price at the same time.
When they submit the form I need to create an entry in the "product" table and then create a related entry in the "price" table.
I'm very new to Graphql, and React for that matter, and am finding it a steep learning curve and have been following an Apollo tutorial and reading docs but so far the solution to this task is remaining a mystery!
Could someone put me out of my misery and give me, or point me in the direction of, the simplest example of handling the mutations necessary for this?
Long story short, that's something that should actually be handled by your server if you want to optimize for as few requests as possible.
Problem: The issue here is that you have a dependency. You need the product to be created first and then with that product's ID, relate that to a new price.
Solution: The best way to implement this on the server is by adding another field to Product in your mutation input that allows you to input the details for Price as well in the same request input. This is called a "nested create" on Scaphold.
For example:
// Mutation
mutation CreateProduct ($input: CreateProductInput!) {
createProduct(input: $input) {
changedProduct {
id
name
price {
id
amount
}
}
}
}
// Variables
{
input: {
name: "My First Product",
price: {
amount: 1000
}
}
}
Then, on the server, you can parse out the price object in your resolver arguments and create the new price object while creating the product. Meanwhile, you can also relate them in one go on the server as well.
Hope this helps!

Resources