Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(appsync): support query & mutation generation for code-first approach #9992

Merged
merged 105 commits into from
Aug 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
46df9f0
complete SchemaBaseType
BryanPan342 Jul 22, 2020
84a7b4c
add doc strings to some classes
BryanPan342 Jul 23, 2020
f3350e3
Merge branch 'master' into appsync-schema
BryanPan342 Jul 23, 2020
ede2020
preliminary changes
BryanPan342 Jul 24, 2020
d9271ec
create enum for schemaDefinition
BryanPan342 Jul 28, 2020
7904e62
adjusted SchemaDefinition to allow for S3
BryanPan342 Jul 28, 2020
4591a70
change addType to addDefinition for temporary inclusion
BryanPan342 Jul 28, 2020
da20dcd
s3 testing
BryanPan342 Jul 28, 2020
6ede81e
Merge branch 'master' into shema
BryanPan342 Aug 3, 2020
4d48a2d
prelim changes
BryanPan342 Aug 3, 2020
63e35b3
prelim run of addType
BryanPan342 Aug 3, 2020
1b82340
reorg schema functions
BryanPan342 Aug 3, 2020
fad768a
== to ===
BryanPan342 Aug 3, 2020
5bec482
chore up schema functions
BryanPan342 Aug 3, 2020
96021db
remove readme section on s3 assets
BryanPan342 Aug 3, 2020
0184c25
remove unneccessary prop this.types
BryanPan342 Aug 3, 2020
2a7c641
remove props
BryanPan342 Aug 3, 2020
076ebdf
expected json file
BryanPan342 Aug 3, 2020
a351a04
listing implementation corrected
BryanPan342 Aug 3, 2020
8637009
update readme
BryanPan342 Aug 3, 2020
0ecd95f
fix bug in integ
BryanPan342 Aug 3, 2020
7005315
pls fix build bug
BryanPan342 Aug 3, 2020
28f7e93
add todo
BryanPan342 Aug 3, 2020
fc98566
dont change list or required
BryanPan342 Aug 4, 2020
c27a158
prelim testing for the OO design
BryanPan342 Aug 5, 2020
72d8be4
new implementation
BryanPan342 Aug 6, 2020
bff3e3b
oops.. forgot to stage changes
BryanPan342 Aug 6, 2020
47d9c89
revert changes to prevent merge conflicts
BryanPan342 Aug 6, 2020
1e2dd60
updated api for generating attribute types
BryanPan342 Aug 7, 2020
d8ee61c
Merge branch 'master' into shema
BryanPan342 Aug 8, 2020
1d1aec9
round off integ test, clean up writing, change api name
BryanPan342 Aug 10, 2020
81563c0
Merge branch 'shema' of https://github.com/BryanPan342/aws-cdk into s…
BryanPan342 Aug 10, 2020
a1e34a3
chore up readme
BryanPan342 Aug 10, 2020
e7b57a4
chore up unit tests
BryanPan342 Aug 10, 2020
7c8115f
allow for object types to be created externally
BryanPan342 Aug 10, 2020
04705e4
update integ for external object type
BryanPan342 Aug 10, 2020
bd6868c
prevent faiils
BryanPan342 Aug 10, 2020
050b160
clean up code and finish up readme for object types
BryanPan342 Aug 10, 2020
08aa720
style change to readme
BryanPan342 Aug 10, 2020
d5bd67c
interfaces implemented
BryanPan342 Aug 11, 2020
14093f6
implemeneted resolvable fields
BryanPan342 Aug 13, 2020
315ffbf
clean up some implementation and some docs
BryanPan342 Aug 13, 2020
66b3685
Merge branch 'shema' into resolvable-fields
BryanPan342 Aug 13, 2020
de4c2ad
edit schema
BryanPan342 Aug 13, 2020
2dc962b
make sure implement interface is appended
BryanPan342 Aug 13, 2020
dfbe57d
Merge branch 'shema' into resolvable-fields
BryanPan342 Aug 14, 2020
912a674
bug fix
BryanPan342 Aug 14, 2020
8bf6ef5
Merge branch 'shema' into resolvable-fields
BryanPan342 Aug 14, 2020
6511d86
fix a bug in implementation
BryanPan342 Aug 14, 2020
beee254
update code-first example on readme
BryanPan342 Aug 14, 2020
dac080d
Merge branch 'master' into resolvable-fields
BryanPan342 Aug 15, 2020
a45ab5c
make resolvable fields as part of graphql type
BryanPan342 Aug 17, 2020
9a6fb99
separate and create IField Interface
BryanPan342 Aug 17, 2020
72cad42
write test cases
BryanPan342 Aug 17, 2020
e0bb9c0
remove unneccessary static function
BryanPan342 Aug 18, 2020
bf1133c
Merge branch 'master' into resolvable-fields
BryanPan342 Aug 18, 2020
3478a47
first pass changes
BryanPan342 Aug 18, 2020
1c549b5
write tests and fix bugs
BryanPan342 Aug 18, 2020
988d2da
remove unneccessary function
BryanPan342 Aug 18, 2020
2f42e64
bug fix
BryanPan342 Aug 18, 2020
f938da8
update test
BryanPan342 Aug 18, 2020
6eb781f
update Readme and make interface for intermediate type
BryanPan342 Aug 19, 2020
2d89379
remove spacing
BryanPan342 Aug 19, 2020
1100f1f
add links
BryanPan342 Aug 19, 2020
57fcb03
address issue
BryanPan342 Aug 20, 2020
783415c
Merge branch 'master' into resolvable-fields
BryanPan342 Aug 20, 2020
11d0f3d
lint
BryanPan342 Aug 20, 2020
b804c15
separating schema from graphql api
BryanPan342 Aug 21, 2020
d0fddda
update readme
BryanPan342 Aug 21, 2020
3d3fa2b
fix suggestions
BryanPan342 Aug 21, 2020
cb6a21b
Merge branch 'master' into resolvable-fields
BryanPan342 Aug 21, 2020
911c87d
implement pipelineConfig + refactor
BryanPan342 Aug 24, 2020
f4df2aa
Merge branch 'master' into schema
BryanPan342 Aug 24, 2020
c23029f
update readme
BryanPan342 Aug 24, 2020
8d510fb
api changes
BryanPan342 Aug 24, 2020
abd1057
fix readme
BryanPan342 Aug 24, 2020
c0e4642
Merge branch 'resolvable-fields' into schema
BryanPan342 Aug 24, 2020
c8408e0
add tests
BryanPan342 Aug 24, 2020
0fd0f2c
allow public definition
BryanPan342 Aug 24, 2020
ba9f337
Merge branch 'master' into schema
BryanPan342 Aug 24, 2020
7ffe7c7
address changes
BryanPan342 Aug 25, 2020
70d584e
update readme
BryanPan342 Aug 25, 2020
8bb0a2a
address suggestions
BryanPan342 Aug 25, 2020
f08f4b8
Merge branch 'master' into schema
BryanPan342 Aug 25, 2020
b3f6843
jsii bug
BryanPan342 Aug 25, 2020
dbb0be2
preliminary changes
BryanPan342 Aug 26, 2020
04ae956
add test for schema.addQuery
BryanPan342 Aug 26, 2020
8d3f899
base changes
BryanPan342 Aug 26, 2020
b0600bb
clean up declareSchema
BryanPan342 Aug 26, 2020
b871a2a
remove addXxxType
BryanPan342 Aug 26, 2020
6f4f5f6
Merge branch 'master' into schema
BryanPan342 Aug 26, 2020
4789137
Merge branch 'schema' into query
BryanPan342 Aug 26, 2020
616a749
Merge branch 'master' into query
BryanPan342 Aug 26, 2020
3871eba
update tests
BryanPan342 Aug 27, 2020
2308c9d
Merge branch 'master' into query
BryanPan342 Aug 27, 2020
69febfd
Merge branch 'query' of https://github.com/BryanPan342/aws-cdk into q…
BryanPan342 Aug 27, 2020
a633f85
update basic readme
BryanPan342 Aug 27, 2020
fdc8a24
update readme with info on query
BryanPan342 Aug 27, 2020
d6f50e1
Merge branch 'master' into query
BryanPan342 Aug 27, 2020
4815997
refactor declareSchema
BryanPan342 Aug 27, 2020
d88f6ae
support mutations
BryanPan342 Aug 28, 2020
d38ba5d
remove attachXxxType
BryanPan342 Aug 28, 2020
23aa01a
address comments
BryanPan342 Aug 29, 2020
0fa73d3
:(
BryanPan342 Aug 29, 2020
0c84ab2
Merge branch 'master' into query
mergify[bot] Aug 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 61 additions & 18 deletions packages/@aws-cdk/aws-appsync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ api.grantMutation(role, 'updateExample');
api.grant(role, appsync.IamResource.ofType('Mutation', 'updateExample'), 'appsync:GraphQL');
```

## Code-First Schema
### Code-First Schema

CDK offers the ability to generate your schema in a code-first approach.
A code-first approach offers a developer workflow with:
Expand All @@ -235,7 +235,7 @@ A code-first approach offers a developer workflow with:

The code-first approach allows for **dynamic** schema generation. You can generate your schema based on variables and templates to reduce code duplication.

### Code-First Example
#### Code-First Example

To showcase the code-first approach. Let's try to model the following schema segment.

Expand Down Expand Up @@ -331,15 +331,13 @@ this.objectTypes = [ schema.Node, schema.Film ];

const filmConnections = schema.generateEdgeAndConnection(schema.Film);

api.addType('Query', {
definition: {
allFilms: new appsync.ResolvableField(dummyDataSource, {
returnType: filmConnections.connection.attribute(),
args: schema.args,
requestMappingTemplate: dummyRequest,
responseMappingTemplate: dummyResponse,
}),
}
api.addQuery('allFilms', new appsync.ResolvableField({
returnType: filmConnections.connection.attribute(),
args: schema.args,
dataSource: dummyDataSource,
requestMappingTemplate: dummyRequest,
responseMappingTemplate: dummyResponse,
}),
});

this.objectTypes.map((t) => api.addType(t));
Expand All @@ -353,7 +351,7 @@ create the base Object Type (i.e. Film) and from there we can generate its respe

Check out a more in-depth example [here](https://github.com/BryanPan342/starwars-code-first).

### GraphQL Types
#### GraphQL Types

One of the benefits of GraphQL is its strongly typed nature. We define the
types within an object, query, mutation, interface, etc. as **GraphQL Types**.
Expand All @@ -369,12 +367,12 @@ More concretely, GraphQL Types are simply the types appended to variables.
Referencing the object type `Demo` in the previous example, the GraphQL Types
is `String!` and is applied to both the names `id` and `version`.

### Field and Resolvable Fields
#### Field and Resolvable Fields

While `GraphqlType` is a base implementation for GraphQL fields, we have abstractions
on top of `GraphqlType` that provide finer grain support.

#### Field
##### Field

`Field` extends `GraphqlType` and will allow you to define arguments. [**Interface Types**](#Interface-Types) are not resolvable and this class will allow you to define arguments,
but not its resolvers.
Expand All @@ -401,7 +399,7 @@ const type = new appsync.InterfaceType('Node', {
});
```

#### Resolvable Fields
##### Resolvable Fields

`ResolvableField` extends `Field` and will allow you to define arguments and its resolvers.
[**Object Types**](#Object-Types) can have fields that resolve and perform operations on
Expand Down Expand Up @@ -463,7 +461,7 @@ const query = new appsync.ObjectType('Query', {

Learn more about fields and resolvers [here](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html).

### Intermediate Types
#### Intermediate Types

Intermediate Types are defined by Graphql Types and Fields. They have a set of defined
fields, where each field corresponds to another type in the system. Intermediate
Expand All @@ -473,7 +471,7 @@ Intermediate Types include:
- [**Interface Types**](#Interface-Types)
- [**Object Types**](#Object-Types)

### Interface Types
##### Interface Types

**Interface Types** are abstract types that define the implementation of other
intermediate types. They are useful for eliminating duplication and can be used
Expand All @@ -488,7 +486,7 @@ const node = new appsync.InterfaceType('Node', {
});
```

### Object Types
##### Object Types

**Object Types** are types that you declare. For example, in the [code-first example](#code-first-example)
the `demo` variable is an **Object Type**. **Object Types** are defined by
Expand Down Expand Up @@ -565,3 +563,48 @@ You can create Object Types in three ways:
```
> This method provides easy use and is ideal for smaller projects.

#### Query

Every schema requires a top level Query type. By default, the schema will look
for the `Object Type` named `Query`. The top level `Query` is the **only** exposed
type that users can access to perform `GET` operations on your Api.

To add fields for these queries, we can simply run the `addQuery` function to add
to the schema's `Query` type.

```ts
const string = appsync.GraphqlType.string();
const int = appsync.GraphqlType.int();
api.addQuery('allFilms', new appsync.ResolvableField({
returnType: filmConnection.attribute(),
args: { after: string, first: int, before: string, last: int},
dataSource: api.addNoneDataSource('none'),
requestMappingTemplate: dummyRequest,
responseMappingTemplate: dummyResponse,
}));
```

To learn more about top level operations, check out the docs [here](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-overview.html).

#### Mutation

Every schema **can** have a top level Mutation type. By default, the schema will look
for the `Object Type` named `Mutation`. The top level `Mutation` Type is the only exposed
type that users can access to perform `mutable` operations on your Api.

To add fields for these mutations, we can simply run the `addMutation` function to add
to the schema's `Mutation` type.

```ts
const string = appsync.GraphqlType.string();
const int = appsync.GraphqlType.int();
api.addMutation('addFilm', new appsync.ResolvableField({
returnType: film.attribute(),
args: { name: string, film_number: int },
dataSource: api.addNoneDataSource('none'),
requestMappingTemplate: dummyRequest,
responseMappingTemplate: dummyResponse,
}));
```

To learn more about top level operations, check out the docs [here](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-overview.html).
32 changes: 32 additions & 0 deletions packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { CfnApiKey, CfnGraphQLApi, CfnGraphQLSchema } from './appsync.generated'
import { IGraphqlApi, GraphqlApiBase } from './graphqlapi-base';
import { Schema } from './schema';
import { IIntermediateType } from './schema-base';
import { ResolvableField } from './schema-field';
import { ObjectType } from './schema-intermediate';

/**
* enum with all possible values for AppSync authorization type
Expand Down Expand Up @@ -588,4 +590,34 @@ export class GraphQLApi extends GraphqlApiBase {
public addType(type: IIntermediateType): IIntermediateType {
return this.schema.addType(type);
}

/**
* Add a query field to the schema's Query. If one isn't set by
* the user, CDK will create an Object Type called 'Query'. For example,
*
* type Query {
* fieldName: Field.returnType
* }
*
* @param fieldName the name of the query
* @param field the resolvable field to for this query
*/
public addQuery(fieldName: string, field: ResolvableField): ObjectType {
return this.schema.addQuery(fieldName, field);
}

/**
* Add a mutation field to the schema's Mutation. If one isn't set by
* the user, CDK will create an Object Type called 'Mutation'. For example,
*
* type Mutation {
* fieldName: Field.returnType
* }
*
* @param fieldName the name of the Mutation
* @param field the resolvable field to for this Mutation
*/
public addMutation(fieldName: string, field: ResolvableField): ObjectType {
return this.schema.addMutation(fieldName, field);
}
}
83 changes: 80 additions & 3 deletions packages/@aws-cdk/aws-appsync/lib/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { readFileSync } from 'fs';
import { Lazy } from '@aws-cdk/core';
import { CfnGraphQLSchema } from './appsync.generated';
import { GraphQLApi } from './graphqlapi';
import { SchemaMode } from './private';
import { SchemaMode, shapeAddition } from './private';
import { IIntermediateType } from './schema-base';
import { ResolvableField } from './schema-field';
import { ObjectType } from './schema-intermediate';

/**
* The options for configuring a schema
Expand Down Expand Up @@ -44,7 +46,13 @@ export class Schema {
*/
public definition: string;

protected schema?: CfnGraphQLSchema;
private query?: ObjectType;

private mutation?: ObjectType;

private subscription?: ObjectType;

private schema?: CfnGraphQLSchema;

private mode: SchemaMode;

Expand All @@ -68,7 +76,7 @@ export class Schema {
if (!this.schema) {
this.schema = new CfnGraphQLSchema(api, 'Schema', {
apiId: api.apiId,
definition: Lazy.stringValue({ produce: () => this.definition }),
definition: Lazy.stringValue({ produce: () => `${this.declareSchema()}${this.definition}` }),
});
}
return this.schema;
Expand All @@ -92,6 +100,52 @@ export class Schema {
this.definition = `${this.definition}${sep}${addition}\n`;
}

/**
* Add a query field to the schema's Query. If one isn't set by
* the user, CDK will create an Object Type called 'Query'. For example,
*
* type Query {
* fieldName: Field.returnType
* }
*
* @param fieldName the name of the query
* @param field the resolvable field to for this query
*/
public addQuery(fieldName: string, field: ResolvableField): ObjectType {
if (this.mode !== SchemaMode.CODE) {
throw new Error(`Unable to add query. Schema definition mode must be ${SchemaMode.CODE} Received: ${this.mode}`);
}
if (!this.query) {
this.query = new ObjectType('Query', { definition: {} });
this.addType(this.query);
};
this.query.addField(fieldName, field);
return this.query;
}

/**
* Add a mutation field to the schema's Mutation. If one isn't set by
* the user, CDK will create an Object Type called 'Mutation'. For example,
*
* type Mutation {
* fieldName: Field.returnType
* }
*
* @param fieldName the name of the Mutation
* @param field the resolvable field to for this Mutation
*/
public addMutation(fieldName: string, field: ResolvableField): ObjectType {
if (this.mode !== SchemaMode.CODE) {
throw new Error(`Unable to add mutation. Schema definition mode must be ${SchemaMode.CODE} Received: ${this.mode}`);
}
if (!this.mutation) {
this.mutation = new ObjectType('Mutation', { definition: {} });
this.addType(this.mutation);
};
this.mutation.addField(fieldName, field);
return this.mutation;
}

/**
* Add type to the schema
*
Expand All @@ -106,4 +160,27 @@ export class Schema {
this.addToSchema(Lazy.stringValue({ produce: () => type.toString() }));
return type;
}

/**
* Set the root types of this schema if they are defined.
*
* For example:
* schema {
* query: Query
* mutation: Mutation
* subscription: Subscription
* }
*/
private declareSchema(): string {
if (!this.query && !this.mutation && !this.subscription) {
return '';
}
type root = 'mutation' | 'query' | 'subscription';
const list: root[] = ['query', 'mutation', 'subscription'];
return shapeAddition({
prefix: 'schema',
fields: list.map((key: root) => this[key] ? `${key}: ${this[key]?.name}` : '')
.filter((field) => field != ''),
}) + '\n';
}
}
Loading