Graphql mutation error in aws amplify appsync - graphql

I am trying to insert/mutate a data using graphql to a dynamodb, see image below having error while inserting data. I am confused if the error exist while creating the schema or while mutating the data. The table was created using amplify
this is the schema script
type PersonalAttributes {
FirstName: String
LastName: String
MiddleName: String
Email: String
Highlights: String
}
type Configurations {
StudyTopic: String
SpokenLanguage: String
Gender: String
ReadbackSpeed: Float
}
type Chapter {
CTitle: String
Content: String
TermHighlights: [String]
}
type Book {
Title: String
Author: String
HighlightsChapter: [Chapter]
}
type Athena #model {
UserKey: ID
UserName: String!
PersonalInformation: [PersonalAttributes]
SysConfig: [Configurations]
Books: [Book]
}

I recommend including an id: ID! for your Athena model. Provide a valid ID whenever you create Athena objects.
The error indicates that no id was provided (Dynamo wanted a valid, non-null String, but it got null.)
The error results from the create mutation call, not from setup of the Dynamo table.

Related

Spring GraphQLmultiple schemas with Query per file

with Spring-GraphQl if I have following two schemas in the resources/graphql folder:
schema1:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
schema2:
type Query {
personByName(name: String): Person
}
type Person {
id: ID
firstName: String
lastName: String
}
Spring-GraphQL seems to be merging them into one GraphQL schema file and starting of Spring-Boot Graphql app ends with following error:
Caused by: graphql.schema.idl.errors.SchemaProblem: errors=['Query' type [#1:1] tried to redefine existing 'Query' type [#1:1]]
When I change it to:
schema1:
type Query {
bookById(id: ID): Book
personByName(name: String): Person
}
schema2:
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
type Person {
id: ID
firstName: String
lastName: String
}
it works perfectly good and I am able to call both queries with graphiql. How graphql spring works with multiple schemas? It seems spring-graphql merges files into one schema so multiple Query types per file breaks the app.
Thanks for answer.
Spring GraphQL is loading all schema resources under the configured location and is using TypeDefinitionRegistry::merge to create a single schema out of them.
I think that redifining any type (even the Query one) should raise an error, otherwise this could hide important issues and conflicting schema definitions. That's what GraphQL Java's TypeDefinitionRegistry is doing.
You can organize your schema files like this:
graphql/schema.graphqls
type Query {
}
// add common directives, scalars, etc
graphql/books.graphqls
extend type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
graphql/person.graphqls
extend type Query {
personByName(name: String): Person
}
type Person {
id: ID
firstName: String
lastName: String
}

Query an interface that implements another interface in GraphQL

I'm currently working on an Activity Feed built using GraphQL Nexus and Apollo Server (3.9.0). It will receive a flurry of information that will have shared fields that are handled by a shared IActivity interface.
In addition, there will be types that will also share similar fields through other interfaces that are not included in IActivity, say for example IMedia and INews.
We are looking for a way to bring all the fields from IActivity and be able to query IMedia and INews within IActivity. We know that there is a possibility to query the concrete types, but we'd like to avoid it, as we want to extend the backend by adding new types of feeds (That share the same fields of those interfaces) without updating the client (it's a react-native application). We would use concrete types only when rendering custom UI components.
Here's an example:
interface IActivity {
id: ID!
name: String!
description: String
}
interface IMedia implements IActivity {
id: ID!
name: String!
description: String
url: String
type: String
}
interface INews implements IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
}
type Video implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
format: String
codec: String
}
type Image implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
compressed: Boolean
codec: String
extension: String
}
type Audio implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
bitrate: Boolean
}
type Post implements INews & IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
comments: [Comment]
}
type Comment {
author: String
message: String
}
type FlashNews implements INews & IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
rating: Int
}
type Query {
activityFeed(): [IActivity]
}
This is the query
query getFeed() {
activityFeed {
id
name
description
... on IMedia {
url
type
}
... on INews {
date
author
content
}
}
}
This queries all the fields from IActivity but none of IMedia nor INews. There are no GraphQL errors (and we lint them through graphql-codegen and the Nexus builder.)
Our belief was that having IActivity also share the same as other interfaces, we could query IActivity and then specify the other interface (e.g: IMedia) as we do with concrete types.
In hindsight, what we're trying to do is somehow a union type of interfaces (which I know it's not possible)...
Is there a workaround or a solution for what we're trying to accomplish?
Edit
We found out that this exact example IS valid, and the problem is within how GraphQL Nexus is configured.
Here's a code sandbox and its Git Repo using plain Apollo Server.
Edit 2:
Try the following query:
query getFeed {
activityFeed {
id
name
description
... on IMedia {
type
format
}
... on INews {
date
author
content
}
... on Video {
length
}
}
}
We have found the problem. It's been Apollo Client (front-end) which was not properly parsing the heuristic fragment matcher.
More information on how we solved the issue can be found here:
https://stackoverflow.com/a/64886593/1057052
We generated something like this:
schema: "./appsync/appSync.gql"
# documents: "./appsync/**/*.gql"
generates:
src/generated/graphql.schema.json:
plugins:
- 'fragment-matcher'
apolloClientVersion: 3
Then the interfaces were working properly!

