Amplify automatically creates Amazon DynamoDB database tables for GraphQL types annotated with the @model
directive in your GraphQL schema. You can create relations between the data models via the @hasOne
, @hasMany
, @belongsTo
, and @manyToMany
directives.
The following GraphQL schema automatically creates a database table for "Todo". @model
will also automatically add an id
field as a primary key to the database table. See Configure a primary key to learn how to customize the primary key.
Upon amplify push
or cdk deploy
, Amplify deploys the Todo database table and a corresponding GraphQL API to perform create, read, update, delete, and list operations.
In addition, @model
also adds the helper fields createdAt
and updatedAt
to your type. The values for those fields are read-only by clients unless explicitly overwritten. See Customize creation and update timestamps to learn more.
Try listing all the todos by executing the following query:
Configure a primary keyEvery GraphQL type with the @model
directive will automatically have an id
field set as the primary key. You can override this behavior by marking another required field with the @primaryKey
directive.
In the example below, todoId
is the database's primary key and an id
field will no longer be created automatically anymore by the @model
directive.
Without any further configuration, you'll only be able to query for a Todo via an exact equality match of its primary key field. In the example above, this is the todoId
field.
Note: After a primary key is configured and deployed, you can't change it without deleting and recreating your database table.
You can also specify "sort keys" to use a combination of different fields as a primary key. This also allows you to apply more advanced sorting and filtering conditions on the specified "sort key fields".
The schema above will allow you to pass different conditions to query the correct inventory item:
Configure a secondary indexAmplify uses Amazon DynamoDB tables as the underlying data source for @model types. For key-value databases, it is critical to model your access patterns with "secondary indexes". Use the @index
directive to configure a secondary index.
Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale but making it work for your access patterns requires a bit of forethought. DynamoDB query operations may use at most two attributes to efficiently query data. The first query argument passed to a query (the hash key) must use strict equality and the second attribute (the sort key) may use gt, ge, lt, le, eq, beginsWith, and between. DynamoDB can effectively implement a wide variety of access patterns that are powerful enough for the majority of applications.
A secondary index consists of a "hash key" and, optionally, a "sort key". Use the "hash key" to perform strict equality and the "sort key" for greater than (gt), greater than or equal to (ge), less than (lt), less than or equal to (le), equals (eq), begins with, and between operations.
The example client query below allows you to query for "Customer" records based on their accountRepresentativeID
:
You can also overwrite the queryField
or name
to customize the GraphQL query name, or secondary index name respectively:
To optionally configure sort keys, provide the additional fields in the sortKeyFields
parameter:
The example client query below allows you to query for "Customer" based on their name
and filter based on phoneNumber
:
Create "has one", "has many", "belongs to", and "many to many" relationships between @model
types.
With versions of Amplify CLI @aws-amplify/cli@12.12.2
and API Category@aws-amplify/amplify-category-api@5.11.5
, an improvement was made to how relational field data is handled in subscriptions when different authorization rules apply to related models in a schema. The improvement redacts the values for the relational fields, displaying them as null or empty, to prevent unauthorized access to relational data. This redaction occurs whenever it cannot be determined that the child model will be protected by the same permissions as the parent model.
Because subscriptions are tied to mutations and the selection set provided in the result of a mutation is then passed through to the subscription, relational fields in the result of mutations must be redacted.
If an authorized end-user needs access to the redacted relational field they should perform a query to read the relational data.
Additionally, subscriptions will inherit related authorization when relational fields are set as required. To better protect relational data, consider modifying the schema to use optional relational fields.
Based on the security posture of your application, you can choose to revert to the subscription behavior before this improvement was made.
To do so, use the subscriptionsInheritPrimaryAuth
feature flag under graphqltransformer
in the amplify/backend/cli.json
file.
The @hasOne
and @hasMany
directives do not support referencing a model which then references the initial model via @hasOne
or @hasMany
if DataStore is enabled.
Create a one-directional one-to-one relationship between two models using the @hasOne
directive.
In the example below, a Project has a Team.
This generates queries and mutations that allow you to retrieve the related record from the source record:
To customize the field to be used for storing the relationship information, set the fields
array argument and matching it to a field on the type:
In this case, the Project type has a teamID
field added as an identifier for the team. @hasOne can then get the connected Team object by querying the Team table with this teamID
:
A @hasOne
relationship always uses a reference to the primary key of the related model, by default id
unless overridden with the @primaryKey
directive.
The @hasOne
and @hasMany
directives do not support referencing a model which then references the initial model via @hasOne
or @hasMany
if DataStore is enabled.
Create a one-directional one-to-many relationship between two models using the @hasMany
directive.
This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record:
Under the hood, @hasMany
configures a default secondary index on the related table to enable you to query the related model from the source model.
To customize the specific secondary index used for the "has many" relationship, create an @index
directive on the field in the related table where you want to assign the secondary index.
Next, provide the secondary index with a name
attribute and a value. Optionally, you can configure a âsort keyâ on the secondary index by providing a sortKeyFields
attribute and a designated field as its value.
On the @hasMany
configuration, pass in the name value from your secondary index as the value for the indexName
parameter. Then, pass in the respective fields
that match the connected index.
In this case, the Comment type has a postID
field added to store the reference of Post record. The id
field referenced by @hasMany
is the id
on the Post
type. @hasMany
can then get the connected Comment object by querying the Comment table's secondary index "byPost" with this postID
:
Make a "has one" or "has many" relationship bi-directional with the @belongsTo
directive.
For 1:1 relationships, the @belongsTo directive solely facilitates the ability for you to query from both sides of the relationship. When updating a bi-directional hasOne relationship, you must update both sides of the relationship with corresponding IDs.
This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:
This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:
@belongsTo
can be used without the fields
argument. In those cases, a field is automatically generated to reference the parentâs primary key.
Alternatively, you set up a custom field to store the reference of the parent object. An example bidirectional âhas manyâ relationship is shown below.
Many-to-many relationshipNote: The
@belongsTo
directive requires that a@hasOne
or@hasMany
relationship already exists from parent to the related model.
Create a many-to-many relationship between two models with the @manyToMany
directive. Provide a common relationName
on both models to join them into a many-to-many relationship.
Under the hood, the @manyToMany
directive will create a "join table" named after the relationName
to facilitate the many-to-many relationship. This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:
Important: The authorization rules that Amplify applies to the "join table" it creates are a union of the authorization rules of the individual models in the many-to-many relationship. See this discussion for more context.
Assign default values for fieldsYou can use the @default
directive to specify a default value for optional scalar type fields such as Int
, String
, and more.
If you create a new Todo and don't supply a content
input, Amplify will ensure that My new Todo
is auto populated as a value. When @default
is applied, non-null assertions using !
are disregarded. For example, String!
is treated the same as String
.
A server-side subscription filter expression is automatically generated for any @model
type.
You can filter the subscriptions server-side by passing a filter expression. For example: If you want to subscribe to tasks of type Security
and priority greater than 5
, you can set the filter
argument accordingly.
If you want to get all subscription events, donât pass any filter
parameters.
Important: Passing an empty object {}
as a filter is NOT recommended. Using {}
as a filter might cause inconsistent behavior based on your data model's authorization rules.
You can override the names of any @model
-generated GraphQL queries, mutations, and subscriptions by supplying the desired name.
In the example above, you will be able to run a queryForTodo
query to get a single Todo element.
You can disable specific operations by assigning their value to null
.
The example above disables the getTodo
query, all mutations, and all subscriptions while allowing the generation of other queries such as listTodo
.
You can disable the get
query and create a custom query that enables us to retrieve a single Todo model.
The example above creates a custom query that utilizes the @function
directive to call a Lambda function for this query.
For the type definitions of queries, mutations, and subscriptions, see Type Definitions of the @model
Directive.
The @model
directive automatically adds createdAt
and updatedAt
timestamps to each entity. The timestamp field names can be changed by passing timestamps attribute to the directive.
For example, the schema above will allow you to query for the following contents:
Modify subscriptions (real-time updates) access levelBy default, real-time updates are on for all @model
types, which means customers receive real-time updates and authorization rules are applied during initial connection time. You can also turn off subscriptions for that model or make the real-time updates public, receivable by all subscribers.
You need to explicitly specify the connection field names if relational directives are used to create two connections of the same type between the two models.
Relationships to a model with a composite primary keyWhen a primary key is defined by a sort key in addition to the hash key, then it's called a composite primary key.
If you explicitly define the fields
argument on the @hasOne
, @hasMany
, or @belongsTo
directives and reference a model that has a composite primary key, then you must set the values in the fields
argument in a specific order:
sortKeyFields
specified in the @primaryKey
directive of the related model.Because query creation against a secondary index is automatic, if you wish to define a secondary index that does not have a corresponding query in your API, set the queryField
parameter to null
.
Amplify Studio does not support splitting GraphQL schemas.
If using Amplify Studio, please follow the Limitations section of the Data Modeling documentation for Amplify Studio.
AWS Amplify supports splitting your GraphQL schema into separate .graphql
files.
You can start by creating a amplify/backend/api/<api-name>/schema/
directory. As an example, you might split up the schema for a blog site by creating Blog.graphql
, Post.graphql
, and Comment.graphql
files.
You can then run amplify api gql-compile
and the output build schema will include all the types declared across your schema files.
As your project grows, you may want to organize your custom queries, mutations, and subscriptions depending on the size and maintenance requirements of your project. You can either consolidate all of them into one file or colocate them with their corresponding models.
Using a Single Query.graphql
File
This method involves consolidating all queries into a single Query.graphql
file. It is useful for smaller projects or when you want to keep all queries in one place.
In the amplify/backend/api/<api-name>/schema/
directory, create a file named Query.graphql
.
Copy all query type definitions from your multiple schema files into the Query.graphql
file.
Make sure all your queries are properly formatted and enclosed within a single type Query { ... }
block.
Using the extend
Keyword
Declaring a Query
type in separate schema files will result in schema validation errors similar to the following when running amplify api gql-compile
:
Amplify GraphQL schemas support the extend
keyword, which allows you to extend types with additional fields. In this case, it also allows you to split your custom queries, mutations, and subscriptions into multiple files. This may be more ideal for larger, more complex projects.
Organize your GraphQL schema into multiple files as per your project's architecture.
In one of the files (e.g., schema1.graphql
), declare your type normally:
schema2.graphql
), use the extend
keyword to add to the type:The order in which the Query types are extended does not affect the compilation of separate schema files. However, declaring custom Query, Mutation, and/or Subscription extensions with the same field names in another schema file will result in schema validation errors similar to the following:
ð Object type extension 'Query' cannot redeclare field getBlogById
@auth
, @function
, and @http
directives on fields of Query
, Mutation
, and Subscription
type extensions. Alternately, you can use the extend
keyword to organize custom queries, mutations, and subscriptions that use custom resolvers rather than Amplify directives.Amplify directives are not supported on extended type definitions themselves (e.g., extend type Todo @auth...
), or on fields of extended types other than Query
, Mutation
, and Subscription
.
The @model
directive will generate:
@model
directive Relational directives
The relational directives are @hasOne
, @hasMany
, @belongsTo
and @manyToMany
.
The @hasOne
will generate:
create
and update
mutations.Type definition of the @hasOne
directive
The @hasMany
will generate:
create
and update
mutations.Type definition of the @hasMany
directive
The @belongsTo
will generate:
create
and update
mutations.Type definition of the @belongsTo
directive
The @manyToMany
will generate:
relationName
.create
and update
mutations.Type definition of the @manyToMany
directive
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4