GraphQL Dataloader fails if backend returns null values - graphql

I have a GraphQL object type Student. And each student may or may not have Phone data.
Phone is another GraphQL type object (A child object in Student).
I have GraphQL dataloader registered on Phone. Things work fine as long as each student record has a corresponding Phone record. But if there is any student record who does not have a corresponding phone record, Dataloader fails with error:
"message": "Exception while fetching data (/students[0]/phone) : The size of the promised values MUST be the same size as the key list",
I believe this is because, dataloader is trying to assert that size-of-keys-in-list should be same as size-of-values-resolved-in-list.
Is there anyway to accept null as values which is a valid case in my requirement.

Found that the backend server is not even sending 'null', it just ignores the missing record.
From official source:
https://github.com/graphql-java/java-dataloader/blob/7bf46ea182b1f8ab255c3107b1b61d4afd36ad88/src/main/java/org/dataloader/BatchLoader.java
Dataloader does support null values:
*
* <pre>
* [
* { id: 2, name: 'San Francisco' },
* { id: 9, name: 'Chicago' },
* null,
* { id: 1, name: 'New York' }
* ]
* </pre>

Related

How can I add 2 types either an array of strings or an object to the data?

I have this mutation function where I can add either array of String or Object in the data arguments.
This is a request with data type value Object.
mutation {
reading(id: 257, data: [{ id: 1, timestamp: "1654831128"}]){
id
name
}
}
This is a request with data type value String
mutation {
reading(id: 257, data: [["ace", "red"], ["rock", "stone"]]){
id
name
}
}
In one mutation, there are 2 different types that I will send to the server.
In my graphQL file code
type Mutation {
reading(
id: Int
data: [Time | String] <----
): [Device!]!
}
In my code with an arrow above. How can I add 2 types either an array of strings or an object to the data?
In the documentation, I try union but I think it only applies to the results.

Understanding what data Stripe needs for a Vue and Laravel project

I am using vue-stripe and trying to setup a way to do one time purchases. I am doing a token request and it generates the token below when I enter the cc number date and cvc.
card:
address_city: null
address_country: null
address_line1: null
address_line1_check: null
address_line2: null
address_state: null
address_zip: "42424"
address_zip_check: "unchecked"
brand: "Visa"
country: "US"
cvc_check: "unchecked"
dynamic_last4: null
exp_month: 4
exp_year: 2024
funding: "credit"
id: "card_1IHHP9Jcu3r8UW8rqiLydyLZ"
last4: "4242"
name: null
object: "card"
tokenization_method: null
__proto__: Object
client_ip: "137.187.202.50"
created: 1612481911
id: "tok_1IHHP9Jcu3r8UW8r81KS1HBH"
livemode: false
object: "token"
type: "card"
used: false
I was hoping I could take this token and give it to Laravel Cashier to complete the charge. In my controller I tried
$stripeCharge = auth()->user()->charge( 100, $request->card);
but it gave me an error
Invalid string: {:id=>"card_1IHHP9Jcu3r8UW8rqiLydyLZ", :object=>"card", :address_zip=>"42424", :address_zip_check=>"unchecked", :brand=>"Visa", :country=>"US", :cvc_check=>"unchecked", :exp_month=>"4", :exp_year=>"2024", :funding=>"credit", :last4=>"4242"}"
so instead I tried to use
$stripeCharge = auth()->user()->charge( 100, $request->id);
but it said
A token may not be passed in as a PaymentMethod. Instead, use payment_method_data with type=card and card[token]=tok_1IHHSfJcu3r8UW8rsTWenxiT.
So I tried
axios.post('/purchase', {
payment_method_data: {
card: {
token: token.id
},
}
})
but that gives me the error
message: "You cannot confirm this PaymentIntent because it's missing a payment method. You can either update the PaymentIntent with a payment method and then confirm it again, or confirm it again directly with a payment method."
I feel like I am close but just not understanding what Stripe wants and what Laravel is sending when I do a charge. I would love any help!
You need to create a Payment Method in Vue, not a token: https://stripe.com/docs/js/payment_methods/create_payment_method

Prisma Not Returning Created Related Records