Querying all objects in Amplify mock api and getting null

I am using Amplify in a simple use case to mock an existing frontend. I have a cutdown schema.graphql as follows:
input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }
schema {
query: Query
}
type Query {
getAirports: [Airport]
}
type Airport #model {
id: Int! #primaryKey
code: String!
city: String!
country: String!
}
The getAirports query is intended to return all the airports. I run amplify mock api and it generates all the resolvers.
When I navigate to http://localhost:20002, I can see the option to use getAirports, however it returns null even when data is present in the mocked database. The response is
{"data":null,"errors":[{"message":"Cannot return null for non-nullable field Query.getAirports.","locations":[{"line":2,"column":3}],"path":["getAirports"]}]}
I'm curious how I can write the schema to have a getAirports query in a way that it returns data a full list of Airports similar to listAirports which is created by default.

Is there a scalar type for arrays and maps in graphql for schemas in AWS amplify?

I was learning to use AWS amplify with React, and the API it uses is a GraphQL API that leverages AWS AppSync. I'm very new to graphQL and my schema currently is like this. This is the schema inside the amplify app:
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
}
To give you an example, I want to store an array of objects inside components in the Note type like this:
Code-1
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: []
}
But reading the docs I got to know there aren't any array scalar types. I know that I can create another table and do it like this instead:
Code-2
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: [elements!]!
}
type elements #model {
id: ID!
item: String!
}
But I don't want this as it creates a new table. I just want one table containing id, name, description, title, image and a components array where you can store objects in like shown above in Code-1. Is there any possible way to do this? Also whats the role of "#modal" in the schema?
Checked out the AWS docs and found out that I could use AWSJSON for lists/arrays like [1, 2, 3] and maps like {"upvotes": 10}, so now my schema is:
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: AWSJSON
}
Here is the link to know more about it AWS Scalar Types

Graphql with nested mutations?

I am trying to figure out how to mutate a nested object with graphql mutations, if possible. For instance I have the following schema:
type Event {
id: String
name: String
description: String
place: Place
}
type Place {
id: String
name: String
location: Location
}
type Location {
city: String
country: String
zip: String
}
type Query {
events: [Event]
}
type Mutation {
updateEvent(id: String, name: String, description: String): Event
}
schema {
query: Query
mutation: Mutation
}
How can I add the place information inside my updateEvent mutation?
Generally speaking, you should avoid thinking of the arguments to your mutations as a direct mapping to object types in your schema. Whilst it's true that they will often be similar, you're better off approaching things under the assumption that they won't be.
Using your basic types as an example. Let's say I wanted to create a new event, but rather than knowing the location, I just have the longitude/latitude - it's actually the backend that calculates the real location object from this data, and I certainly don't know its ID (it doesn't have one yet!). I'd probably construct my mutation like this:
input Point {
longitude: Float!
latitude: Float!
}
input PlaceInput {
name
coordinates: Point!
}
type mutation {
createEvent(
name: String!
description: String
placeId: ID
newPlace: PlaceInput
): Event
updateEvent(
id: ID!
name: String!
description: String
placeId: ID
newPlace: PlaceInput
): Event
)
A mutation is basically just a function call, and it's best to think of it in those terms. If you wrote a function to create an Event, you likely wouldn't provide it an event and expect it to return an event, you'd provide the information necessary to create an Event.
If you want to add a whole object to the mutation you have to define a graphql element of the type input. Here is a link to a small cheatsheet.
In your case it could look like this:
type Location {
city: String
country: String
zip: String
}
type Place {
id: String
name: String
location: Location
}
type Event {
id: String
name: String
description: String
place: Place
}
input LocationInput {
city: String
country: String
zip: String
}
input PlaceInput {
id: ID!
name: String!
location: LocationInput!
}
type Query {
events: [Event]
}
type Mutation {
updateEvent(id: String, name: String, description: String, place: PlaceInput!): Event
}
schema {
query: Query
mutation: Mutation
}

Resources