I'm currently using AppSync to query against a GSI. I've been able to successfully use this block of code in a Pipeline Resolver function, but I don't know why it is not working when I try to use it in a traditional resolver.
I'm currently getting a mapping template error:
{
"data": {
"units": null
},
"errors": [
{
"path": [
"units"
],
"data": null,
"errorType": "MappingTemplate",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Value for field '$[version]' not found."
}
]
}
I tried searching in the AWS docs but adding "version" to the GraphQL type didn't work.
I also tried this (even though I'm not using S3)
AppSync S3Object retrieval
And the docs:
https://docs.aws.amazon.com/appsync/latest/devguide/troubleshooting-and-common-mistakes.html#mapping-template-errors
Here's the request mapping template:
#set($arg=$context.args)
{
"operation": "Query",
"index" : "userPK-userSK-index",
"query": {
"expression": "userPK = :pk and begins_with(userSK, :sk)",
"expressionValues": {
":pk": {"S": "tenant:${arg.tenantId}" },
":sk": {"S": "school-year:${arg.schoolYear}:grades:${arg.gradeId}:subject:${arg.subjectId}:unit:"}
}
}
}
Here's the response mapping template:
$util.toJson($ctx.result.items)
Here is a snippet of the executed GraphQL:
query GetUnits{
units(tenantId: "5fc30406-346c-42e2-8083-fda33ab6000a"
schoolYear: "2019-2020"
gradeId: "c737e341-a0cb-4a16-95de-f3a092049e74"
subjectId: "d0306e25-422d-4628-8fcc-c354b67c932a") {
id
indicator {
id,
description
}
competency {
id,
description,
name
}
description,
name
}
}
Here is a snippet of the GraphQL schema:
type Unit {
id: ID!
competency: Competency
indicator: Indicator
name: String!
description: String
version: Int
}
type Competency {
id: ID
# grade: Grade
# subject: Subject
# schoolYear: String
name: String
description: String
}
type Indicator {
id: ID!
description: String
}
type Query {
units(
tenantId: String!
schoolYear: String!
gradeId: String!
subjectId: String!
): [Unit]
Here's a data example from the DynamoDB table:
Here's a screenshot from a successful query in the Console:
Note: I have created a GSI that maps the userPK and userSK as partition key and sort key respectively. I'm querying that Secondary Index. I've been able to query this successfully using the console.
The error shows you forgot version parameter. This is the query template (docs):
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "some expression",
"expressionNames" : {
"#foo" : "foo"
},
"expressionValues" : {
":bar" : ... typed value
}
}
"index" : "fooIndex",
"nextToken" : "a pagination token",
"limit" : 10,
"scanIndexForward" : true,
"consistentRead" : false,
"select" : "ALL_ATTRIBUTES",
"filter" : {
...
}
}
and the version is required:
version
The template definition version. 2017-02-28 and 2018-05-29 are currently supported. This value is required.
Related
So I am currently playing with AWS AppSync and Amplify, and all is good except, with the new Transformer V2, I am struggling to get things to work.
Here's my schema:
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany
}
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
]
) {
id: ID!
message: String
}
I can create a post and a comment. However, whenever I query a list of posts, I never get comments.
Here's an example of a query:
query MyQuery {
listPosts {
items {
comments {
items {
id
message
createdAt
}
}
content
title
username
}
}
}
and here's the corresponding result I get:
{
"data": {
"listPosts": {
"items": [
{
"comments": {
"items": []
},
"content": "Testing stuff",
"title": "Today is the day",
"username": "bawp"
},
{
"comments": {
"items": []
},
"content": "### hello\n````\n function call()\n```",
"title": "next item of the day",
"username": "paulod"
},
{
"comments": {
"items": []
},
"content": "Hello Word",
"title": "santo dia",
"username": "paulod"
}
]
}
}
}
Notice how the
"comments": {
"items": []
},
It is always empty!
Even though, when I query the Comments table, I get at least one comment added.
query MyQuery {
listComments {
items {
id
message
createdBy
}
}
}
Result:
{
"data": {
"listComments": {
"items": [
{
"id": "ddddf58b-df1c-498c-97b4-6d61361b4b9e",
"message": "Thjis is may coment here\n\n```\nCode could go here also!\n```",
"createdBy": "paulod"
}
]
}
}
}
I am not sure what I am missing here. Remember I am using new directives (Transformer v2) as opposed to the old relationship directives like
#connection
Any help is greatly appreciated.
Thank you very much!
Okay, this is a response to my question for anyone who might run into some of these issues.
Firstly,
The schema!
Since I am adding some relationships between the tables, the directives must be added correctly. Here are the changes I made to my schema:
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany(indexName: "byPost", fields: ["id"]) #check out: https://docs.amplify.aws/cli/graphql/data-modeling/#has-many-relationship
}
#Comment
#queries: null - removes any authorization rules for queries, allowing anyone to query for comments
#ownerField:createdBy - sets the createdBy field as the currently signed in user
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
]
) {
id: ID!
message: String
post: Post #belongsTo(fields: ["postID"])
postID: ID #index(name: "byPost")
}
Next, because appsync autogenerates the queries.js file on each push, I had to edit this file manually (which is not really a final solution). In particular, the listPosts query:
export const listPosts = /* GraphQL */ `
query ListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
content
username
coverImage
comments {
items {
id
message
postID
createdAt
updatedAt
createdBy
}
}
createdAt
updatedAt
}
nextToken
}
}
`;
You see, when this file is autogenerated, it would have "nextToken" instead of having fields that I wanted to query. In other words, the comments field would have { nextToken }
So, the query would look like this:
export const listPosts = /* GraphQL */ `
query ListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
content
username
coverImage
comments {
nextToken # --> this is what was autogenerated, which was giving me issues!!!
}
createdAt
updatedAt
}
nextToken
}
}
`;
Once I changed nextToke with what I showed you earlier in the post, it all worked perfectly.
Now, I know that changing this file manually doesn't seem right. However, I am not in the process of figuring out a better way to do this.
But for now, that's what I was able to come up with.
I hope this helps somebody running into similar issues.
Thank you!
I have applied the schema just like you did in the answer, but also made the postId field important.
I think that has helped get the nested comments.
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
{ allow: private, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany(indexName: "byPost", fields: ["id"]) #check out: https://docs.amplify.aws/cli/graphql/data-modeling/#has-many-relationship
}
#Comment
#queries: null - removes any authorization rules for queries, allowing anyone to query for comments
#ownerField:createdBy - sets the createdBy field as the currently signed in user
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
{ allow: private, operations: [read] }
]
) {
id: ID!
message: String
post: Post #belongsTo(fields: ["postID"])
postID: ID! #index(name: "byPost")
}
I am using aws-amplify to define my appsync schema.
I have following simplified schema:
type Country #model {
id: ID!
name: String!
code: String!
tracks: [Track] #connection(name: "CountryTrack")
}
type Track #model
id: ID!
name: String!
country: Country! #connection(name: "CountryTrack")
lng: Float
lat: Float
length: Float
curves: Int
website: String
trackImage: String
information: String
}
Amplify generates the FilterInput for the models. However it does not include the connection types.
I want to filter a Track based on the Country.
The dynamodb tables does have a trackCountryId and in the scan operation I can simply filter based on the id.
However this does not work in the graphql schema. Because the trackCountryId is not included into the FiterInput.
Does anyone know how to work around this?
Amplify CLI creates listTracks query+resolver, and tracks resolver on the Country type, out of the box. If you would like to filter all Tracks based on a countryId, you would have to add this manually in the following steps, which are essentially a mix of the above generated query+resolvers:
-> In your Schema: Add this within the type Query, and then click on "Save Schema":
listTracksByCountry(countryId: ID!, limit: Int, nextToken: String, sortDirection: ModelSortDirection): ModelTrackConnection
-> Attach a Resolver to this query field you just added, and click on "Save Resolver":
Pick the TrackTable as your Data source name
RequestMapping template:
#set( $limit = $util.defaultIfNull($context.args.limit, 10) )
{
"version": "2017-02-28",
"operation": "Query",
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "trackCountryId"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.args.countryId"
}
}
},
"scanIndexForward": #if( $context.args.sortDirection )
#if( $context.args.sortDirection == "ASC" )
true
#else
false
#end
#else
true
#end,
"filter": #if( $context.args.filter )
$util.transform.toDynamoDBFilterExpression($ctx.args.filter)
#else
null
#end,
"limit": $limit,
"nextToken": #if( $context.args.nextToken )
"$context.args.nextToken"
#else
null
#end,
"index": "gsi-CountryTrack"
}
ResponseMapping template:
#if( !$result )
#set( $result = $ctx.result )
#end
$util.toJson($result)
-> Navigate to the Queries section on the Console, and run the following query:
query {
listTracksByCountry(countryId: "countryId1") {
items {
id
name
length
}
}
}
You should be able to get a list of tracks for the countryId you specified. In my case, the GraphQL output for the above operation was:
{
"data": {
"listTracksByCountry": {
"items": [
{
"id": "trackId1",
"name": "track name 1",
"length": 1.1
},
{
"id": "trackId2",
"name": "track name 2",
"length": 1.2
}
]
}
}
}
This seems to be a very common use case, so feel free to create an issue here, if it doesn't exist already, and we can then have Amplify CLI (amplify add api), generate these resolvers automatically.
I created a schema using the amplify cli and everything works as expected. The problem is when i try to perform a query on the events model it brings back comments as being null even though the event has comments. What confuses me more is when i query the comments alone they bring back their respective events but same thing does not work when i query for events. This is my schema below:
type Event #model {
id: ID!
title: String!
latitude: Float!
longitude: Float!
startDate: String!
endDate: String!
description: String!
coverUrl: String!
locationName: String!
Owner: User! #connection
attendies: [User!] #connection
photos: [Photo]
organization: Organization
comments: [Comment] #connection
}
type Comment #model {
id: ID!
user: User! #connection
event: Event! #connection
text: String!
}
The queries i performed are:
List Events
query listEvents {
listEvents {
items {
title
Owner {
username
}
comments {
items{
text
}
}
}
}
}
which brings back:
{
"data": {
"listEvents": {
"items": [
{
"title": "second Event",
"Owner": {
"username": "likono"
},
"comments": {
"items": []
}
}
]
}
}
}
and List Comments
query listComment{
listComments{
items{
text
event {
title
id
}
}
}
}
which brings back
{
"data": {
"listComments": {
"items": [
{
"text": "Second Comment Same User Same Event",
"event": {
"title": "second Event",
"id": "8bd6656b-b307-4e8f-ba65-84f75a4c2298"
}
}
]
}
}
}
Any help will be appreciated. Thanks.
My backend replies to find all requests:
User.find();
Like this
{ 'users' : [ user1_obj, user2_obj ] }
Ember-data is happy about it. Now if I do a simple single object find:
User.find('user1');
I have tried configuring the backend to return any of the following:
user1
{ 'user1' : user1_obj }
{ 'user' : { 'user1' : user1_obj } }
{ 'user' : user1_obj }
But none of those are working. What should I return from the backend in reply to find("obj-id") requests? According to the documentation about JSON ROOT, the right format looks like:
{ 'user' : user1_obj }
Ember does not complain about it, but the Ember Objects processed have a very strange structure, like this:
As you can see, _reference.record is referring to the top record. Also (not shown here) _data field is empty.
What could be causing that strange nesting?
EDIT
As linked by mavilein in his answer, the JSON API suggests using a different format for singular resources:
{ 'users' : [user1_obj] }
That means, the same format as for plural resources. Not sure if Ember will swallow that, I'll check now.
Following this specification, i would suspect the following:
{
'users' : [{
"id": "1",
"name" : "John Doe"
},{
"id": "2",
"name" : "Jane Doe"
}]
}
For singular resources the specification says:
Singular resources are represented as JSON objects. However, they are
still wrapped inside an array:
{
'users' : [{
"id": "1",
"name" : "John Doe"
}]
}
Using User.find() will expect the rootKey pluralized and in your content an array of elements, the response format is the following json:
{
users: [
{ id: 1, name: 'Kris' },
{ id: 2, name: 'Luke' },
{ id: 3, name: 'Formerly Alex' }
]
}
And with User.find(1) the rootKey in singular, and just one object:
{
user: {
id: 1, name: 'Kris'
}
}
Here a demo showing this working
I was working on a code which was about integrating ExtJS 4 and Django. The link is:
https://github.com/diegocmsantos/extjs4-tdc2011-django
It works fine on ExtJS 4.0.0. But when I upgrade to 4.1.0 it's proxy returns update api instead of create.
I have added the 'idProperty' parameter to the Model, but still gives me the same result.
Model class:
Ext.define('TDC2011.model.Contact', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields : [
{ name : "id", type : "int", mapping : "#id" },
{ name : "name", type : "string"},
{ name : "phone", type : "string"},
{ name : "email", type : "string"}]
});
Store Class:
Ext.define('TDC2011.store.Contacts', {
extend: 'Ext.data.Store',
model: 'TDC2011.model.Contact',
autoLoad: true,
pageSize: 35,
autoLoad: {start: 0, limit: 35},
proxy: {
type: 'ajax',
api: {
read : 'contact/view.action',
create : 'contact/create.action/',
update: 'contact/update.action/',
destroy: 'contact/delete.action/'
},
reader: {
type: 'json',
root: 'data',
successProperty: 'success'
},
writer: {
type: 'json',
writeAllFields: true,
encode: false,
root: 'data'
},
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'REMOTE EXCEPTION',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
}
});
Is there anyone who knows the main cause of problem?