Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions DEVELOPMENT_GUIDE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,23 @@ Install snakeviz `pip install snakeviz`
```
python -m cProfile -o sam_profile_results bin/sam-translate.py translate --input-file=tests/translator/input/alexa_skill.yaml --output-file=cfn-template.json
snakeviz sam_profile_results
```

Verifying transforms
--------------------

If you make changes to the transformer and want to verify the resulting CloudFormation template works as expected, you can transform your SAM template into a CloudFormation template using the following process:

```shell
# Optional: You only need to run the package command in certain cases; e.g. when your CodeUri specifies a local path
# Replace MY_TEMPLATE_PATH with the path to your template and MY_S3_BUCKET with an existing S3 bucket
aws cloudformation package --template-file MY_TEMPLATE_PATH/template.yaml --output-template-file output-template.yaml --s3-bucket MY_S3_BUCKET

# Transform your SAM template into a CloudFormation template
# Replace "output-template.yaml" if you didn't run the package command above or specified a different path for --output-template-file
bin/sam-translate.py --input-file=output-template.yaml

# Deploy your transformed CloudFormation template
# Replace MY_STACK_NAME with a unique name each time you deploy
aws cloudformation deploy --template-file cfn-template.json --capabilities CAPABILITY_NAMED_IAM --stack-name MY_STACK_NAME
```
2 changes: 1 addition & 1 deletion bin/sam-translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def main():
except InvalidDocumentException as e:
errorMessage = reduce(lambda message, error: message + ' ' + error.message, e.causes, e.message)
print(errorMessage)
errors = map(lambda cause: {'errorMessage': cause.message}, e.causes)
errors = map(lambda cause: cause.message, e.causes)
print(errors)


Expand Down
41 changes: 21 additions & 20 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.todo',
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'sphinx.ext.githubpages']
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'sphinx.ext.githubpages']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand Down Expand Up @@ -85,25 +85,29 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#

html_theme_options = {
'description': "Define your serverless infrastructure as a simple YAML file",
'logo': 'logo.png',
'logo_name': True,
'logo_text_align': 'center',
'github_user': 'awslabs',
'github_repo': 'serverless-application-model',
'github_button': True,
'github_type': 'star',
'github_banner': True,
'sidebar_collapse': True,
}

# html_theme_options = {
# 'description': "Define your serverless infrastructure as a simple YAML file",
# 'logo': 'logo.png',
# 'logo_name': True,
# 'logo_text_align': 'center',
# 'github_user': 'awslabs',
# 'github_repo': 'serverless-application-model',
# 'github_button': True,
# 'github_type': 'star',
# 'github_banner': True,
# 'sidebar_collapse': True,
# }

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
Expand All @@ -116,9 +120,9 @@
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html'
'about.html',
'navigation.html',
'relations.html'
]
}

Expand Down Expand Up @@ -180,7 +184,6 @@
]



# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
Expand All @@ -200,5 +203,3 @@

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']


3 changes: 3 additions & 0 deletions examples/.eslintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extends: standard
rules:
prefer-promise-reject-errors: off # API Gateway expects string response from Lamdba (when using async + Promise.reject)
45 changes: 45 additions & 0 deletions examples/2016-10-31/api_cognito_auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# API Gateway + Cognito Auth + Cognito Hosted Auth Example

This example shows you how to create an API Gateway API with a Cognito Authorizer using SAM.

## Running the example

Install the Node.js/NPM dependencies for your API's Lambda logic into the `src/` directory. This is necessary so that the dependencies get packaged up along with your Lambda function.

```bash
npm install . --prefix ./src
```

Deploy the example into your account (replace `YOUR_S3_ARTIFACTS_BUCKET` with an existing S3 bucket to store your app assets):

```bash
# The following default values are also allowed: STACK_NAME, COGNITO_USER_POOL_CLIENT_NAME, COGNITO_USER_POOL_DOMAIN_PREFIX
S3_BUCKET_NAME=YOUR_S3_ARTIFACTS_BUCKET \
npm run package-deploy
```

Cognito User Pools doesn't currently have CloudFormation support for configuring their Hosted Register/Signin UI. For now we will create these via the AWS CLI:

```bash
npm run configure-cognito-user-pool
```

Open the registration page created and hosted for you by Cognito in your browser. After the page loads, enter a Username and Password and click the Sign Up button.

```bash
npm run open-signup-page

# Alternatively, you can open the login page by running `npm run open-login-page`
```

After clicking Sign Up, you will be redirected to the UI client for your API.

To access the API UI directly as an unauthorized user (who has access to `GET /users` and `GET /users/{userId}`) you can run `npm run open-api-ui`.

## Additional resources

