How to properly append to an array using Dgraph GraphQL API? - graphql

I'm trying to spin up Dgraph, but appears as though to add a node to an array of nodes using the GraphQL api requires an unnecessary amount of work if I understand it correctly:
I have the following simplified schema:
type User #secret(field: "password") {
account: String! #id
email: String! #search(by: [hash])
extension: String! #search(by: [hash])
phone: String! #search(by: [hash])
hasCreated: [Transaction]! #hasInverse(field: from)
hasReceived: [Transaction]! #hasInverse(field: to)
}
type Transaction {
id: ID!
type: TransactionType! #search(by:[terms])
amount: Float!
assetCode: String! #search(by:[terms])
to: User!
from: User!
initiatedAt: DateTime! #search(by:[hash])
completedAt: DateTime #search(by:[hash])
status: Status!
}
To me, it appears as though to add a node to the User's hasCreated or hasReceived fields would require me to pull the entire array, append a new Transaction to the array and then use an updateUser mutation to complete the update. But the updateUser mutation would require me to get all the Transactions and all Users attached to these transactions and so on.
Example trying to retrieve an entire user object:
query {
getUser(id:"%s"){
account
email
extension
phone
hasCreated {
id
type
amount
assetCode
to {
...
}
}
hasReceived {
id
type
amount
assetCode
to {
...
}
}
}
}
}
Is there another way to append to arrays or update objects using the GraphQL api without having to retrieve whole objects?

Related

AWS AppSync GraphQL subscriptions returning null values on event

New to GraphQL, Amplify, AppSync, etc, and running into an issue when attempting to subscribe to an onUpdate event.
I added the 'API' library to my Amplify project with authentication through an API key. I can successfully send a mutation (updatePurchaseOrder) request through Postman, and the subscription listener registers an update, but the data returned is null on everything besides the id of the updated record.
screenshot in the AppSync console
The status field is null here, I would expect to see the new updated value. Is that the expected behavior?
The defined type on this:
type PurchaseOrder #model #auth(rules: [ { allow: public } ] ){
id: ID!
name: String!
description: String!
user: String
time: String
file: String!
status: String
}
Schema mutations and subscriptions created from the initial type definition haven't been changed:
type PurchaseOrder {
id: ID!
name: String!
description: String!
user: String
time: String
file: String!
status: String
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type Mutation {
updatePurchaseOrder(input: UpdatePurchaseOrderInput!, condition: ModelPurchaseOrderConditionInput): PurchaseOrder
}
input UpdatePurchaseOrderInput {
id: ID!
name: String
description: String
user: String
time: String
file: String
status: String
}
type Subscription {
onUpdatePurchaseOrder: PurchaseOrder
#aws_subscribe(mutations: ["updatePurchaseOrder"])
}
I tried logging to console in browser and see the same empty object returned. Figured listening through the AppSyncConsole would be less error prone, but I'm still seeing the same result.
Figured out where I went wrong... I needed to specify the response fields I wanted in the POST query (eg.:
mutation updatePurchaseOrder {
updatePurchaseOrder(input: {status: "Pending", id: "53a98236-7b64-428c-93ea-2fae5228c0ef"}) {
id
**status**
}
)
'status' was not in the query response parameters originally. The subscription response will only include fields that are part of the mutation response in the query itself.

Apollo GraphiQL browser playground: How to nest queries?

Wish to run a nested query within as Apollo GraphiQL browser playground.
Schema for two queries intended to be nested and a response type:
getByMaxResults(maxResults: Int = null): [ID!]!
appById(id: ID!): AppOutputGraphType
AppOutputGraphType = {
accountIdGuid: ID!
createdAt: DateTime!
description: String!
id: ID!
updatedAt: DateTime!
userId: ID
}
Query getByMaxResults: [ID!]!, the result is an array of element ID:
Query appById(id: ID!) requesting a couple of AppOutputGraphType fields:
Is there a way within the GraphiQL browser sandbox to nest these two Queries?:
query getByMaxResults gather an array of IDs.
Iterate this array and perform multiple queries appById with each ID.
Thank you
Change your definition of the getByMaxResults query to:
getByMaxResults: [AppOutputGraphType!]!
Change your resolver to return an array containing all the fields of the AppOutputGraphType objects and not just the id.
Then just:
query {
getByMaxResults {
id
updatedAt
}
}
There is no way in GraphQL to nest queries but the whole point of the language is to remove the need to do so.
With the proper resolvers you could even get the related account and user for each AppOutputGraphType.
Change:
AppOutputGraphType = {
account: Account <= don't include foreign keys, refer to the related type
createdAt: DateTime!
description: String!
id: ID!
updatedAt: DateTime!
user: User <= don't include foreign keys, refer to the related type
}
Then you can do queries like:
query {
getByMaxResults {
id
updatedAt
account {{
id
name
city
}
user {
id
firstName
lastName
}
}
}

How to resolve Inconsistent __typename error in Relay?

I just tried to implement the Relay in Frontend for this graphql tutorial, In that tutorial, they created graphql server to store URL(Link) bookmarks with the User who posted those URLs.
The relationship between the link and the users is:
Link belongs_to :user,
User has_many :links.
And I listed out all the Links with Users in Frontend, at the time I got the below error.
Warning: RelayResponseNormalizer: Invalid record 1. Expected __typename to be consistent, but the record was assigned conflicting types Link and User. The GraphQL server likely violated the globally unique id requirement by returning the same id for different objects
I'm not aware of how much it will impact the application. because I got the expected result from Frontend.
Frontend View of Query.
I read this relay official blog for this kind of error, but there is no example to know how exactly to resolve this. so can someone help to resolve this?
Relay Query
graphql`
query LinkListQuery {
allLinks {
id,
description,
url,
postedBy {
id,
name
}
}
}`
Schema:
input AUTH_PROVIDER_CREDENTIALS {
email: String!
password: String!
}
input AuthProviderSignupData {
credentials: AUTH_PROVIDER_CREDENTIALS
}
type Link implements Node {
description: String!
id: ID!
postedBy: User
url: String!
votes: [Vote!]!
}
input LinkFilter {
OR: [LinkFilter!]
descriptionContains: String
urlContains: String
}
type Mutation {
createLink(description: String!, url: String!): Link!
createUser(name: String!, authProvider: AuthProviderSignupData): User!
createVote(linkId: ID): Vote!
signinUser(credentials: AUTH_PROVIDER_CREDENTIALS): SignInUserPayload
}
"""An object with an ID."""
interface Node {
"""ID of the object."""
id: ID!
}
type Query {
allLinks(filter: LinkFilter, first: Int, skip: Int): [Link]!
"""Fetches an object given its ID."""
node(
"""ID of the object."""
id: ID!
): Node
}
"""Autogenerated return type of SignInUser"""
type SignInUserPayload {
token: String
user: User
}
type User implements Node {
email: String!
id: ID!
links: [Link!]!
name: String!
votes: [Vote!]!
}
type Vote {
id: ID!
link: Link!
user: User!
}

Using Apollo Federated GraphQL, is there a way to sort/paginate on a value from an external entity?

Is it possible to mark a field in an input to a query as requiring a field extended by a different service?
Using the federation-demo to illustrate my question, but keeping a little bit more simple. Having just an Account service and a Reviews service, and adding a karma field to the User, is it possible to filter reviews based on User karma.
Account service, adding a karma int to a User:
extend type Query {
me: User
}
type User #key(fields: "id") {
id: ID!
name: String
username: String
karma: Int!
}
Reviews service, adding a reviews Query:
extend type Query {
reviews(minKarma: Int): [Review!]!
}
type Review #key(fields: "id") {
id: ID!
body: String
author: User #provides(fields: "username")
product: Product
}
extend type User #key(fields: "id") {
id: ID! #external
username: String #external
karma: Int! #external
reviews: [Review]
}
extend type Product #key(fields: "upc") {
upc: String! #external
reviews: [Review]
}
In my resolver for Query.reviews, I want to filter out any review where review.author.karma is less than the specified minKarma.
How do I tell the gateway that when minKarma is specified in the Query input, I want the Account service to be queried first and a representation of users to be passed into the Reviews service, with the karma of each user attached to the review as the author, so that I can do the filter?
Circling back to the question at the top of this post, can I mark the minKarma field as requiring User.karma?
This is the questions plaguing me as well.

