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

[aws-appsync] code-first generation of object types for schema #9307

Closed
BryanPan342 opened this issue Jul 28, 2020 · 2 comments · Fixed by #9417
Closed

[aws-appsync] code-first generation of object types for schema #9307

BryanPan342 opened this issue Jul 28, 2020 · 2 comments · Fixed by #9417
Assignees
Labels
@aws-cdk/aws-appsync Related to AWS AppSync effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. in-progress This issue is being actively worked on. p2

Comments

@BryanPan342
Copy link
Contributor

BryanPan342 commented Jul 28, 2020

Allow custom object type definition for schema.

Use Case

Would allow for object type definition for schema generated using a code-first approach.

Proposed Solution

const api = new GraphQLApi(stack, 'ExampleApi', {
  name: 'example',
  schemaDefinition: SCHEMA.CODE,
  ...
});

// Defining attribute types (i.e. Int! and String!)
const t_int_r = AttributeType.int().required();
const t_string_r = AttributeType.string().required();

// Defining Object Type ( i.e. type Example @aws_iam { id: Int! content: String! } )
const example = api.addType('Example', {
  definition: {
    id: t_int_r,
    content: t_string_r, 
  },
  directives: Directives.iam(),
});

api.addType would return ObjectType so that other types can reference it.

Other

Tracked by: #9305


This is a 🚀 Feature Request

@BryanPan342 BryanPan342 added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Jul 28, 2020
@BryanPan342 BryanPan342 self-assigned this Jul 28, 2020
@github-actions github-actions bot added the @aws-cdk/aws-appsync Related to AWS AppSync label Jul 28, 2020
@BryanPan342 BryanPan342 added effort/medium Medium work item – several days of effort p2 @aws-cdk/aws-appsync Related to AWS AppSync and removed @aws-cdk/aws-appsync Related to AWS AppSync needs-triage This issue or PR still needs to be triaged. labels Jul 28, 2020
@BryanPan342 BryanPan342 added the in-progress This issue is being actively worked on. label Aug 1, 2020
@BryanPan342
Copy link
Contributor Author

BryanPan342 commented Aug 5, 2020

EDIT: Decided to move to a different approach for object types

The previous approach to design was extremely cumbersome. Some of the tenets I was envisioning was to produce a similar feel to graphql but in a much more cohesive a modular manner. The old approach was terrible in terms of scaling because as projects got bigger, the Attribute Types become very annoying to continually type out.

I believe this should be sufficient as to show why the old implementation is really cumbersome.

Example of Old Implementation and why it's cumbersome
const t_id = appsync.AttributeType.id('id').required();

// Planet Props
const t_name = appsync.AttributeType.string('name');
const t_diameter = appsync.AttributeType.int('diameter');
const t_rotationPeriod = appsync.AttributeType.int('rotationPeriod');
const t_orbitalPeriod = appsync.AttributeType.int('orbitalPeriod');
const t_gravity = appsync.AttributeType.string('gravity');
const t_population = appsync.AttributeType.float('population');
const t_climates= appsync.AttributeType.string('climates').list();
const t_terrains = appsync.AttributeType.string('terrains').list();
const t_surfaceWater = appsync.AttributeType.float('surfaceWater');
const t_created = appsync.AttributeType.string('created');
const t_edited = appsync.AttributeType.string('edited');

// Species Props
const t_classification = appsync.AttributeType.string('classification');
const t_designation = appsync.AttributeType.string('designation');
const t_averageHeight = appsync.AttributeType.float('averageHeight');
const t_averageLifespan = appsync.AttributeType.int('averageLifespan');
const t_eyeColors = appsync.AttributeType.string('eyeColors').list();
const t_hairColors = appsync.AttributeType.string('hairColors').list();
const t_skinColors = appsync.AttributeType.string('skinColors').list();
const t_language = appsync.AttributeType.string('language');

const t_planet = api.addType('Planet', {
  definition: [
    t_name,
    t_diameter,
    t_rotationPeriod,
    t_orbitalPeriod,
    t_gravity,
    t_population,
    t_climates,
    t_terrains,
    t_surfaceWater,
    t_created,
    t_edited,
    t_id,
  ],
});

api.addType('Species', {
  definition: [
    t_name,
    t_classification,
    t_designation,
    t_averageHeight,
    t_averageLifespan,
    t_eyeColors,
    t_hairColors,
    t_skinColors,
    t_language,
    appsync.AttributeType.object('homeworld', t_planet),
    t_created,
    t_edited,
    t_id,
  ],
});

The new approach is detailed in this comment.


Some of the main tenets I was envisioning was modularity, consistency, and reusability.

A schema-first approach, while very customizable, requires a lot of boilerplate code. Something I want to tackle is simplifying that process to a more reusable, modular approach.

