How to get list of objects using an array in AWS App Sync? - graphql

The intention is to query a list of users using an array of User IDs passed into a contains filter. The schema below is my attempt at solving this, but the query does not return a list of users. Even passing only a single User ID results in an empty query result. This schema is being published to AWS AppSync.
Is it possible to query a list of users using an array of User IDs in AppSync?
schema.graphql
type User #model {
id: ID!
username: String!
friends: [String]
}
type Query {
getAllFriends(filter: ModelAllFriendsFilterInput): ModelGetAllFriends
}
type ModelGetAllFriends {
items: [User]
}
input ModelAllFriendsFilterInput {
id: ModelAllFriendsIDInput
}
input ModelAllFriendsIDInput {
contains: [ID]
}
GraphQL Query:
query MyQuery {
getAllFriends(filter: {id: {contains: "VALID-USER-ID-HERE"}}) {
items {
id
username
}
}
}
Query result:
{
"data": {
"getAllFriends": null
}
}

Yes, lists are valid inputs in GraphQl fields.
The "null" response indicates that (a) Appsync passed your query to the resolver, (b) your resolver returned a result without error and (c) Appsync accepted the result. If any of these were not true, Appsync would have given you an error message. In other words, I believe the problem to be your resolver returning a null result, not the schema.
By the way, in the case of a list field like contains: [ID], Appsync will accept a list or a scalar value (like your {contains: "VALID-USER-ID-HERE"} above) as valid input. If you pass a scalar value to a list field, Appsync will helpfully pass it as a list/array value ["VALID-USER-ID-HERE"] in the lambda resolver's handler function arguments.

Related

Passing variables from mutation to query

I have a GraphQL mutation that creates an item and returns the data that's created. I need to pass some of the created fields into a query. Is this possible? This is almost working but I can't figure out how to get the data between the mutation and the query:
mutation {
createToken(
input: { tokenname: "my token", tokendescription: "my valuable token" }
) {
id
randomdata
}
insert__helloworld_article(objects: [{randomdata: "Hello" , author_id: 1}]) {
returning {
id
}
}
}
So my problem is getting "randomdata" from the mutation to insert into the helloworld_article
You wouldn't be able to use the return value in the same mutation with GraphQL, however if those objects have a relationship you could do a nested insert.

GraphQL | How to implement conditional nesting?

Please consider the following GraphQL schema:
type User {
id: ID!
events: [Event]
}
type Event {
id: ID!
user: User!
asset: Asset!
}
type Asset {
id: ID
price: Number!
name: String!
}
GraphQL is a fantastic framework for fetching nested objects, but I'm struggling to understand how conditional nesting is implemented.
Example:
I want to retrieve all events for a specific user where asset.price is greater than x.
Or
I want to retrieve all events for an asset that belongs to a list of users [].
Question: Is conditional nesting a concept in GraphQL and how is it implemented?
Side note: I use AWS AppSync and resolvers are fetching data from AWS DynamoDB.
You can define a filter/condition on any GraphQL query such as:
query {
users(permission: 'ADMIN') {
...
}
}
The permission param is passed to your resolver (say DynamoDb VTL template, Lambda etc) to be handled however you want - to GQL this is just another parameter.
You can carry this concept into nested field by creating an events resolver and you'd then call it like this:
query {
user(id: '123') {
name
events(minPrice: 200) {
nodes: {
id
eventName
eventDate
}
}
dob
...
}
}
In above case I am using a simple minPrice param but you could do more complex things such price ranges, even pass operators (eq, gt, ...). It's all irrelevant to GraphQL - all gets passed to the resolver.
How you implement that on backend depends on your setup. I use AppSync without Amplify and write my own VTL templates and build the DynamoDb request using the provided GQL fields.
Here is an SO post that shows how to create a date filter.

Contentful GraphQL endpoint: how to retrieve all entries of a content type

{
Post {
name
}
}
While trying to retrieve all the entries on a content type, it only gives error of:
"Argument \"id\" of required type \"String!\" was not provided."
Since id field is required. How do I get all entries of a content type then?
Ref: https://www.contentful.com/developers/docs/references/graphql/
From docs here:
The produced Query object exposes two fields that you can use to query content of that type: one to fetch individual content documents (friendlyUser in the example) and another to do queries over all the content of the type (friendlyUserCollection).
So for any resource that you want to retrieve all entries of, you need to append Collection at the end of its id, then use items field to retrieve all entries. As in:
{
PostCollection {
items {
name
}
}
}
Apart from docs, you can also view all available resources at corresponding GraphiQL instance here, which could be pretty useful:
https://graphql.contentful.com/content/v1/spaces/{SPACE_ID}/explore?access_token={ACCESS_TOKEN}
Search or select Query to see all schemas:
Query a single id
I think you can try this in the GraphQL playgound
http://localhost:8000/___graphql
query PostById($id: String!) {
contentfulPost(id: { eq: $id }) {
name
}
}
and add a QUERY VARIABLE
{
"id": "my-awesome-id"
}
Query all the Posts
How do I get all entries of a content type then?
On the GraphQL playground, you should be able to do something like this
{
allContentfulPost {
nodes {
name
}
}
}

How to run GraphQL filter query on an ARRAY field type in Hasura?

I'm trying to run GraphQL filter query on array field types, for example on a text ARRAY field type.
In the following example scenario:
CREATE TABLE
CREATE TABLE Employee (
firstName text,
lastName text,
tags text[]
);
And we can filter on text array field in one of the following ways:
SELECT STATEMENT with CONDITION on an ARRAY type
SELECT * FROM Employee WHERE tags #> ARRAY['teamplayer']::varchar[]
This works in PostGres and also in Postgraphile implicitly.
On Postgraphile GraphQL, we can query the above table as follows:
Query
{
allEmployees(filter: {tags: {contains: "teamplayer"}}) {
nodes {
firstName
lastName
tags
}
}
}
and the result will be:
Response
{
"data": {
"allEmployees": {
"nodes": [
{
firstName: 'Russell'
lastName: 'Dodds'
tags: ['teamplayer', 'punctual']
},
{
firstName: 'Emma'
lastName: 'Samsin'
tags: ['teamplayer']
}
]
}
}
}
Can someone please give me some references or suggestions on how to achieve similar results on ARRAY field types in Hasura?
I think you couldn't use array directly in the Hasura console. You should use jsonb instead. It's more appropriate as you can use _append, _prepend, _delete_key...
But it's seems you can use Array with hasura. If your schema come from external service, the input for an array should be a literal. For a column of type tags[] the input value has to be a string like: "{teamplayer,punctual}". It's how Array works in postgres.
So your mutation will be:
mutation {
insert_table(objects:{
tags: "{teamplayer,punctual}"
}) {
returning {
tags
}
}
}

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.

Resources