Example #1
0
    def _build_api(self, *, stack):

        self.api = appsync.GraphqlApi(stack, 'exampleapi',
                                name="examplegraphqlapi",
                                log_config=appsync.LogConfig(field_log_level=appsync.FieldLogLevel.ALL),
                                schema=appsync.Schema.from_asset(file_path="../appsync-conf/schema.graphql")
                                )

        self.api_key = appsync.CfnApiKey(stack, 'examplegraphqlapi',
                                    api_id=self.api.api_id
                                    )
Example #2
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Create a new AppSync GraphQL API
        api = appsync.GraphQLApi(
            self,
            'Api',
            name="demoapi",
            log_config=appsync.LogConfig(
                field_log_level=appsync.FieldLogLevel.ALL),
            schema_definition_file="schema/schema.graphql")

        api_key = appsync.CfnApiKey(self,
                                    'the-simple-graphql-service-api-key',
                                    api_id=api.api_id)

        # Create new DynamoDB Table for Customer
        customer_table = dynamo_db.Table(
            self,
            "CustomerTable",
            partition_key=dynamo_db.Attribute(
                name="id", type=dynamo_db.AttributeType.STRING))

        # Add Customer DynamoDB as a Datasource for the Graphql API.
        customer_ds = api.add_dynamo_db_data_source(
            'Customer', 'The customer data source', customer_table)

        # Query Resolver to get all Customers
        customer_ds.create_resolver(
            type_name='Query',
            field_name='getCustomers',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_scan_table(),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_list(),
        )

        # Query Resolver to get an individual Customer by their id
        customer_ds.create_resolver(
            type_name='Query',
            field_name='getCustomer',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_get_item('id', 'id'),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_item(),
        )

        # Mutation Resolver for adding a new Customer
        customer_ds.create_resolver(
            type_name='Mutation',
            field_name='addCustomer',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_put_item(key=appsync.PrimaryKey.partition('id').auto(),
                               values=appsync.Values.projecting('customer')),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_item())

        # Mutation Resolver for updating an existing Customer
        customer_ds.create_resolver(
            type_name='Mutation',
            field_name='saveCustomer',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_put_item(
                key=appsync.PrimaryKey.partition('id').is_('id'),
                values=appsync.Values.projecting('customer')),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_item())

        #  Mutation resolver for creating a new customer along with their first order
        customer_ds.create_resolver(
            type_name='Mutation',
            field_name='saveCustomerWithFirstOrder',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_put_item(
                key=appsync.PrimaryKey.partition('order').auto().sort(
                    'customer').is_('customer.id'),
                values=appsync.Values.projecting('order').attribute(
                    'referral').is_('referral')),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_item())

        # Mutation Resolver for deleting an existing Customer
        customer_ds.create_resolver(
            type_name='Mutation',
            field_name='removeCustomer',
            request_mapping_template=appsync.MappingTemplate.
            dynamo_db_delete_item('id', 'id'),
            response_mapping_template=appsync.MappingTemplate.
            dynamo_db_result_item(),
        )

        # defines an AWS  Lambda resource
        loyalty_lambda = _lambda.Function(
            self,
            "LoyaltyLambdaHandler",
            runtime=_lambda.Runtime.NODEJS_12_X,
            handler="loyalty.handler",
            code=_lambda.Code.from_asset("lambda_fns"),
        )

        # Add Loyalty Lambda as a Datasource for the Graphql API.
        loyalty_ds = api.add_lambda_data_source('Loyalty',
                                                'The loyalty data source',
                                                loyalty_lambda)

        # Query Resolver to get all Customers
        loyalty_ds.create_resolver(
            type_name='Query',
            field_name='getLoyaltyLevel',
            request_mapping_template=appsync.MappingTemplate.lambda_request(),
            response_mapping_template=appsync.MappingTemplate.lambda_result(),
        )

        # GraphQL API Endpoint
        core.CfnOutput(self, 'Endpoint', value=api.graph_ql_url)

        # API Key
        core.CfnOutput(self, 'API_Key', value=api_key.attr_api_key)
