Multiple microservices inside same AWS API Gateway - microservices

I'm developing a series of microservices which need to share the same AWS API Gateway. Here's my structure:
/
/assessments
/skills
/work-values
/graphql
/skills, /work-values, and /graphql are 3 different microservices I'm trying to register with the same AWS API Gateway. The problem I'm having is getting the serverless.yaml files for /skills, /work-values routes to nest under 'assessments'. There is no functionality for /assessments in-and-of-itself. It exists just so we can organize all of our assessments under the same URL path structure.
Here's my serverless.yaml file for `/work-values':
service:
name: assessments-workvalues
...
custom:
stage: ${opt:stage, self:provider.stage}
provider:
...
apiGateway:
restApiId:
# THE FOLLOWING REFERENCES A VARIABLE FROM MY API GATEWAY ROOT
'Fn::ImportValue': ${self:custom.stage}-ApiGatewayRestApiId
restApiRootResourceId:
'Fn::ImportValue': # HOW DO I GET THE PROPER VALUE HERE TO MAP TO `/assessments`?
...
functions:
...
Here's my serverless.yaml file for `/assessments':
service:
name: assessments
custom:
stage: ${opt:stage, self:provider.stage}
provider:
...
apiGateway:
restApiId:
# THE FOLLOWING REFERENCES A VARIABLE FROM MY API GATEWAY ROOT
'Fn::ImportValue': ${self:custom.stage}-ApiGatewayRestApiId
restApiRootResourceId:
'Fn::ImportValue': ${self:custom.stage}-ApiGatewayRestApiRootResourceId
functions:
...
resources:
Outputs:
ApiGatewayRestApiId:
Value:
Ref: ApiGatewayRestApi
Export:
Name: ${self:custom.stage}-Assessments-ApiGatewayRestApiId
ApiGatewayRestApiRootResourceId:
Value:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
Export:
Name: ${self:custom.stage}-Assessments-ApiGatewayRestApiRootResourceId
The problem seems to be coding the Outputs in serverless.yaml file for assessments route. When I run serverless deploy, I get this error message:
Error: The CloudFormation template is invalid: Unresolved resource dependencies [ApiGatewayRestApi] in the Outputs block of the template
At the end of Share an API Endpoint Between Services article, the author mentions 'You HAVE TO import /billing from the billing-api, so the new service will only need to create the /billing/xyz part.' (which seems to be the situation I'm in). But, the author does not explain how to import /billing. Or in my case, how do I import /assessments into the serverless.yaml files for each assessment microservice?

After further research, I found this link:
Splitting Your Serverless Framework API on AWS
I ended up reworking my original approach following what's in the article above. The piece I was missing was having a root or base serverless file which is used to create your routing in AWS API Gateway and expose those placeholders as output which your subsequent child serverless files consume as input for wiring up your child lambda functions to routes under the API Gateway umbrella.

Related

how to include secret.json files in SAM template.yml

In my previous application, I work with a serverless framework but now I want to use sam template.
when I used serverless I include secret.json in one section and used multiple places like this way ${self:custom.secrets.AWS_ID}.
My sample code:
custom:
secrets: ${file(secrets.json)}
tableName: ${self:custom.secrets.DB_TABLE_NAME}
provider:
name: aws
runtime: nodejs12.x
environment:
JWT_SECRET: ${self:custom.secrets.JWT_SECRET}
AWS_ID: ${self:custom.secrets.AWS_ID}
DB_TABLE_NAME: ${self:custom.secrets.DB_TABLE_NAME}
Now my question is, how can I include secret.json and use multiple places in sam template.yml file

lambda#edge cloudfront resource creation

I'm a little lost here, I'm trying to deploy a simple function that uses Lambda#edge but I having some problems creating the Cloudfront resource and attaching that CF to the lambda function.
Here is an example of the serverless.yml
service: some-service
plugins:
- serverless-pseudo-parameters
provider:
name: aws
runtime: nodejs10.x
stage: ${env:STAGE}
region: us-east-1
resources:
- ${file(./resources.yml):resources}
functions:
- ${file(./lambda-at-edge/function.yml):functions}
The function definition:
functions:
lambda-at-edge-function:
description: Lambda at edge authentication
handler: serverless/index.handler
events:
- cloudFront:
eventType: viewer-response
origin: s3://some.s3.amazonaws.com/
One thing if I don't define the Cloudfront resources it's not created and If I define the resource and attach that to the serverless definition it's create the resource, but then I don' know how to attach that cloudfront to the function.
Edit:
So I'm deploying everithing with sls deploy, so my question now is how can I attach the funtion name to be used in LambdaFunctionAssociations from cloudfront distribution.
When using Lambda#edge you have to respect the limits.
Check them out here:
Requirements and Restrictions on Lambda Functions
This should work:
service: some-service
plugins:
- serverless-pseudo-parameters
provider:
name: aws
runtime: nodejs10.x
stage: ${env:STAGE}
region: us-east-1
memorySize: 128
timeout: 5
resources:
- ${file(./resources.yml):resources}
functions:
- ${file(./lambda-at-edge/function.yml):functions}

AWS SAM : Creating/Exporting API Gateway resource and importing it in another stack

I am trying to use SAM to automate my deployment on AWS.
In the first SAM template, I want to create an API Gateway, Cognito authoriser and a lambda function which uses this API gateway.
I am trying to export this API gateway resource, from the first template.
I want to use this API gateway resource in another SAM template, using import statement.
Is there any good example which explains exporting API gateway resource from the first SAM template and then using it in the second SAM template.
Try this (not tested):
From here Fn::ImportValue
Stack A Export
Outputs:
ServerlessRestApi:
Value: !Ref MyApiGatewayResource
Export:
Name: !Sub "${AWS::StackName}-ServerlessRestApi"
Stack B Import
Import to a Lambda Function:
MyLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-MyLambda"
Handler: ....
CodeUri: .....
Events:
MyApi:
Type: Api
Properties:
Path: /example
Method: post
RestApiId:
Fn::ImportValue:
!Sub "${StackANameParameter}-ServerlessRestApi"
Hope this helps

Pointing Two AWS Lambda Functions to Same Domain

I am using the serverless framework and AWS Lambdas to deploy two function with different path names (/message and /subscribe) to my subdomain at form.example.com.
I am using the serverless-domain-manager plugin for serverless and successfully configured my domain for the /message function using serverless create_domain, but since I also needed to do that for /subscribe I tried to follow the same process receiving messages that the domain already existed and caught an error Error: Unable to create basepath mapping..
After flipping a configuration (createRoute53Record: false) and re-running it started to work, but now when I run sls deploy for my /message function I get the error message I used to see for /subscribe.
Error (from sls deploy):
layers:
None
Error --------------------------------------------------
Error: Unable to create basepath mapping.
For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
Here is my config for the serverless-domain-manager:
plugins:
- serverless-offline
- serverless-domain-manager
custom:
transactionDomain:
dev: ${file(./local-keys.yml):transactionDomain}
prod: ${ssm:mg-production-transaction-domain~true}
newsletterDomain:
dev: ${file(./local-keys.yml):newsletterDomain}
prod: ${ssm:mg-production-newsletter-domain~true}
apiKey:
dev: ${file(./local-keys.yml):apiKey}
prod: ${ssm:mg-production-api-key~true}
customDomain:
domainName: form.example.com
certificateName: 'www.example.com' //sub-domain is included in the certificate
stage: 'prod'
createRoute53Record: true
Does this have to do with the deployment of two functions to the same domain? Is there a proper process to allow that to happen?
If you do not need API gateway specific features, such as usage plan. You can put two lambda behind ALB per path routing.

SAM Template: multiple microservice lambdas sharing a single AWS::ApiGateway::DomainName

My goal is allow several independent lambda resources (microservices) to share a common custom domain for test environment. Using the below template, deploying microservice #1 went off without issue. However, when deploying microservice #2, CloudFormation fails and rolls back because the domain name is assigned to microservice #1.
Surely it must be possible to share a common custom domain among several microservices with unique paths?
Service #1 template.yaml
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: !Sub ${apiGatewayStageName}
DefinitionBody:
swagger: "2.0"
info:
title: !Sub ${functionName}
paths:
"/service_one":
post:
responses: {}
x-amazon-apigateway-integration:
uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}:live/invocations"
httpMethod: POST
type: aws_proxy
ApiGatewayCustomDomainName:
Type: AWS::ApiGateway::DomainName
Properties:
CertificateArn: !Sub "arn:aws:acm:${AWS::Region}:${AWS::AccountId}:certificate/${apiGatewayCDNCertificateId}"
DomainName: !Sub "${envName}.${apiGatewayCustomDomainNameSuffix}"
DependsOn:
- "LogsSubscriptionFilter"
- "ApiGatewayApi"
ApiGatewayBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
DomainName: !Ref ApiGatewayCustomDomainName
RestApiId: !Ref ApiGatewayApi
Stage: !Ref apiGatewayStageName
DependsOn: "ApiGatewayCustomDomainName"
The Service #2 template is the same, except with a different path (.e.g. /service_two.
Worked with AWS support to get to the bottom of this one. In its current form (May 2018), if you want separate SAM templates for each lambda for deployment reasons, but have a shared API Gateway resource for those lambdas, then you must have a separate dedicated API Gateway SAM template. Additionally, the Events parameter in AWS::Serverless::Function must be excluded in favor of paths definitions in AWS::Serverless::Api.
Lastly, the AWS::Serverless::Function(s) must be exported under Output and then imported by the AWS::Serverless::Api resource.

Resources