{"id":23429998,"url":"https://github.com/mikeparcewski/aws-openapi","last_synced_at":"2025-04-12T21:36:22.595Z","repository":{"id":52412558,"uuid":"173618965","full_name":"mikeparcewski/aws-openapi","owner":"mikeparcewski","description":"A massively scalable CRUD application built using AWS (CloudFormation) \u0026 OpenAPI 3.0 that focuses on configuration over code.","archived":false,"fork":false,"pushed_at":"2021-04-29T21:52:13.000Z","size":449,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T15:48:08.584Z","etag":null,"topics":["aws","aws-apigateway","aws-cloudformation","aws-dynamodb","aws-lambda","aws-sns","bdd","howto","openapi-generator","openapi3"],"latest_commit_sha":null,"homepage":null,"language":"Gherkin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikeparcewski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-03T19:17:31.000Z","updated_at":"2025-01-29T16:18:50.000Z","dependencies_parsed_at":"2022-09-08T18:31:25.911Z","dependency_job_id":null,"html_url":"https://github.com/mikeparcewski/aws-openapi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2Faws-openapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2Faws-openapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2Faws-openapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2Faws-openapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikeparcewski","download_url":"https://codeload.github.com/mikeparcewski/aws-openapi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248637417,"owners_count":21137533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-apigateway","aws-cloudformation","aws-dynamodb","aws-lambda","aws-sns","bdd","howto","openapi-generator","openapi3"],"created_at":"2024-12-23T08:14:03.677Z","updated_at":"2025-04-12T21:36:22.550Z","avatar_url":"https://github.com/mikeparcewski.png","language":"Gherkin","readme":"# AWS + OpenAPI\n\nA fast, massively scalable sample CRUD application with simple eventing that harnesses the power of AWS and OpenAPI.\n\n### Table of Contents\n\n* [What This Is](#what-this-is)\n* [What You'll Need](#what-youll-need)\n* [Setting It Up](#setting-it-up)\n* [Making Sure It Works](#making-sure-it-works)\n* [How It Works](#how-it-works)\n  * [How to Customize](#srcmainresourcesopenapiyaml)\n* [The Test Harness](#the-test-harness)\n* [Taking It Further](#taking-it-further)\n* [Cleaning Up](#cleaning-up)\n\n### What This Is\n\nLeveraging AWS, OpenAPI and BDD testing methodologies this a fast, massively scalable API created entirely through configuration, leveraging each of the technologies to simplify development and deployment.\n\n* Amazon Web Services\n  * [API Gateway](https://aws.amazon.com/api-gateway/) - To manage resource requests to AWS Lambda or DynamoDB\n  * [AWS Lambda](https://aws.amazon.com/lambda) - To handle transformation of data\n  * [DynamoDB](https://aws.amazon.com/dynamodb/) - A multi-master (e.g. read/write), regionally scalable\n  * [AWS SNS](https://aws.amazon.com/sns/) - Alerting you in real time to changes in data\n* [OpenAPI 3.x](https://www.openapis.org/) with AWS extensions (for deployment)\n* [BDD For All](https://github.com/accenture/bdd-for-all) - A behavorial driven development grammar/test harness from Accenture\n\n![AWS Diagram of Solution](content/diagram.png)\n\n\u003e Add Route 53 to route traffic based on best consumer region - https://medium.com/fintech-studios-engineering/automatic-multi-region-api-failover-and-geo-proximity-routing-on-aws-271f57752c1b\n\n## What You'll Need\n\nTo run this application and create other API's you'll need the following installed...\n\n* Modern IDE \u0026 Environment - Supports Maven, Java 8, NodeJS \u0026 Python\n* AWS CLI - https://aws.amazon.com/cli/\n* AWS CloudFormation Template Flip - https://github.com/awslabs/aws-cfn-template-flip\n\n## What You'll Be Doing\n\nCreating and testing a fast, and multi-region CRUD with no code using documentation and configuration.\n\n**Features**\n* CRUD API based on OpenAPI 3.x schema (either example one, or one you write)\n* Launches in two regions, but can scale to all easily\n* For reduced latency, all resources for an API exist within same region\n  * All in-region resources resources configured to scale as well\n* Backed by a global DynamoDB instance which makes each region instance multi-master read/write\n* Change notifications sent via real time VIA SMS\n* No code, other than reusable lambdas that could be used for any API.\n\n## Setting It Up\n\nFirst we need to generate the configuration.  In src/main/resources/ we have 3 YAML files...\n\n* **aws-resources.yaml** - this outlines most of the components of the cloud formation stack\n* **openapi.yaml** - this is the openapi spec for the service\n* **aws-extensions.yaml** - these are openapi extensions from AWS that describe the API Gateway deployment\n\nYou can learn more about these in the [How This all Works](#how-this-all-works) section.  For now, let's get started.\n\n* Go to the root of this projects directory\n* First we need to convert our YAML configurations to AWS JSON.  We'll us the cfn-flip library to do this.\n  ```sbtshell\n  cfn-flip -j src/main/resources/aws-resources.yaml src/main/resources/aws-resources.json\n  ```\n  And...\n  ```sbtshell\n  cfn-flip -j src/main/resources/api-extensions.yaml src/main/resources/api-extensions.json\n  ```\n  Finally...\n  ```sbtshell\n  cfn-flip -j src/main/resources/openapi.yaml src/main/resources/openapi.json\n  ```\n* Next, we'll generate the final cloudformation template from these...\n  ```sbtshell\n  mvn clean generate-test-resources\n  ```\n\nAnd now we can start launching the stack...\n\n```sbtshell\naws cloudformation create-stack \\\n  --stack-name ItemsExample \\\n  --template-body file:///$PWD/target/aws-config.json \\\n  --capabilities CAPABILITY_IAM \\\n  --region us-east-1\n```\n\nThis creates the database, lambdas, and api gateway configuration and publishes demo endpoints in the us-east-1 region.\n\n\u003e You should jump to the console at this point - https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filter=active - and make sure it completes without error.  You can also check via the command line using `aws cloudformation describe-stacks --stack-name ItemsExample --region us-east-1` where you should see `\"StackStatus\": \"CREATE_COMPLETE\"`\n\nNow, let's do the same for us-west-1...\n\n```sbtshell\naws cloudformation create-stack \\\n  --stack-name ItemsExample \\\n  --template-body file:///$PWD/target/aws-config.json \\\n  --capabilities CAPABILITY_IAM \\\n  --region us-west-1\n```\n\u003e Again jump to the console at this point - https://console.aws.amazon.com/cloudformation/home?region=us-west-1#/stacks?filter=active - and make sure it completes without error or check via the command line using the `aws cloudformation describe-stacks --stack-name ItemsExample --region us-west-1` command.\n\nOnce both stacks have been created, we want to make sure any database changes are synched between regions.  Since we can't specify global tables in the cloudformation template (as of Feb '19), we just need to issue the following command to bring the east/west databases together...\n\n```sbtshell\naws dynamodb create-global-table \\\n  --region us-east-1 \\\n  --replication-group RegionName=us-east-1 RegionName=us-west-1 \\\n  --global-table-name ItemsExampleTable\n```\n\nTo validate it worked, check out https://console.aws.amazon.com/dynamodb/home?region=us-east-1#tables:selected=ItemsExampleTable;tab=globaltables\n\nThere you should see lines for US East \u0026 West in the Global Table regions list.\n\n### Making Sure It Works\n\nIn addition to writing an OpenAPI spec, we also write acceptance tests (BDD).  Let's see if the application works by executing those tests...\n\n* First let's get the url's.  The easiest way... \n  ```sbtshell\n  { \\\n  aws cloudformation describe-stack-resources \\\n    --stack-name ItemsExample \\\n    --region us-east-1 \\\n    | grep -C 5 \"ApiGateway::RestApi\" \\\n    | grep PhysicalResourceId \\\n    | sed 's/^.*: //; s/\\\"//g; s/^/host - https:\\/\\//; s/,/\\.execute-api\\.us-east-1\\.amazonaws\\.com\\/demo/g' \\\n  ; \\\n  aws cloudformation describe-stack-resources \\\n    --stack-name ItemsExample \\\n    --region us-west-1 \\\n    | grep -C 5 \"ApiGateway::RestApi\" \\\n    | grep PhysicalResourceId \\\n    | sed 's/^.*: //; s/\\\"//g; s/^/alternative - https:\\/\\//; s/,/\\.execute-api\\.us-west-1\\.amazonaws\\.com\\/demo/g' \\\n  } \\\n  | cat\n  ```\n  \u003e Your output should look something like...\n  ```sbtshell\n  host - https://uoa9j84ufh.execute-api.us-east-1.amazonaws.com/demo/items\n  alternative - https://39gzfyhlv9.execute-api.us-west-1.amazonaws.com/demo/items\n  ```\n* Now open src/test/resources/application.conf and take \"host\" from the command above (just the URL part) and put it where it says USEAST1 below.  Then take the \"alternative\" output from above and replace the USWEST1 location as shown below.\n  ```scala\n  bddcore {\n  \n    request {\n  \n      server {\n        host = \"USEAST1\"\n      }\n  \n      userAgent = \"AWS-OPENAPI-SHOWCASE\"\n  \n    }\n  \n    vars {\n  \n      Alternative {\n  \n        Region = \"USWEST1\"\n  \n      }\n  \n    }\n  \n  }\n  ```\n* Now for the SMS notifications, we'll add our phone.  First, we need to know the ARN...\n  ```sbtshell\n  aws cloudformation describe-stack-resources \\\n    --stack-name ItemsExample \\\n    --region us-east-1 \\\n    | grep -C 5 \"AWS::SNS::Topic\" \\\n    | grep PhysicalResourceId  \\\n    | sed 's/^.*: //; s/\\\"//g; s/,//g;'  \n  ```\n  \u003e Your output should look something like...\n  ```sbtshell\n  arn:aws:sns:us-east-1:XXXXXXXXXXXX:ItemsExample-ChangeEventTopic-Q1W7ED1AEHQK\n  ```\n* Now we'll register using the arn (the output above) and your cell number\n  ```sbtshell\n  aws sns subscribe \\\n  --topic-arn \u003cARN_FROM_ABOVE\u003e \\\n  --region us-east-1 \\\n  --protocol sms \\\n  --notification-endpoint \u003cYOUR_PHONE\u003e\n  ```\n  NOTE: Phone needs to include area code and us code (e.g. 15554444)\n* Finally, let's execute the tests\n  ```sbtshell\n  mvn test\n  ```\n  \nIf everything looks good, all the tests will past and you should of got a bunch of text messages.  Now you can spin up postman or your favorite tool and start playing with the available endpoints.\n\n\u003e See [The Test Harness](#the-test-harness) section for more on what's happening here and check out the curl.log in the logs/ directory to grab some test curls to play with.\n\nYou can get a human readable version of the spec, to better understand what you have to work with, by...\n\n* Going to https://editor.swagger.io/\n* Click file -\u003e \"Import File\"\n* Select \"/path/to/this/src/main/resources/openapi.yaml\"\n\nThis will give you and idea of the model and endpoints.  In addition, checkout the logs/ directory.  If you ran the tests, there should be a curl.log.  You can copy those into your favorite tool as well to begin playing.\n\n\u003e To remove all the resources, see [Cleaning Up](#cleaning-up).\n\nMore fun, checkout the various consoles for each of the services we've launched...\n\n* https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks (you could do us-west-1 too) - gives you a view of all the resources we just created and some management over them.\n* https://console.aws.amazon.com/dynamodb/home?region=us-east-1 - checkout the global table you created and your additional configuration options\n* https://console.aws.amazon.com/iam/home?region=us-east-1#/home - the roles and policies you've created\n* https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions - the nodejs endpoints you've launched\n* https://console.aws.amazon.com/sns/v2/home?region=us-east-1#/home - the SNS topic you created\n* https://console.aws.amazon.com/cloudwatch/home?region=us-east-1# - The logs all these new services are producing.\n\n### How It Works\n\nThe magic starts with the configuration files mentioned way back in the beginning.  Let's begin with these...\n\n#### src/main/resources/aws-resources.yaml\n\nThis file describes and configures the resources needed to run your new service in AWS and includes...\n\n```yaml\n  ## the actual table\n  ItemsTable:\n    Type: AWS::DynamoDB::Table\n```\n\nThe above starts off the section for the applications database configuration.  It...\n\n* Creates a table - This is the \"ItemsTable\" section and to make it easier for us to create a global table, we provide a name (e.g. \"ItemsExampleTable\").  If you wanted to repeat this setup for another application, the \"TableName\" attribute is actually the only thing you would need to change.\n* Creates a scaling role and policy - The \"ScalingRole\" section allows this table to be managed by AWS Auto-Scaling services for both the DB itself and it's logs - https://docs.aws.amazon.com/AmazonECS/latest/developerguide/autoscale_IAM_role.html\n* Creates read and write scalable targets - The \"WriteCapacityScalableTarget\", \"WriteScalingPolicy\", \"ReadScalingTarget\", and \"ReadScalingPolicy\" sections all tell AWS the scaling rules (e.g. how and when to scale) - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html\n* Creates an event stream - \"DataTableStream\" creates a stream for table change events and registers our Lambda \"\" as the receiver\n\n```yaml\n  LambdaBasicExecutionRole:\n    Type: AWS::IAM::Role\n```\n\nThe above starts off the Lambda configuration.  Here we configure and deploy two lambdas using inline NodeJS code.  This section breaks down to...\n\n* The execution role - \"LambdaBasicExecutionRole\" gives DynamoDB access to the lambdas, you can use this to configure access to any AWS service - https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role\n* Ability to save JSON as a structured DynamoDB document - \"SaveToDynamo\" is a generic lambda that takes any JSON converts it to a DynamoDB friendly format, adds an ID, and then saves off to the table configured in the \"ItemsTable\" section.\n* Ability to convert DynamoDB JSON to normalized JSON - \"DynamoToJSON\" is another generic lambda, that simply converts the DynamoDB format back to a JSON format in keeping with the API data model.\n* Ability to update DynamoDB - \"DynamoJSONUpdate\", the last of the generic lambdas, converts a JSON request into an update statement.\n* Ability to receive change events from dynamo - \"HandleDynamoEvent\" takes DynamoDB change events and publishes messages to SNS about what's happened.\n* Finally, the \"ChangeEventTopic\" is the topic that the \"HandleDynamoEvent\" will use to publish it's messages.\n\n```yaml\n  APIGatewayRole:\n    Type: AWS::IAM::Role\n```\n\nThis section simply provides the API Gateway rights to use both DynamoDB and lambda functions so it can handle responses to API requests.\n\n```yaml\n  RestAPIv2:\n    Type: AWS::ApiGateway::RestApi\n```\n\nFinally, the above, is the container for what will be the AWS Gateway deployment. Our OpenAPI document is appended here as part of the `mvn clean compile generate-resources` command.\n\n#### src/main/resources/openapi.yaml\n\nNothing special here.  If you don't know about OpenAPI, we recommend you learn more - https://www.openapis.org/ - and come back.\n\nYou could replace this specification with any, as long as it's OpenAPI 3.x and you could generate a CRUD just for it. By default, this will handle any validations you describe with the spec.  It's pretty powerful for not writing any code!\n\nYou can even take this further by enabling transactions on DynamoDB - https://aws.amazon.com/blogs/aws/new-amazon-dynamodb-transactions/ - where you can configure transactional validations making it even more powerful without a line of code.\n\n\u003e Need to call AWS to enable for global tables, if you don't it won't work :)\n\n#### src/main/resources/aws-extensions.yaml\n\nMore of AWS' secret sauce, this let's us describe how the endpoints interact with AWS or other services.  Typically this would be in the OpenAPI spec itself, but for readability we broke it out to a separate document and merge it with the same `mvn clean compile generate-resources` command that merges the OpenAPI spec into the AWS Resources document.\n\nIn this document there is a matching section for each endpoint, using same canonical structure, just with AWS specific extensions.  For each operation, we have some configuration...\n\n**GET /item/{id}**\n\n```yaml\n      x-amazon-apigateway-integration:\n        credentials: !GetAtt APIGatewayRole.Arn\n        uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DynamoToJSON.Arn}/invocations\n        responses:\n          default:\n            statusCode: \"200\"\n        passthroughBehavior: \"when_no_templates\"\n        httpMethod: \"POST\"\n        type: \"aws_proxy\"\n```\n\nThis section tells that any get request should be routed our \"DynamoToJSON\" described earlier.  API Gateway just acts as a proxy here, passing the request to the function and the response back to the consumer.\n\n**DELETE /item/{id}**\n\n```yaml\n      x-amazon-apigateway-integration:\n        credentials: !GetAtt APIGatewayRole.Arn\n        uri: !Sub \"arn:aws:apigateway:${AWS::Region}:dynamodb:action/DeleteItem\"\n        responses:\n          default:\n            statusCode: \"200\"\n            responseTemplates:\n              application/json: |-\n                { \"id\": \"$method.request.path.id\" }\n        requestTemplates:\n          application/json: !Sub |\n            {\n              \"TableName\": \"${ItemsTable}\",\n              \"Key\": {\n                \"id\": {\n                  \"S\": \"$input.params('id')\"\n                }\n              }\n            }\n        passthroughBehavior: when_no_templates\n        httpMethod: \"POST\"\n        type: aws\n```\n\nThis endpoint puts a little more onus on the API Gateway.  It uses it's DynamoBD service integration to send a DELETE request directly to DynamoDB then respond with ID of the deleted item as confirmation.\n\n**PUT /item/{id}**\n\n```yaml\n      x-amazon-apigateway-integration:\n        credentials: !GetAtt APIGatewayRole.Arn\n        uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DynamoJSONUpdate.Arn}/invocations\n        responses:\n          default:\n            statusCode: \"200\"\n        passthroughBehavior: \"when_no_templates\"\n        httpMethod: \"POST\"\n        type: \"aws_proxy\"\n```\n\nThe above works like the GET, by proxying to \"DynamoJSONUpdate\" lambda and taking the path and the body to perform the update.\n\n**GET /items/**\n\n```yaml\n      x-amazon-apigateway-integration:\n        credentials: !GetAtt APIGatewayRole.Arn\n        uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DynamoToJSON.Arn}/invocations\n        responses:\n          default:\n            statusCode: \"200\"\n        passthroughBehavior: \"when_no_templates\"\n        httpMethod: \"POST\"\n        type: \"aws_proxy\"\n```\n\nLike GET /items/{id}, this method works as a proxy to the \"DynamoToJSON\" lambda so it can return a list of requests.\n\n**POST /items/**\n\n```yaml\n      x-amazon-apigateway-request-validator: \"Validate body\"\n      x-amazon-apigateway-integration:\n        credentials: !GetAtt APIGatewayRole.Arn\n        uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SaveToDynamo.Arn}/invocations\n        responses:\n          default:\n            statusCode: \"200\"\n        passthroughBehavior: \"when_no_templates\"\n        httpMethod: \"POST\"\n        type: \"aws_proxy\"\n```\n\nLike the other endpoints that work as proxies, the POST endpoint does as well. You will notice one difference here...\n\n```yaml\n      x-amazon-apigateway-request-validator: \"Validate body\"\n```\n\nThe above actually tells the API Gateway to validate the request payload before proxying it.  API Gateway uses the OpenAPI spec descriptors (required,min/max,allowed,etc...) to validate the payload automatically.  This is great if you're actually defining your field level requirements in the spec and is standard (e.g. NOT AWS specific) so the documentation, client libraries and other artifacts generated will also include this information.\n\n\u003e Amazon API Gateway Specs say things like patterns, exclusiveMinimum and other OAS properties don't work, but if you look at the tests, you'll see they actually do!\n\n**Bringing It Together**\n\nWe use YAML because it's easier to read and has less markup then the JSON version of the documents.  To make merging easier, however, we convert to JSON.  This is why we have those `cfn-flip` statements.  There is some secret sauce there that we don't want to try to replicate ourselves when it comes to JSON \u003c--\u003e YAML conversion for CloudFormation templates.\n\nWhen we combine this, with our simple JAVA program that merges all the docs as one we have our final CloudFormation template which describes all resources.  All those `aws cloudformation create-stack` commands really do is send that template off to AWS and telll it what region to push it too.\n\n#### The Test Harness\n\nUsing the [BDD For All](https://github.com/Accenture/bdd-for-all) test harness from Accenture,  we created a few test cases to make sure we were truly cross-region and that some of the rules and validations we set up through the OAS Spec were actually working.  \n\nFound in [src/test/resources/features/](src/test/resources/features/), we have test cases that cover invalid requests, checking for create/updates/deletes availablity cross region and more.\n\n\u003e Try writing your own tests, learn the grammar and other functionality available with the BDD For All library at - \n\nIf you look in the logs directory after the tests are executed, you'll find a \"curl.log\", which has all the tests logged as cURLs that you can import into your favorite application to do some further testing.\n\n### Taking it Further\n\nWhat if we didn't want a simple NodeJS lambda backing our API, but instead wanted a Reactive JAVA application.  \n\nThat's easy!  Just type...\n\n```\nmvn clean spring-boot:run -Poas\n```\n\nand when you see...\n\n```sbtshell\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::        (v2.1.0.RELEASE)\n```\n\nGo to http://localhost:8080 and checkout your docs and somewhat functioning mocks.\n\n#### What Did We Just Do?\n\nThe OpenAPITools project - https://github.com/OpenAPITools - has built on what the SmartBear - https://swagger.io/ - done to make some cool tools.  \n\nThe `-Poas` at the end of the previous mvn command, executes a maven plugin that exposes the OpenAPI Generator project - https://github.com/OpenAPITools/openapi-generator - which allows you to generate client libraries, server stubs, documentation and more for a variety of languages and platforms.\n\nWe generated a Spring Reactor shell, the code for which you can find at [src/main/java/io/github/mikeparcewski/demos/awsoas/generated](src/main/java/io/github/mikeparcewski/demos/awsoas/generated).  The shell pretty much contains all the plumbing.  All you really need to do implement, is...\n\n* Add src/main/java/io/github/mikeparcewski/demos/awsoas/generated/api/ItemsApiDelegate.java to the .openapi-generator-ignore file (this keeps it from getting overwritten)\n* Then edit ItemsApiDelegate to implement your business logic.\n\n**Aside**\n\nThere are a lot of languages to choose from - https://github.com/OpenAPITools/openapi-generator#Overview - and by changing the following line to be the language/framework of your choice...\n\n```xml\n\u003cgeneratorName\u003espring\u003c/generatorName\u003e\n```\n\nand this...\n\n```xml\n\u003cconfigOptions\u003e\n...\n\u003c/configOptions\u003e\n```\n\nTo match the config for your language/framework option, you could build the app in almost any language your want.\n  \n## Cleaning Up\n\nRemove the global table mapping...\n\n```sbtshell\naws dynamodb update-global-table \\\n    --global-table-name ItemsExampleTable \\\n    --replica-updates 'Delete={RegionName=us-east-1,RegionName=us-west-1}' \\\n    --region us-east-1\n```\n\nRemove the US East stack...\n\n```sbtshell\naws cloudformation delete-stack \\\n  --stack-name ItemsExample \\\n  --region us-east-1\n```\n\nRemove the US West stack...\n\n```sbtshell\naws cloudformation delete-stack \\\n  --stack-name ItemsExample \\\n  --region us-west-1\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeparcewski%2Faws-openapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikeparcewski%2Faws-openapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeparcewski%2Faws-openapi/lists"}