Add or delete from connection depending on response - graphql

Essentially, I have users who can have payments, and theses payments can be filtered with an arg.
Here is my schema, simplified :
type User {
payments($filter: PaymentsFilter): PaymentsConnection,
}
enum PaymentsFilter {
MissingDetails,
}
type PaymentsConnection {
edges { ... }
pageInfo { ... }
}
type Payment {
id
description
}
The MissingDetails filter returns only the Payment who are missing a description.
For example, if I have 2 Payment :
[
{ id: 1, description: null },
{ id: 2, description: 'A great payment' },
]
A query as such :
query {
loggedUser {
payments(filter: MissingDetails) {
...
}
}
}
Would return only the first Payment, with id: 1.
I want to achieve an UpdatePaymentMutation, that would update the payment and depending on if the description is set or not in the response, I would RANGE_ADD it to the connection with the filter MissingDetails, or RANGE_DELETE it.
How can I achieve that ?

Related

How to create a cart on the shopify storefront API

I am building a headless shopify site using remix. Fro reading the documentation on storefront in order for you to do a a checkout you must create a cart and send a post request to the api.
I am sending this graphql request which I found off the official docs to create a cart https://shopify.dev/api/examples/cart. Where the merchadise id is the id I get back from when i call get products
mutation {
cartCreate(
input: {
lines: [
{
quantity: 2
merchandiseId: "gid://shopify/ProductVariant/6964601651340"
}
]
attributes: { key: "cart_attribute", value: "This is a cart attribute" }
}
) {
cart {
id
createdAt
updatedAt
lines(first: 10) {
edges {
node {
id
merchandise {
... on ProductVariant {
id
}
}
}
}
}
}
}
}
Here is a response of getProducts
{
"node": {
"id": "gid:\/\/shopify\/Product\/6964601651340",
"handle": "vans-authentic-butterfly-true-white-black",
"title": "VANS | AUTHENTIC (BUTTERFLY) TRUE | WHITE \/ BLACK",
"description": "The forefather of the Vans family, the Vans Authentic was introduced in 1966 and nearly 4 decades later is still going strong, its popularity extending from the original fans - skaters and surfers to all sorts. The Vans Authentic is constructed from canvas and Vans' signature waffle outsole construction.",
"variants": {
"edges": [
{
"node": {
"price": "109.95"
}
}
]
}
}
}
If I change "gid://shopify/ProductVariant/6964601651340" to gid://shopify/Product/6964601651340 - i get invalid id. But if I make the request with productVariant I get the response
{
"data": {
"cartCreate": {
"cart": null
}
}
}
what am I doing wrong - how do i create a cart?
You need to use the id of the Variant. Not the product.
Each product (Vans) can have several variants, typically sizes and colors (39 black,40 black, 39 red etc)
You can retrive the Variant id with a query like this
{
products(first:100){
edges{
node{
variants(first:100){
edges{
node{
id
}
}
}
}
}
}
}

How to add graphql pagination on nested object

I am writing a graphql api endpoint where I have customer details as below.
{
customer_name:
customer_address:
[
{
address_1:
},
{
address_2:
},
]
}
I need to apply pagination on customer_address which is a list.
Is this possible? Or I can do it only at top level record? Please let me know what would be the best way to do it?
You can possible by using resolver like following
input PageInput{
limit: Int!
page: Int!
}
type CustomerAddressPage {
totalCount: Int!
edges: [CustomerAddress!]!
}
type CustomerAddress {
address: String
}
type Customer {
customerName: String
customerAddress(input: PageInput!): CustomerAddressPage
}
I don't know what kind of framework you use, in nestjs you can be done as follows.
#Resolver(() => Customer)
export class CustomerResolver {
#ResolveField(() => CustomerAddressPage)
customerAddress(
#Parent() customer: Customer,
#Args('input') input: PageInput,
): Promise<CustomerAddressPage> {
return {
};
}
}

Shopify Admin API, graphQL, create draft order - add products

This is my fist time creating an order. From what I understand you need to create a draft order - add products, price, email, notes etc. I am just creating a test query now to see how it works and it tells me "Add at least 1 product". I am trying to add a product, but I dont know how. I have been messing around and reading and cant figure it out.
This is my query:
mutation draftOrderCreate {
draftOrderCreate(input: {email: "123abc#hotmail.com"}) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}
If anyone can give me an example on how to add products to this would be great. Thanks.
You can create an draft order like so:
mutation draftOrderCreate($items: DraftOrderInput!) {
draftOrderCreate(input: $items) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}
query variables:
{
"items": {
"email": "123abc#hotmail.com",
"lineItems": [
{
"variantId": "gid://shopify/ProductVariant/32231002996788",
"quantity": 1
}
]
}
}
Or if you don't want to use query variables you can pass the whole object as the input:
mutation draftOrderCreate {
draftOrderCreate(input: {email: "123abc#hotmail.com", lineItems: [{variantId: "gid://shopify/ProductVariant/32231002996788", quantity: 1}]}) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}

How does GraphQL support AND-OR query conditions?

