Multiple services under directory


#1

Hi, newbie here. I’d like to deploy a serverless architecture with multiple subservices under a single api gateway.

So far I understood there should be a supported configuration which is:

provider: 
      apiGateway:
        restApiId: xxxxxxxxxx 
        restApiRootResourceId: xxxxxxxxxx
        restApiResources:
        /posts: xxxxxxxxxx

But apart from the first series of xxx, I am not able to understand from serverless documentation, what restApiRootResourceId or /posts xxxx values should be supplied.

Can anyone help me understand this? thanks


#2

I don’t have a solution, but I have been trying to figure this out for a couple days. Can someone PLEASE post example YML from 2 services with 1 apiGatewayId?

I have tried using an Output Value and an Export from the main stack resources, and then using that variable in the second stack’s provide. But it always creates 2 separate ApiGateways.

resources:
  Outputs:
    BamGatewayId:
      Description: Id of the auto-generated API Gateway resource
      Value:
        Fn::Join:
          - ''
          - - Ref: ApiGatewayRestApi
      Export:
        Name: bamgateway

I can’t seem to find an example of this solution anywhere…


#3

I’m a newbie too, but I can think of 2 ways of doing this.

The first way is to use a custom domain and url rewriting (through baseUrl) for each service. Basically each service will have its own CloudFront, but they’ll all be available though a common custom domain.

For instance, using this model, I can have:

  • https://api.mydomain/service1/get/:id
  • https://api.mydomain/service1/getAll
  • https://api.mydomain/service2/create

The 2nd way would be to only use 1 service but split your code in subdirectories:

functions:
  service1.getById:
    handler: service1/main.getById
    events:
      - http:
          method: get
          path: service1/get/:id
  service2.create:
    handler: service2/main.create
    events:
      - http:
          method: post
          path: service2/create

I haven’t tested the 2nd solution but read about it online a few times. I’d rather go with the 1st solution or I guess the serverless.yml will grow quite a lot if it contains all endpoints of all services.


#4

I’m starting to implement a variation of that first solution now:

I am deploying all of my services to separate API gateways. I have a cloudfront CDN in front of them with each API-G mapped to a behavior.

So https://mydomain.com/api/assets -> cloudfront behavior that routes that traffic to the api gateway for the “assets” service.


#5

I think both are brilliant solutions, but there should be a way of doing this using the restApiId, restApiRootResourceId and in general the apiGateway configuration section.


#6

I have updated the docs to explain this. You can find it here: https://github.com/serverless/serverless/blob/master/docs/providers/aws/events/apigateway.md#share-api-gateway-and-api-resources


#7

Hey great documentation. I 've also deploy many microservices under same API GATEWAY.

But i find some one big issue on this approach.
There is the chance that 2 services use the same parent resource /resource so in order to solve this I 've created a seperate serverless.yml that builds all resource in ApiGateway and output the values in the stack value. But thinks getting harder in examples like you have urls

companies/{companyId}/stories
companies/{companyId}/campaigns

Now you need a value in the stack for both companies and companies/{companyId} resource

While api is getting bigger you either have more resources to create and output or you should find other ways to format your urls

What would you suggest?


#8

Hi,
I copied the code in this link: https://github.com/serverless/serverless/blob/master/docs/providers/aws/events/apigateway.md#share-api-gateway-and-api-resources, but i get different endpoints and restApiId’s. Can anyone check what i could have done wrong? here are my 2 services:

service: notes-app-mono-notes

plugins:

  • serverless-webpack
  • serverless-offline

custom:
stage: ${opt:stage, self:provider.stage}

webpack:
webpackConfig: …/…/webpack.config.js
includeModules: true

provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1

environment:
tableName:
${file(…/database/serverless.yml):custom.tableName}

iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- ‘Fn::ImportValue’: ${self:custom.stage}-NotesTableArn

functions:
get:
# Defines an HTTP API endpoint that calls the main function in get.js
# - path: url path is /notes/{id}
# - method: GET request
handler: get.main
events:
- http:
path: notes/{id}
method: get
cors: true
authorizer: aws_iam

resources:
Resources:
MyApiGW:
Type: AWS::ApiGateway::RestApi
Properties:
Name: MyApiGW

Outputs:
apiGatewayRestApiId:
Value:
Ref: MyApiGW
Export:
Name: MyApiGateway-restApiId

apiGatewayRestApiRootResourceId:
  Value:
    Fn::GetAtt:
      - MyApiGW
      - RootResourceId
  Export:
    Name: MyApiGateway-rootResourceId

service: notes-app-mono-billing

plugins:

  • serverless-webpack
  • serverless-offline

custom:
stage: {opt:stage, self:provider.stage} webpack: webpackConfig: ../../webpack.config.js includeModules: true environment: {file(env.yml):${self:custom.stage}, file(env.yml):default}

provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1

apiGateway:
restApiId:
‘Fn::ImportValue’: MyApiGateway-restApiId
restApiRootResourceId:
‘Fn::ImportValue’: MyApiGateway-rootResourceId

environment:
stripeSecretKey: ${self:custom.environment.stripeSecretKey}

functions:

billing:
handler: billing.main
events:
- http:
path: billing
method: post
cors: true
authorizer: aws_iam

I noticed in cloudfront that my notes service has different service endpoint and apiGatewayRestApiId. Is this supposed to happen?
Service endpoint: https://exttceymxb.execute-api.us-east-1.amazonaws.com/dev
apiGatewayRestApiId: e10zsltayj

Thank you