i want to create a new graphql api and i have an issue that i am struggling to fix.
the code is open source and can be found at: https://github.com/glitr-io/glitr-api
i want to create a mutation to create a record with relations... it seems the record is created correctly with all the expected relations, (when checking directly into the database), but the value returned by the create<YourTableName> method, is missing all the relations.
... so so i get an error on the api because "Cannot return null for non-nullable field Meme.author.". i am unable to figure out what could be wrong in my code.
the resolver looks like the following:
...
const newMeme = await ctx.prisma.createMeme({
author: {
connect: { id: userId },
},
memeItems: {
create: memeItems.map(({
type,
meta,
value,
style,
tags = []
}) => ({
type,
meta,
value,
style,
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
}))
},
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
});
console.log('newMeme', newMeme);
...
that value of newMeme in the console.log here (which what is returned in this resolver) is:
newMeme {
id: 'ck351j0f9pqa90919f52fx67w',
createdAt: '2019-11-18T23:08:46.437Z',
updatedAt: '2019-11-18T23:08:46.437Z',
}
where those fields returned are the auto-generated fields. so i get an error for a following mutation because i tried to get the author:
mutation{
meme(
memeItems: [{
type: TEXT
meta: "test1-meta"
value: "test1-value"
style: "test1-style"
}, {
type: TEXT
meta: "test2-meta"
value: "test2-value"
style: "test2-style"
}]
) {
id,
author {
displayName
}
}
}
can anyone see what issue could be causing this?
(as previously mentioned... the record is created successfully with all relationships as expected when checking directly into the database).
As described in the prisma docs the promise of the Prisma client functions to write data, e.g for the createMeme function, only returns the scalar fields of the object:
When creating new records in the database, the create-method takes one input object which wraps all the scalar fields of the record to be
created. It also provides a way to create relational data for the
model, this can be supplied using nested object writes.
Each method call returns a Promise for an object that contains all the
scalar fields of the model that was just created.
See: https://www.prisma.io/docs/prisma-client/basic-data-access/writing-data-JAVASCRIPT-rsc6/#creating-records
To also return the relations of the object you need to read the object again using an info fragment or the fluent api, see: https://www.prisma.io/docs/prisma-client/basic-data-access/reading-data-JAVASCRIPT-rsc2/#relations

GraphQL error FieldsConflict: fields have different list shapes

I'm using AWS AppSync's GraphQL server with the following (simplified) schema:
type Query {
getIssue(id: String!): Issue
}
type Issue {
id: String!
data: IssueData!
}
type Event {
id: String!
time: AWSDateTime!
status: [String]
}
type Payment {
id: String!
amount: Int!
status: String
}
union IssueData = Event | Payment
When I make a query that includes inline fragments to select the status as a child of either an Event or Payment type in the Issue/data field, I get a FieldsConflict error:
query getIssue($id: String!) {
getIssue(id: $id) {
id
data {
... on Event {
time
status
}
... on Payment {
amount
status
}
}
}
}
Validation error of type FieldsConflict: status: fields have different list shapes # 'getIssue/data'
This is presumably caused by the Event/status field returning an array of strings, while the Payment/status field returns a single string.
Why does GraphQL consider this to be a conflict? How should I construct my query to allow access to the status field on both data types?
Note that I'm using a union rather than an extended interface because the Issue and Payment types have no common data structure.
From the spec:
If multiple field selections with the same response names are encountered during execution, the field and arguments to execute and the resulting value should be unambiguous. Therefore any two field selections which might both be encountered for the same object are only valid if they are equivalent.
You can resolve the issue by providing a field alias for one or both fields:
query getIssue($id: String!) {
getIssue(id: $id) {
id
data {
... on Event {
time
eventStatus: status
}
... on Payment {
amount
status
}
}
}
}
Renaming one or both fields in your schema would obviously also resolve the issue.

Prisma graphql computed fields

I have this datamodel:
type Item {
id: ID! #unique
title: String!
description: String!
user: User!
pictures: [Picture]
basePrice: Int!
addons: [Addon]
}
I'm writing a query called parsedItem that takes the id from arguments and looks for the Item (using the default query for Item generated by Prisma), something like this:
const where = { id: args.id };
const item = await ctx.db.query.item({ where },
`{
id
title
...
I need to show on the frontend a computed value: "dynamicPrice" it depends on the quantity of the Addons that the Item has.
e.g:
Item #1 has 3 addons, each addons has a value of $5. This calculated value should be
dynamicPrice = basePrice + 3 * 5
The Addon relation could change, so I need to compute this in every request the frontend makes.
I'd like so much to do something like:
item.dynamicPrice = item.basePrice + (item.addons.length * 5)
and return this item in the resolver, but this doesn't work. That throw an error:
"message": "Cannot query field \"dynamicPrice\" on type \"Item\"."
(when I try to query the Item from the frontend)
This error message makes me think: Should I create dynamicPrice as a field on the datamodel? Can I then populate this field in the query resolver? I know I can, but is this a good approach?
This is an example, I need to create more computed values for this Item model.
What is the best scalable solution/workaround for this simple use case?
You need create field resolver for dynamicPrice field at Item type. It will looks like that:
const resolvers = {
Query: {
parsedItem: (parent, args, ctx, info) => {
...
}
...
},
Item: {
dynamicPrice: parent => parent.basePrice + parent.addons.length * 5
}
}
More details you can find at A Guide to Common Resolver Patterns.

Resources