I'm new to GraphQL. There is a requirement that query all the qualified data from CUSTOMERS table, which meets condition: GENDER == 'MALE' or 'AGE' >= 20. What GQL should looks like for it?
Someone proposed a similar thing before but it is rejected. That means GraphQL does not support it natively and you have to roll it out by yourself.
Several ways to do it based on what I see :
(1) Define your own query language such as what stackoverflow or Shopify does :
type Query{
customers (query:String) : [Customer]
}
The query becomes :
{
customers (query : "GENDER == 'MALE' or 'AGE' >= 20"){
id
name
}
}
(2) Define your own input object models that can cover all the required searching requirement.Prisma try to define one in OpenCRUD specification .You may take a look on it for the idea . For example , you can define an input model like :
input CustomerFilter {
AND : [CustomerFilter]
OR : [CustomerFilter]
# Define the fields that you support to search
gender : String
gender_not : String
....
....
...
...
age : Int
age_gte : Int
}
type Query{
customers (filter:CustomerFilter) : [Customer]
}
And the query becomes :
{
customers (filter : {
OR: [
{ gender : 'MALE' } ,
{ age_gte: 20 }
]
}){
id
name
}
}
This is another filter model for reference. The idea is to tailor-made it such that it is just enough to handle all your application requirements without introducing any unnecessary filtering complexity.
Also , you most probably need to consider something like pagination if it potentially will return many data. It means you have to add an offset and limit to the input arguments for each query to somehow limit the number of record returned if you are doing offset-based pagination or take a look on Relay Specification if you want to do it in the cursor-based pagination style.
You need to define query, schema and resolver. Your Query will be like :
type Query {
nameItAsPerUsecase: Customer
}
Schema will be like these :
type Customer{
name : String
age: Int
.. add more fields as per as your need
}
Your resolver will be like this: -
#Component
public class CustomerQuery implements GraphQLQueryResolver {
#Autowired
private CustomerRepository customerRepository ;
public Customer getNameItAsPerUsecase() {
return customerRepository.findByGenderAndAgeGreaterThanEqual(String gender, int age);
}
}
Nested logic with the same and/or conjunction can be simplified into a single list.
For example, the following complex query:
or: [
{ or: [ { foo: { eq: "A" } }, { bar: { eq: "B" } } ] },
{ or: [ { baz: { eq: "C" } }, { quz: { eq: "D" } } ] }
]
} ) { ... }
Moreover, can be simplified into the following simplified query syntax:
queryPost(filter: {
or: [
{ foo: { eq: "A" } },
{ bar: { eq: "B" } },
{ baz: { eq: "C" } },
{ quz: { eq: "D" } }
]
} ) { ... }

GraphQL - how to filter a hierarchy? ("customers who ordered gizmos last month")

Let's assume a type hierarchy of Customer -(hasMany)-> Orders -(hasMany)-> OrderLines
Something like this:
Customer {
Name
Orders [
{
OrderId
Date
OrderLines [
{
ItemCount
ItemName
}
]
}
]
}
I want to query for this whole tree, and filter on properties at any level in the tree.
For instance: Get all customers who ordered 'gizmos'.
This is what I tried: at each level of the hierarchy, I specify optional arguments that would filter based on the properties available at that level:
Customer (Name) {
Name
Orders (OrderId, Date) [
{
OrderId
Date
OrderLines (ItemCount, ItemName) [
{
ItemCount
ItemName
}
]
}
]
}
GraphQL needs me to define how to resolve each type in the hierarchy, so when resolving, I filter based on the arguments in the query.
But what if I only specify a filter at a deep level? e.g. ItemName : 'gizmo'
Assuming there's only one order line in the system containing a gizmo, I would expect to get a response like this:
[{
Name: "cust12",
Orders [{
OrderId: "ade32f",
OrderLines: [{
ItemCount: 50000, //customer really likes gizmos
ItemName: "gizmo"
}]
}]
}]
But what I actually get is all customers (no filter there), all their orders (no filter there) and all order items, mostly empty (the items inside are filtered).
[{
Name: "cust12",
Orders [
{
OrderId: "aaaaaa",
OrderLines: [ ]
},
{
OrderId: "ade32f",
OrderLines: [{
ItemCount: 50000,
ItemName: "gizmo"
}]
},
{
OrderId: "bbbbbb",
OrderLines: [ ]
},
{
OrderId: "cccccc",
OrderLines: [ ]
}
]
},
{
Name: "cust345",
Orders [
{
OrderId: "eeeeee",
OrderLines: [ ]
},
{
OrderId: "ffffff",
OrderLines: [ ]
}
]
}]
GraphQL calls the resolvers top-down:
- get all (filtered) clients
- for each of these get all (filtered) orders
- for each of those get all (filtered) order lines
Because of the top-down nature of calling the resolvers, I get a lot more data than I bargained for.
How should I approach this?
Relation filters
This is actually a more complex topic than it first seems. The problem is that your current filter condition expresses
get all customers, but only include items named 'gizmo'
but what you really want is
get all customers that are related to at least one item named 'gizmo'
get all customers that are related to at least one item named 'gizmo'
An elegant solution for this problem is the addition of relation filters to the schema. In your case, it could look like this:
query {
Customer(filter: {
orders_some: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
Using
orders_some: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
we only fetch customers that are indirectly related to an item named 'gizmo', exactly what we wanted.
Two more examples:
get all customers that are not related to any item named 'gizmo'
query {
Customer(filter: {
orders_none: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
get all customers where all their orders contain some order line with an item named 'gizmo'
query {
Customer(filter: {
orders_every: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
The every, some and none relation filters are an essential part of the Graphcool APIs - you can read more here.

Resources