- https://aws.amazon.com/blogs/aws/launch-amazon-cognito-user-pools-general-availability-app-integration-and-federation/
- https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
- https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-idp-settings.html
- https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-invoke-api-integrated-with-cognito-user-pool.html
- https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html
30 changes: 30 additions & 0 deletions examples/2016-10-31/api_cognito_auth/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "api_cognito_auth",
"version": "1.0.0",
"description": "Example using API Gateway with Cognito Authorizer.",
"main": "lambda.js",
"license": "Apache-2.0",
"dependencies": {
"aws-serverless-express": "^3.3.3",
"body-parser": "^1.17.1",
"cors": "^2.8.3",
"express": "^4.15.2",
"pug": "^2.0.0-rc.1"
},
"scripts": {
"package-deploy": "npm run set-config && npm run package && npm run deploy",
"set-config": "npm config set STACK_NAME ${STACK_NAME:-sam-example-api-cognito-auth}",
"package": "aws cloudformation package --template-file template.yaml --output-template-file template.packaged.yaml --s3-bucket $S3_BUCKET_NAME",
"deploy": "aws cloudformation deploy --template-file ./template.packaged.yaml --stack-name $STACK_NAME --capabilities CAPABILITY_IAM",
"configure-cognito-user-pool": "npm run set-cognito-user-pool-id && npm run set-cognito-user-pool-client-id && npm run set-api-id && npm run set-api-url && npm run update-user-pool-client && npm run create-user-pool-domain",
"set-cognito-user-pool-id": "npm config set COGNITO_USER_POOL_ID $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`CognitoUserPoolId`].OutputValue' --output text)",
"set-cognito-user-pool-client-id": "npm config set COGNITO_USER_POOL_CLIENT_ID $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`CognitoUserPoolClientId`].OutputValue' --output text)",
"set-api-url": "npm config set API_URL $(aws cloudformation describe-stacks --stack-name sam-example-api-cognito-auth --query 'Stacks[].Outputs[?OutputKey==`ApiUrl`].OutputValue' --output text)",
"set-api-id": "npm config set API_ID $(aws cloudformation describe-stacks --stack-name sam-example-api-cognito-auth --query 'Stacks[].Outputs[?OutputKey==`ApiId`].OutputValue' --output text)",
"update-user-pool-client": "aws cognito-idp update-user-pool-client --user-pool-id $(npm config get COGNITO_USER_POOL_ID) --client-id $(npm config get COGNITO_USER_POOL_CLIENT_ID) --supported-identity-providers COGNITO --callback-urls \"[\\\"$(npm config get API_URL)\\\"]\" --allowed-o-auth-flows code implicit --allowed-o-auth-scopes openid email --allowed-o-auth-flows-user-pool-client",
"create-user-pool-domain": "aws cognito-idp create-user-pool-domain --domain $(npm config get API_ID) --user-pool-id $(npm config get COGNITO_USER_POOL_ID)",
"open-signup-page": "open \"https://$(npm config get API_ID).auth.us-east-1.amazoncognito.com/signup?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"",
"open-login-page": "open \"https://$(npm config get API_ID).auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"",
"open-api-ui": "open \"$(npm config get API_URL)\""
}
}
79 changes: 79 additions & 0 deletions examples/2016-10-31/api_cognito_auth/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use strict'
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
const app = express()
const router = express.Router()

app.set('view engine', 'pug')

router.use(cors())
router.use(bodyParser.json())
router.use(bodyParser.urlencoded({ extended: true }))
router.use(awsServerlessExpressMiddleware.eventContext())

router.get('/', (req, res) => {
res.render('index', {
apiId: req.apiGateway ? req.apiGateway.event.requestContext.apiId : null,
apiUrl: req.apiGateway ? `https://${req.apiGateway.event.headers.Host}/${req.apiGateway.event.requestContext.stage}` : 'http://localhost:3000',
cognitoUserPoolClientId: process.env.COGNITO_USER_POOL_CLIENT_ID
})
})

router.get('/users', (req, res) => {
res.json(users)
})

router.get('/users/:userId', (req, res) => {
const user = getUser(req.params.userId)

if (!user) return res.status(404).json({})

return res.json(user)
})

router.post('/users', (req, res) => {
const user = {
id: ++userIdCounter,
name: req.body.name
}
users.push(user)
res.status(201).json(user)
})

router.put('/users/:userId', (req, res) => {
const user = getUser(req.params.userId)

if (!user) return res.status(404).json({})

user.name = req.body.name
res.json(user)
})

router.delete('/users/:userId', (req, res) => {
const userIndex = getUserIndex(req.params.userId)

if (userIndex === -1) return res.status(404).json({})

users.splice(userIndex, 1)
res.json(users)
})

const getUser = (userId) => users.find(u => u.id === parseInt(userId))
const getUserIndex = (userId) => users.findIndex(u => u.id === parseInt(userId))

// Ephemeral in-memory data store
const users = [{
id: 1,
name: 'Joe'
}, {
id: 2,
name: 'Jane'
}]
let userIdCounter = users.length

app.use('/', router)

// Export your express server so you can import it in the lambda function.
module.exports = app
7 changes: 7 additions & 0 deletions examples/2016-10-31/api_cognito_auth/src/lambda.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'
const awsServerlessExpress = require('aws-serverless-express')
const app = require('./app')

const server = awsServerlessExpress.createServer(app)

exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context)
Loading