How to resolve subselections / relations in prisma (nested lists)

Let's take an example from the github repo of prisma:
We have a user, the user could have multiple posts, and one post could have multiple links.
My goal is, to retrieve all posts and all links.
This means, my response is a list (links) in a list (posts).
I want to map the values I get back as two nested lists.
datamodel.prisma
type User {
id: ID! #id
email: String! #unique
name: String
posts: [Post]!
}
type Post {
id: ID! #id
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
published: Boolean! #default(value: false)
title: String!
content: String
author: User!
links: [Link]!
}
type Link {
id: ID! #id
url: String
title: String
post: Post!
}
schema.graphql
type Query {
...
}
type Mutation {
...
}
type Link {
id: ID!
url: String
title: String
post: Post!
}
type Post {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
published: Boolean!
title: String!
content: String
author: User!
}
type User {
id: ID!
email: String!
name: String
posts: [Post]!
}
I want to query all posts of a user, and all of the links for every post in the response.
How would I query this request?
user {
id
posts {
id
links {
id
}
}
}
The above code snipper would not work.
EDIT
I want to use the following:
User: {
listPosts: (parent, args, context, info) {
return context.prisma.posts().links()
}
}
So in my response (data in front-end via react-apollo Query Component), I want to map over posts AND the links in each post.
BUT the links attribute in posts is null.
Is there another way to achieve this?!
According to the docs:
Prisma client has a fluent API to query relations in your database. Meaning you can simply chain your method calls to navigate the relation properties of the returned records. This is only possible when retrieving single records, not for lists. Meaning you can not query relation fields of records that are returned in a list.
In order to get around that limitation, you can use the $fragment method:
const fragment = `
fragment UserWithPostsAndLinks on User {
id
email
name
posts {
id
title
content
links {
id
url
title
}
}
}
`
const userWithPostsAndLinks = await prisma.user({ id: args.id }).$fragment(fragment)

Resources