Example #3
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # store
        dynamodb_table = dynamodb.Table(
            self,
            'dynamodb_table',
            table_name=f'{PROJECT}_{STAGE}',
            partition_key=dynamodb.Attribute(
                name='date', type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            point_in_time_recovery=False,
            removal_policy=core.RemovalPolicy.DESTROY,
            server_side_encryption=True,
        )

        # public api
        public_api = appsync.CfnGraphQLApi(
            self,
            'public_api',
            name=f'{PROJECT}_{STAGE}',
            authentication_type='API_KEY',
        )

        now = time.localtime()
        epoch = time.mktime(now)
        public_api_key = appsync.CfnApiKey(
            self,
            'public_api_key',
            api_id=public_api.attr_api_id,
            expires=epoch + core.Duration.days(90).to_seconds(),
        )

        with open('schema.gql', mode='r') as f:
            graphql_schema = f.read()

            appsync.CfnGraphQLSchema(self,
                                     'public_api_schema',
                                     api_id=public_api.attr_api_id,
                                     definition=graphql_schema)

        public_api_role = iam.Role(
            self,
            'public_api_role',
            assumed_by=iam.ServicePrincipal('appsync.amazonaws.com'),
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    'AmazonDynamoDBFullAccess')
            ],
        )

        public_api_datasource = appsync.CfnDataSource(
            self,
            'public_api_datasource',
            api_id=public_api.attr_api_id,
            name=f'{PROJECT}_{STAGE}_dynamodb',
            type='AMAZON_DYNAMODB',
            dynamo_db_config={
                'awsRegion': 'us-east-1',
                'tableName': dynamodb_table.table_name,
            },
            service_role_arn=public_api_role.role_arn,
        )

        with open('mapping_templates/get_holiday.json', mode='r') as f:
            get_holiday_json = f.read()

            appsync.CfnResolver(
                self,
                'public_api_resolver_get_holiday',
                api_id=public_api.attr_api_id,
                type_name='Query',
                field_name='getHoliday',
                data_source_name=public_api_datasource.attr_name,
                kind='UNIT',
                request_mapping_template=get_holiday_json,
                response_mapping_template='$util.toJson($context.result)',
            )

        with open('mapping_templates/list_holidays.json', mode='r') as f:
            list_holidays_json = f.read()

            appsync.CfnResolver(
                self,
                'public_api_resolver_list_holidays',
                api_id=public_api.attr_api_id,
                type_name='Query',
                field_name='listHolidays',
                data_source_name=public_api_datasource.attr_name,
                kind='UNIT',
                request_mapping_template=list_holidays_json,
                response_mapping_template='$util.toJson($context.result)',
            )

        # lambda source code upload to s3
        lambda_assets = s3_assets.Asset(self,
                                        'lambda_assets',
                                        path='./function/.artifact/')

        # update function
        func_api = lambda_.Function(
            self,
            f'{PROJECT}-{STAGE}-func',
            function_name=f'{PROJECT}-{STAGE}-func',
            code=lambda_.Code.from_bucket(bucket=lambda_assets.bucket,
                                          key=lambda_assets.s3_object_key),
            handler='app.handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
            timeout=core.Duration.seconds(120),
            log_retention=logs.RetentionDays.SIX_MONTHS,
            memory_size=128,
            tracing=lambda_.Tracing.ACTIVE,
        )
        func_api.add_environment('TABLE_NAME', dynamodb_table.table_name)
        func_api.add_environment('CSV_URL', CSV_URL)
        func_api.add_to_role_policy(
            iam.PolicyStatement(
                actions=[
                    'dynamodb:Get*',
                    'dynamodb:Put*',
                    'dynamodb:Batch*',
                ],
                resources=[dynamodb_table.table_arn],
            ))

        # schedule execute
        events.Rule(
            self,
            f'{PROJECT}-{STAGE}-schedule',
            enabled=True,
            schedule=events.Schedule.rate(core.Duration.days(10)),
            targets=[events_targets.LambdaFunction(func_api)],
        )

        # lambda@edge
        func_lambdaedge = lambda_.Function(
            self,
            f'{PROJECT}-{STAGE}-func-lambdaedge',
            function_name=f'{PROJECT}-{STAGE}-func-lambdaedge',
            code=lambda_.Code.from_inline(
                open('./function/src/lambdaedge.py').read().replace(
                    '__X_API_KEY__', public_api_key.attr_api_key)),
            handler='index.handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
            timeout=core.Duration.seconds(30),
            memory_size=128,
            role=iam.Role(
                self,
                f'{PROJECT}-{STAGE}-func-lambdaedge-role',
                assumed_by=iam.CompositePrincipal(
                    iam.ServicePrincipal('edgelambda.amazonaws.com'),
                    iam.ServicePrincipal('lambda.amazonaws.com'),
                ),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name(
                        'service-role/AWSLambdaBasicExecutionRole'),
                ],
            ),
        )
        lambdaedge_version = func_lambdaedge.add_version(
            hashlib.sha256(
                open('./function/src/lambdaedge.py').read().replace(
                    '__X_API_KEY__',
                    public_api_key.attr_api_key).encode()).hexdigest())

        # ACM
        certificates = acm.Certificate(
            self,
            'certificates',
            domain_name=DOMAIN,
            validation_method=acm.ValidationMethod.DNS,
        )

        # CDN
        cdn = cloudfront.CloudFrontWebDistribution(
            self,
            f'{PROJECT}-{STAGE}-cloudfront',
            origin_configs=[
                cloudfront.SourceConfiguration(
                    behaviors=[
                        # default behavior
                        cloudfront.Behavior(
                            allowed_methods=cloudfront.
                            CloudFrontAllowedMethods.ALL,
                            default_ttl=core.Duration.seconds(0),
                            max_ttl=core.Duration.seconds(0),
                            min_ttl=core.Duration.seconds(0),
                            is_default_behavior=True,
                            lambda_function_associations=[
                                cloudfront.LambdaFunctionAssociation(
                                    event_type=cloudfront.LambdaEdgeEventType.
                                    ORIGIN_REQUEST,
                                    lambda_function=lambdaedge_version,
                                ),
                            ])
                    ],
                    custom_origin_source=cloudfront.CustomOriginConfig(
                        domain_name=core.Fn.select(
                            2, core.Fn.split('/',
                                             public_api.attr_graph_ql_url)), ),
                )
            ],
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=certificates.certificate_arn,
                names=[DOMAIN],
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_2_2018,
            ),
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
        )
        core.CfnOutput(
            self,
            'cloudfront-domain',
            value=cdn.domain_name,
        )
    def __init__(self, scope: core.Construct, id: str, vpc_id: str, subnet_ids, rds_secret_arn: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        vpc = ec2.Vpc.from_vpc_attributes(self, vpc_id, vpc_id=vpc_id, 
        availability_zones= [ 'eu-west-1c'],
        public_subnet_ids= subnet_ids)

        # creating vote table for dynamodb resolver
        vote_table = ddb.Table(self, 'votes', 
            table_name='votes', 
            partition_key={
                "name": "productid",
                "type": ddb.AttributeType.STRING
            }, 
            # Sortkey structure is like : UP#20200902T12:34:00 - DOWN#20201030T10:45:12
            sort_key={
                "name": "votesortkey",
                "type": ddb.AttributeType.STRING
            },
            read_capacity=5, 
            write_capacity=5
        )

        # creating API with GraphQL schema
        api = appsync.GraphqlApi(self, 'example_appsync_api',
                                name="example_appsync_api",
                                log_config=appsync.LogConfig(field_log_level=appsync.FieldLogLevel.ALL),
                                schema=appsync.Schema.from_asset(file_path="../appsync-conf/schema.graphql")
                                )

        # Authentication done with API key - for development purposes only
        appsync.CfnApiKey(self, 'examplegraphqlapi',
                                    api_id=api.api_id
                                    )

        # create security group for lambda
        # this will need to be added to your RDS inbound
        lambda_security_group = ec2.SecurityGroup(self, "Example-AppSyncResolverLambdaSG", 
            security_group_name="Example-AppSyncResolverLambdaSG",
            vpc=vpc,
            allow_all_outbound=True
        )

        # getting the code from local directory
        lambda_rds_code = aws_lambda.Code.asset("../lambda-rds")

        lambda_rds_resolver = aws_lambda.Function(self,
            "LambdaAppSyncSQLResolver",
            function_name=f"LambdaAppSyncSQLResolver",
            code=lambda_rds_code,
            handler="index.handler",
            runtime=aws_lambda.Runtime.NODEJS_12_X,
            memory_size=512,
            timeout=core.Duration.seconds(60),
            log_retention=logs.RetentionDays.ONE_MONTH,
            vpc=vpc,
            vpc_subnets={
                "subnet_type": ec2.SubnetType.PUBLIC
            },
            allow_public_subnet=True,
            security_group=lambda_security_group,
        )

        # env parameters for rds lambda to perform SQL calls
        lambda_rds_resolver.add_environment("SECRET_ARN", rds_secret_arn)

        # allow lambda to read secret
        lambda_rds_resolver.add_to_role_policy(iam.PolicyStatement(
            effect=iam.Effect.ALLOW,
            actions=[ 'secretsmanager:GetSecretValue' ],
            resources=[ rds_secret_arn ]
        ))

        # adding the product datasource as lamda resolver
        products_ds = api.add_lambda_data_source('Products', lambda_rds_resolver)

        # creates resolver for query getProduct
        products_ds.create_resolver(
            type_name='Query',
            field_name='getProduct',
            request_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/getProduct.vtl"),
            response_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/getProduct_output_template.vtl"),
        )

        # adding lamda resolver for vote fields in product model
        lambda_dynamodb_code = aws_lambda.Code.asset("../lambda-dynamodb")

        lambda_dynamodb_votes_resolver = aws_lambda.Function(self,
            "LambdaAppSyncVotesResolver",
            function_name=f"LambdaAppSyncVotesResolver",
            code=lambda_dynamodb_code,
            handler="index.handler",
            runtime=aws_lambda.Runtime.NODEJS_12_X,
            memory_size=512,
            timeout=core.Duration.seconds(60),
        )

        # allow lambda to query dynamodb
        lambda_dynamodb_votes_resolver.add_to_role_policy(iam.PolicyStatement(
            effect=iam.Effect.ALLOW,
            actions=[ 
                "dynamodb:GetItem",
                "dynamodb:Query", 
            ],
            resources=[ 
                vote_table.table_arn,
                vote_table.table_arn + "/*"
            ]
        ));           

        # create lambda datasource for dynamodb queries
        votes_ds = api.add_lambda_data_source('Votes', lambda_dynamodb_votes_resolver)

        votes_ds.create_resolver(
            type_name='Product',
            field_name='ups',
            request_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/fields/votes_up.vtl"),
            response_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/fields/votes_up_output_template.vtl"),
        )

        votes_ds.create_resolver(
            type_name='Product',
            field_name='downs',
            request_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/fields/votes_down.vtl"),
            response_mapping_template=appsync.MappingTemplate.from_file("../appsync-conf/vtl/fields/votes_down_output_template.vtl"),
        )