diff --git a/appsync-stepfunctions-express-sam/README.md b/appsync-stepfunctions-express-sam/README.md new file mode 100644 index 000000000..4ea890ec5 --- /dev/null +++ b/appsync-stepfunctions-express-sam/README.md @@ -0,0 +1,55 @@ +# AWS AppSync to AWS Step Functions (sync express workflow) + +This project contains a sample AWS SAM template for running synchronous express workflows for Step Functions from an AppSync API. The State Machine will be added as an HTTP data source to AppSync API. + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ``` + cd appsync-stepfunctions-express-sam + ``` +3. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file: + ``` + sam deploy --guided + ``` +4. During the prompts: + * Enter a stack name + * Enter the desired AWS Region + * Allow SAM CLI to create IAM roles with the required permissions. + + Once you have run `sam deploy --guided` mode once and saved arguments to a configuration file (samconfig.toml), you can use `sam deploy` in future to use these defaults. + +5. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing. + +## How it works + +This project creates an AppSync API. From your AppSync API, you are able to run a mutation called `startWorkflow` to start your step function express workflow execution syncronously. + +## Testing + +You can test your AppSync API and Step Functions express workflow integration by running a query from AWS AppSync console. +![mutation](images/mutation.png) + +## Cleanup + +1. Delete the stack, Enter `Y` to confirm deleting the stack and folder. + ``` + sam delete + ``` +---- +Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 \ No newline at end of file diff --git a/appsync-stepfunctions-express-sam/example-pattern.json b/appsync-stepfunctions-express-sam/example-pattern.json new file mode 100644 index 000000000..c2de61eda --- /dev/null +++ b/appsync-stepfunctions-express-sam/example-pattern.json @@ -0,0 +1,62 @@ +{ + "title": "AWS AppSync to AWS Step Functions (sync express workflow)", + "description": "Create AppSync API to trigger a syncrounuous SFN execution", + "language": "YAML", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This project contains a sample AWS SAM template for running synchronous express workflows for Step Functions from an AppSync API.", + "The State Machine will be added as an HTTP data source to AppSync API." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/appsync-stepfunctions-express-sam", + "templateURL": "serverless-patterns/appsync-stepfunctions-express-sam", + "projectFolder": "appsync-stepfunctions-express-sam", + "templateFile": "appsync-stepfunctions-express-sam/template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Invoke AWS services directly from AWS AppSync", + "link": "https://aws.amazon.com/blogs/mobile/invoke-aws-services-directly-from-aws-appsync/" + }, + { + "text": "AWS Appsync", + "link": "https://aws.amazon.com/appsync/" + }, + { + "text": "AWS Step Functions", + "link": "https://aws.amazon.com/step-functions/" + } + ] + }, + "deploy": { + "text": [ + "sam deploy" + ] + }, + "testing": { + "text": [ + "See the Github repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: sam delete." + ] + }, + "authors": [ + { + "name": "Alexis Philippart de Foy", + "image": "https://media.licdn.com/dms/image/C4D03AQFyN5GLrFk-0g/profile-displayphoto-shrink_800_800/0/1586853008031?e=1693440000&v=beta&t=0BtjX92oZxhHUrrIzh55wah8V1OiwOAOyigPtfAcZdo", + "bio": " I am a Startup Solutions Architect, Serverless enthusiast and former Startup Founder.", + "linkedin": "apdf", + "twitter": "@aphilippartd" + } + ] +} diff --git a/appsync-stepfunctions-express-sam/images/mutation.png b/appsync-stepfunctions-express-sam/images/mutation.png new file mode 100644 index 000000000..6803b241e Binary files /dev/null and b/appsync-stepfunctions-express-sam/images/mutation.png differ diff --git a/appsync-stepfunctions-express-sam/schema.graphql b/appsync-stepfunctions-express-sam/schema.graphql new file mode 100644 index 000000000..cd53078dc --- /dev/null +++ b/appsync-stepfunctions-express-sam/schema.graphql @@ -0,0 +1,19 @@ +type Execution { + name: String + status: String + input: String + executionArn: String + startDate: String + stopDate: String + output: String +} + +type Mutation { + startWorkflow ( + name: String! + ): Execution +} + +# Any Query you need for your application +type QueryOutput { output: String! } +type Query { myQuery(input: String!): QueryOutput } diff --git a/appsync-stepfunctions-express-sam/template.yaml b/appsync-stepfunctions-express-sam/template.yaml new file mode 100644 index 000000000..137ac6283 --- /dev/null +++ b/appsync-stepfunctions-express-sam/template.yaml @@ -0,0 +1,126 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: AppSync to Step Functions Express (Sync) + +Resources: +########################################################################## +# AppSync API # +########################################################################## + AppSyncApi: + Type: AWS::Serverless::GraphQLApi + Properties: + SchemaUri: ./schema.graphql + ApiKeys: + TestApiKey: + Description: Test Api Key + Auth: + Type: API_KEY + Functions: + addWorkflowArnToStashFunction: + Runtime: + Name: APPSYNC_JS + Version: 1.0.0 + DataSource: None + InlineCode: !Sub | + export function request(ctx) { + ctx.stash.stateMachineArn = "${StateMachine}" + return {}; + } + export function response(ctx) { + return ctx.args; + } + startWorkflowFunction: + Runtime: + Name: APPSYNC_JS + Version: 1.0.0 + DataSource: !GetAtt StepFunctionDataSource.Name + InlineCode: | + import { util } from '@aws-appsync/utils' + export function request(ctx) { + return { + "version": "2018-05-29", + "method": "POST", + "resourcePath": "/", + "params": { + "headers": { + "content-type": "application/x-amz-json-1.0", + "x-amz-target":"AWSStepFunctions.StartSyncExecution" + }, + "body": { + "stateMachineArn": ctx.stash.stateMachineArn, + "input": JSON.stringify(ctx.args) + } + } + }; + } + export function response(ctx) { + if (ctx.error) util.error(ctx.error.message, ctx.error.type); + if (ctx.result.statusCode === 200) { + return JSON.parse(ctx.result.body); + } else { + util.appendError(ctx.result.body, ctx.result.statusCode); + } + } + Resolvers: + Mutation: + startWorkflow: + Runtime: + Name: APPSYNC_JS + Version: "1.0.0" + Pipeline: + - addWorkflowArnToStashFunction + - startWorkflowFunction + +########################################################################## +# AppSync Data Sources # +########################################################################## + StepFunctionDataSource: + Type: AWS::AppSync::DataSource + Properties: + ApiId: !GetAtt AppSyncApi.ApiId + Name: StepFunctionDataSource + Type: HTTP + ServiceRoleArn: !GetAtt StepFunctionDataSourceRole.Arn + HttpConfig: + Endpoint: !Sub "https://sync-states.${AWS::Region}.amazonaws.com/" + AuthorizationConfig: + AuthorizationType: AWS_IAM + AwsIamConfig: + SigningRegion: !Ref AWS::Region + SigningServiceName: states + + StepFunctionDataSourceRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: appsync.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: WorkflowPolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: states:StartSyncExecution + Resource: !Ref StateMachine + +########################################################################## +# SFN State Machine # +########################################################################## + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Type: EXPRESS + Definition: + Comment: StateMachine + StartAt: Pass + States: + Pass: + Type: Pass + End: true + Parameters: + message.$: States.Format('Hey {}, this is a message from your state machine',$.name) \ No newline at end of file