I have AWS AppSync API with DynamoDb and I can create and get data from it with DynamoDb Resolvers. (VTL templates)
I am not sure how can I do the user input validation with VTL templates. I want to make sure the contact's "firstName" is between 2 - 30 characters in length.
How can I achieve this with VTL? Is there a way to do this kind of validation within the GraphQL schema itself?
Here's my GraphQL Schema,
schema {
query: Query
mutation: Mutation
}
type Mutation {
createContact(contact: ContactInput!): Contact!
}
type Contact {
contactId: ID!
firstName: String!
lastName: String!
email: String!
}
input ContactInput {
firstName: String!
lastName: String!
email: String!
}
I can't find a nice way of doing this in GraphQL, but you can do it easily in VTL using either $util.validate or $util.error (see the AWS documentation). They both have the same result of adding an item to the errors array.
Here's a demo of $util.validate:
https://mappingtool.dev/app/appsync/bee55bd607e2166091451e7a7959318e
Here's a demo of $util.error:
https://mappingtool.dev/app/appsync/006d6c05e8bb7257c6cebce34494994c
Related
When creating a Many-to-Many relationship using GraphQL for the schema, I have been unable to alter the entity created. The #manyToMany annotation enables the syntax to produce a table named "OrderUsers". But the problem lies in my inability to alter the "OrderUsers" entity. After different attempts at changing the table, I have been unable to figure out how to change it. The only attributes that are taken into the "OrderUsers" table are the id from both the User as well as Order table, which also creates only two GSIs. Also, this is using the v2 docs.
type User #model {
id: ID!
fName: String!
lName: String!
phoneNumber: String!
email: String!
DOB: String!
orders: [Order] #manyToMany(relationName: "OrderUsers")
ordersByDate: [Order] #hasMany(indexName: "byOrderByDate", fields: ["id"])
ordersByStatusDate: [Order] #hasMany(indexName: "byOrderStatusByDate", fields: ["id"])
}
type Order #model {
id: ID!
userId: ID! #index(name: "byOrderStatusByDate", sortKeyFields: ["status", "date"]) #index(name: "byOrderByDate", sortKeyFields: ["date"])
status: String!
amount: Int
date: String!
users: [User] #manyToMany(relationName: "OrderUsers") # Test to see if I can tinker w/ the 'OrderUsers' tbl
productId: ID! #index(name: "byProductOrder", sortKeyFields: ["id"])
clubId: ID! #index(name: "byClub", sortKeyFields: ["id"])
}
After reviewing the AWS Amplify as well as AppSync docs, attempting to add GSIs to the 'OrderUsers' table, switch the partition key used from the 'User' entity to a composite partition key for the 'OrderUsers' table, and adding other attributes to the 'OrderUsers' table, everything gets wiped as I try to push/pull it. Since the syntax isn't stored in the schema.graphql file, I have been stuck. My expectation was that it would save into the schema and update the resolvers used for the mutation(s) & queries, but that has not been the case.
Any and all help would be appreciated,
Thank you & Happy holidays
I am currently sucessfully being able to extend types across services.
Service A:
type User #key(fields: "id") {
id: ID!
}
Service B:
extend type User #key(fields: "id") {
id: ID! #external
extendedList: [ExtendedType]
}
And then ofcource resolve this just fine. However I have one case where I want to do this within one subgraph, is this possible? I know the real solution would be to split those up into two subgraphs but this is not possible currently.
I have the following entities within one subgraph:
type Chat #key(fields: "id") {
id: ID!
listingId: String!
createdAt: DateTime!
updatedAt: DateTime!
participants: [Participant!]!
title: String!
}
type Message {
id: ID!
chatId: String!
content: String!
createdAt: DateTime!
participant: Participant!
}
I dont always want to resolve messages when querying the Chat entity, and would like to do like I did in the example above and extend the type like such:
extend type Chat #key(fields: "id") {
id: ID!
messages: [Message!]!
}
Is this possible in any way when the entities are in the same subgraph?
I used AWS Amplify to create an GraphQL API. In DynamoDB the fields createdAt and updatedAt are created automatically. I have no way of filter values for this fields with Appsync. I would like to query data with appsync with filter range between two createdAt field but it doesn't appear in my appsync query schema.
So how can I do a query with createdAt filter or sort?
This is an AWS-Amplify specific question. It's not about how to do this with generic GraphQL.
I found the solution finally.
You have to add auto generated fields "createdAt" and "updatedAt" directly on the schema.graphql
Like that:
According to this inital schema.graphql:
type User #model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn" })
{
id: String!
username: String!
firstName: String!
lastName: String!
}
It will become:
type User #model
{
id: String!
username: String!
firstName: String!
lastName: String!
createdAt: AWSDateTime! #important to keep it to have filter with keys
updatedAt: AWSDateTime! #important to keep it to have filter with keys
}
After the amplify push, we can get items by date directly, simply like that:
query MyQuery {
listUsers(filter: {updatedAt: {between: ["2021-04-29T16:02:21.285Z", "2021-05-29T16:02:21.285Z"]}}) {
items {
id
lastName
}
}
}
So I have the schema below. If I try to query data off this schema AppSync will time out saying 'NetworkError when attempting to fetch resource.'
type Model {
PartitionKey: ID!
SortKey: ID!
Name: String
Version: Int
FBX: String
# ms since epoch
CreatedAt: AWSTimestamp
Description: String
Tags: [Tag]
}
type ImageSet {
PartitionKey: ID!
SortKey: ID!
Name: String
CreatedAt: AWSTimestamp
Description: String
Tags: [String]
}
Now, if I change 'Name' in the model to 'ModelName' then queries on that will work. If I change 'Name' in ImageSet to 'SetName' then queries on that will work.
What is going on with this? What is wrong with the 'Name' field name? 'Description' and 'CreatedAt' do not have this issue.
Edit
Actually I am encountering this happening with other fields in the
schema as well. Please help.
I do have resolvers attached to specific fields. Removing them does
solve the problem. Am I not supposed to attach revolvers to specific
fields or is something else wrong?
-
Edit 2
This really does seem to only occur if the name of a field is shared
between different schema objects, is that not allowed!?
does anyone know if there is a recent problem with camelcased properties.
I have a model like this:
var attr = DS.attr;
App.Users = DS.Model.extend({
firstName: attr('string'),
phone: attr('string'),
email: attr('string')
});
In my template email and phone show up correctly but firstName doesnt appear. I checked the json file and everything seems to be fine. With all my other models the same problems appear,
so i guess it has to do something with the camelCase.
Deprecation Notice: This answer is from 2013, and hasn't been touched up until now. This does not reflect JSON API Adapter but rather Ember-Data's RESTAdapter.
Ember.js relies on naming conventions, and it expects that multiple-word-camel-case (e.g. firstName) model properties to be mapped to multiple-word-underscore-separated-lower-case attributes (e.g. first_name) on the JSON response. If your JSON is giving you firstName, or anything that is not in this convention in a scenario that you do not control the backend API, you have the option of defining a map which tells your adapter to look for a specific key in the JSON response and map it to a property in a given Model.
You can do something like this:
DS.RESTAdapter.map('App.User', {
firstName: { key: 'firstName' },
lastName: { key: 'familyName' }
});
Note that in the sample above I've added a lastName property which is not part of your own model. I've done that just to make it clear that you can map several properties at the same time, and its name in the JSON response can be anything, not necessarily the same name in a different casing.