Skip to content

Commit 30a5b80

Browse files
authored
feat(appsync): support enumeration types for code-first approach (#10023)
Support `Enum Types` for code-first approach. `Enum Types` are special types of Intermediate Types in CDK. <details> <summary> Desired GraphQL Enum</summary> ```gql enum Episode { NEWHOPE EMPIRE JEDI } ``` </details> The above GraphQL Enumeration Type can be expressed in CDK as the following: <details> <summary>CDK Code</summary> ```ts const episode = new appsync.EnumType('Episode', { definition: [ 'NEWHOPE', 'EMPIRE', 'JEDI', ], }); api.addType(episode); ``` </details> Discussion on the addField API can be found [here](#10023 (comment)). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 8cfc190 commit 30a5b80

File tree

5 files changed

+287
-39
lines changed

5 files changed

+287
-39
lines changed

packages/@aws-cdk/aws-appsync/README.md

+36
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ Types will be the meat of your GraphQL Schema as they are the types defined by y
563563
Intermediate Types include:
564564
- [**Interface Types**](#Interface-Types)
565565
- [**Object Types**](#Object-Types)
566+
- [**Enum Types**](#Enum-Types)
566567
- [**Input Types**](#Input-Types)
567568
- [**Union Types**](#Union-Types)
568569

@@ -581,6 +582,8 @@ const node = new appsync.InterfaceType('Node', {
581582
});
582583
```
583584

585+
To learn more about **Interface Types**, read the docs [here](https://graphql.org/learn/schema/#interfaces).
586+
584587
##### Object Types
585588

586589
**Object Types** are types that you declare. For example, in the [code-first example](#code-first-example)
@@ -644,6 +647,39 @@ You can create Object Types in three ways:
644647
```
645648
> This method allows for reusability and modularity, ideal for reducing code duplication.
646649

650+
To learn more about **Object Types**, read the docs [here](https://graphql.org/learn/schema/#object-types-and-fields).
651+
652+
### Enum Types
653+
654+
**Enum Types** are a special type of Intermediate Type. They restrict a particular
655+
set of allowed values for other Intermediate Types.
656+
657+
```gql
658+
enum Episode {
659+
NEWHOPE
660+
EMPIRE
661+
JEDI
662+
}
663+
```
664+
665+
> This means that wherever we use the type Episode in our schema, we expect it to
666+
> be exactly one of NEWHOPE, EMPIRE, or JEDI.
667+
668+
The above GraphQL Enumeration Type can be expressed in CDK as the following:
669+
670+
```ts
671+
const episode = new appsync.EnumType('Episode', {
672+
definition: [
673+
'NEWHOPE',
674+
'EMPIRE',
675+
'JEDI',
676+
],
677+
});
678+
api.addType(episode);
679+
```
680+
681+
To learn more about **Enum Types**, read the docs [here](https://graphql.org/learn/schema/#enumeration-types).
682+
647683
##### Input Types
648684

649685
**Input Types** are special types of Intermediate Types. They give users an

packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts

+129-37
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { BaseTypeOptions, GraphqlType, ResolvableFieldOptions } from './schema-f
1313
*
1414
* @experimental
1515
*/
16-
export interface IntermediateTypeProps {
16+
export interface IntermediateTypeOptions {
1717
/**
1818
* the attributes of this type
1919
*/
@@ -52,22 +52,12 @@ export class InterfaceType implements IIntermediateType {
5252
*/
5353
protected modes?: AuthorizationType[];
5454

55-
public constructor(name: string, props: IntermediateTypeProps) {
55+
public constructor(name: string, props: IntermediateTypeOptions) {
5656
this.name = name;
5757
this.definition = props.definition;
5858
this.directives = props.directives;
5959
}
6060

61-
/**
62-
* Method called when the stringifying Intermediate Types for schema generation
63-
*
64-
* @internal
65-
*/
66-
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
67-
this.modes = api.modes;
68-
return this;
69-
}
70-
7161
/**
7262
* Create a GraphQL Type representing this Intermediate Type
7363
*
@@ -111,6 +101,16 @@ export class InterfaceType implements IIntermediateType {
111101
}
112102
this.definition[options.fieldName] = options.field;
113103
}
104+
105+
/**
106+
* Method called when the stringifying Intermediate Types for schema generation
107+
*
108+
* @internal
109+
*/
110+
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
111+
this.modes = api.modes;
112+
return this;
113+
}
114114
}
115115

116116
/**
@@ -123,7 +123,7 @@ export class InterfaceType implements IIntermediateType {
123123
*
124124
* @experimental
125125
*/
126-
export interface ObjectTypeProps extends IntermediateTypeProps {
126+
export interface ObjectTypeOptions extends IntermediateTypeOptions {
127127
/**
128128
* The Interface Types this Object Type implements
129129
*
@@ -149,7 +149,7 @@ export class ObjectType extends InterfaceType implements IIntermediateType {
149149
*/
150150
public resolvers?: Resolver[];
151151

152-
public constructor(name: string, props: ObjectTypeProps) {
152+
public constructor(name: string, props: ObjectTypeOptions) {
153153
const options = {
154154
definition: props.interfaceTypes?.reduce((def, interfaceType) => {
155155
return Object.assign({}, def, interfaceType.definition);
@@ -234,7 +234,7 @@ export class InputType implements IIntermediateType {
234234
*/
235235
protected modes?: AuthorizationType[];
236236

237-
public constructor(name: string, props: IntermediateTypeProps) {
237+
public constructor(name: string, props: IntermediateTypeOptions) {
238238
this.name = name;
239239
this.definition = props.definition;
240240
}
@@ -253,16 +253,6 @@ export class InputType implements IIntermediateType {
253253
});
254254
}
255255

256-
/**
257-
* Method called when the stringifying Intermediate Types for schema generation
258-
*
259-
* @internal
260-
*/
261-
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
262-
this.modes = api.modes;
263-
return this;
264-
}
265-
266256
/**
267257
* Generate the string of this input type
268258
*/
@@ -289,13 +279,21 @@ export class InputType implements IIntermediateType {
289279
}
290280
this.definition[options.fieldName] = options.field;
291281
}
282+
283+
/**
284+
* Method called when the stringifying Intermediate Types for schema generation
285+
*
286+
* @internal
287+
*/
288+
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
289+
this.modes = api.modes;
290+
return this;
291+
}
292292
}
293293

294294
/**
295295
* Properties for configuring an Union Type
296296
*
297-
* @param definition - the object types for this union type
298-
*
299297
* @experimental
300298
*/
301299
export interface UnionTypeOptions {
@@ -348,16 +346,6 @@ export class UnionType implements IIntermediateType {
348346
});
349347
}
350348

351-
/**
352-
* Method called when the stringifying Intermediate Types for schema generation
353-
*
354-
* @internal
355-
*/
356-
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
357-
this.modes = api.modes;
358-
return this;
359-
}
360-
361349
/**
362350
* Generate the string of this Union type
363351
*/
@@ -387,4 +375,108 @@ export class UnionType implements IIntermediateType {
387375
}
388376
this.definition[options.field?.toString() + 'id'] = options.field;
389377
}
378+
379+
/**
380+
* Method called when the stringifying Intermediate Types for schema generation
381+
*
382+
* @internal
383+
*/
384+
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
385+
this.modes = api.modes;
386+
return this;
387+
}
388+
}
389+
390+
/**
391+
* Properties for configuring an Enum Type
392+
*
393+
* @experimental
394+
*/
395+
export interface EnumTypeOptions {
396+
/**
397+
* the attributes of this type
398+
*/
399+
readonly definition: string[];
400+
}
401+
402+
/**
403+
* Enum Types are abstract types that includes a set of fields
404+
* that represent the strings this type can create.
405+
*
406+
* @experimental
407+
*/
408+
export class EnumType implements IIntermediateType {
409+
/**
410+
* the name of this type
411+
*/
412+
public readonly name: string;
413+
/**
414+
* the attributes of this type
415+
*/
416+
public readonly definition: { [key: string]: IField };
417+
/**
418+
* the authorization modes for this intermediate type
419+
*/
420+
protected modes?: AuthorizationType[];
421+
422+
public constructor(name: string, options: EnumTypeOptions) {
423+
this.name = name;
424+
this.definition = {};
425+
options.definition.map((fieldName: string) => this.addField({ fieldName }));
426+
}
427+
428+
/**
429+
* Create an GraphQL Type representing this Enum Type
430+
*/
431+
public attribute(options?: BaseTypeOptions): GraphqlType {
432+
return GraphqlType.intermediate({
433+
isList: options?.isList,
434+
isRequired: options?.isRequired,
435+
isRequiredList: options?.isRequiredList,
436+
intermediateType: this,
437+
});
438+
}
439+
440+
/**
441+
* Generate the string of this enum type
442+
*/
443+
public toString(): string {
444+
return shapeAddition({
445+
prefix: 'enum',
446+
name: this.name,
447+
fields: Object.keys(this.definition),
448+
modes: this.modes,
449+
});
450+
}
451+
452+
/**
453+
* Add a field to this Enum Type
454+
*
455+
* To add a field to this Enum Type, you must only configure
456+
* addField with the fieldName options.
457+
*
458+
* @param options the options to add a field
459+
*/
460+
public addField(options: AddFieldOptions): void {
461+
if (options.field) {
462+
throw new Error('Enum Type fields consist of strings. Use the fieldName option instead of the field option.');
463+
}
464+
if (!options.fieldName) {
465+
throw new Error('When adding a field to an Enum Type, you must configure the fieldName option.');
466+
}
467+
if (options.fieldName.indexOf(' ') > -1) {
468+
throw new Error(`Enum Type values cannot have whitespace. Received: ${options.fieldName}`);
469+
}
470+
this.definition[options.fieldName] = GraphqlType.string();
471+
}
472+
473+
/**
474+
* Method called when the stringifying Intermediate Types for schema generation
475+
*
476+
* @internal
477+
*/
478+
public _bindToGraphqlApi(api: GraphqlApi): IIntermediateType {
479+
this.modes = api.modes;
480+
return this;
481+
}
390482
}

0 commit comments

Comments
 (0)