Deprecated Implementation

Given

import { GraphQLAPi, ScalarType, Directives } as '@aws-cdk/aws-appsync';

const api = new GraphQLApi(stack, 'ExampleApi', {
  name: 'example',
  schemaDefinition: SCHEMA.CODE,
  ...
}

Creating Object Types

You can create object types by using the addType function.

const example = api.addType('Example', {
  definition: [
    ScalarType.string('id').required(),
    ScalarType.string('content').required(), 
    ScalarType.string('version').required(),
    ScalarType.string('author'),
  ],
  directives: Directives.iam(),
});

Would create the following graphql statement

type Example @aws_iam {
  id: String!
  content: String!
  version: String!
  author: String
}

Modularity

The following implementation is very modular and allows for single changes to affect the entire schema. Instead of declaring the ScalarType in the addType definition, we can declare them as constants. This would produce the same output as before.

const type_id = ScalarType.string('id').required();
const type_content = ScalarType.string('content').required();
const type_version = ScalarType.string('version').required();
const type_author = ScalarType.string('author');

const example = api.addType('Example', {
  definition: [
    type_id,
    type_content, 
    type_version,
    type_author,
  ],
 directives: Directives.iam(),
});

This would allow for more modular design in the form of switching out types easily. For example if we want to make a new Author type, we can use something as follows:

const type_id = ScalarType.string('id').required();
const type_name = ScalarType.string('name').required();

const author = api.addType('Author', {
 definition: [
   type_id,
   type_name,
 ]
});

const type_content = ScalarType.string('content').required();
const type_version = ScalarType.string('version').required();
const type_author = author.attribute('author').required();

const example = api.addType('Example', {
 definition: {
   type_id,
   type_content, 
   type_version,
   type_author,
 },
directives: Directives.iam(),
});

which would produce the following graphql snippet

type Author {
  id: String!
  name: String!
}

type Example @aws_iam {
  id: String!
  content: String!
  version: String!
  author: Author!
}

@BryanPan342
Copy link
Contributor Author

BryanPan342 commented Aug 6, 2020

Some of the main tenets I was envisioning was modularity, consistency, and reusability.

A schema-first approach, while very customizable, requires a lot of boilerplate code. Something I want to tackle is simplifying that process to a more reusable, modular approach.

Given
import { GraphQLAPi, ScalarType, Directives } as '@aws-cdk/aws-appsync';

const api = new GraphQLApi(stack, 'ExampleApi', {
  name: 'example',
  schemaDefinition: SCHEMA.CODE,
  ...
}
Creating Object Types

You can create object types by using the addType function.

const example = api.addType('Example', {
  definition: {
    id: AttributeType.string().required(),
    content: AttributeType.string().required(), 
    version: AttributeType.string().required(),
    author: AttributeType.string(),
  },
  directives: Directives.iam(),
});

Would create the following graphql statement

type Example @aws_iam {
  id: String!
  content: String!
  version: String!
  author: String
}
Modularity

The following implementation is very modular and allows for single changes to affect the entire schema. Instead of declaring the AttributeType in the addType definition, we can declare them as constants. This would produce the same output as before.

const t_string_r = AttributeType.string().required();
const t_string = AttributeType.string();

const example = api.addType('Example', {
  definition: {
    id: t_string_r,
    content: t_string_r, 
    version: t_string_r,
    author: t_string,
  },
  directives: Directives.iam(),
});

This would allow for more modular design in the form of switching out types easily. For example if we want to make a new Author type, we can use something as follows:

const t_string_r = AttributeType.string().required();
const t_string = AttributeType.string();

const author = api.addType('Author', {
 definition: {
   id: t_string_r,
   name: t_string_r,
 }
});

const t_author = AttributeType.object(author);

const example = api.addType('Example', {
 definition: {
   id: t_string_r,
   content: t_string_r, 
   version: t_string_r,
   author: t_author,
 },
 directives: Directives.iam(),
});

which would produce the following graphql snippet

type Author {
  id: String!
  name: String!
}

type Example @aws_iam {
  id: String!
  content: String!
  version: String!
  author: Author
}

@mergify mergify bot closed this as completed in #9417 Aug 15, 2020
mergify bot pushed a commit that referenced this issue Aug 15, 2020
…9417)

AppSync now able to generate a code-first approach to generating object and interface types through code. You can also append to schema through the `GraphQLApi.appendToSchema` function. 

Feature List:
- GraphqlTypes
- InterfaceTypes
- ObjectTypes
- Directives

All details can be found in the README.md

Fixes #9307 

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-appsync Related to AWS AppSync effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. in-progress This issue is being actively worked on. p2
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants