serverless-domain-manager icon indicating copy to clipboard operation
serverless-domain-manager copied to clipboard

Different domains for different functions

Open zirkelc opened this issue 7 years ago • 12 comments

Is it possible to have different domains pointing to different functions within the same service?

For example: abc.com points to function handle-abc, and xyz.com points to function handle-xyz. Both functions are defined within the same serverless.yaml.

zirkelc avatar Oct 01 '18 17:10 zirkelc

Hi @chriszirkel,

Not in the way that this plugin is currently structured. The easiest solution would probably be to split the functions into different serverless.yaml files.

jconstance-amplify avatar Oct 01 '18 18:10 jconstance-amplify

Yes, that's what I was thinking of. The problem is these services share the same resources and variables, so I have to duplicate those in two serverless.yaml files. Furtheremore, I am using the csharp template and having just one service and project gives me the possibility to share a lot of code between those two functions.

zirkelc avatar Oct 02 '18 07:10 zirkelc

You could try splitting common things out into another file and read that into both of your serverless.yaml files https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-in-other-files

jconstance-amplify avatar Oct 02 '18 14:10 jconstance-amplify

Yes, that's what I am doing now. I got two services that I would like to assign two different domains. Because they use the same other resources (database tables), I split them up in a third service for get, create, update and delete an item from the database. Unfortunately, I have to hard-code the names of the third service functions in my two previous services. Is there a possibility two export those service function names (get-item, create-item, ...) and access threir names them via some env variables?

BTW: Are you planning to support multiple domains in one serverless.yaml any time in the future?

zirkelc avatar Oct 03 '18 13:10 zirkelc

Yes, serverless natively supports that: https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-environment-variables

I wouldn't be opposed to someone sending a PR for that, but I wouldn't consider it a priority for me or anyone else at Amplify to do. Do you have a proposal for how you think that should be structured? I suspect you'd have some issues with it because of how Serverless handles API Gateway creation right now, but would be interested to see how folks would like to see the problem be solved.

jconstance-amplify avatar Oct 03 '18 14:10 jconstance-amplify

I could think of two options how to structure it:

  • addtional customDomains attribute with a list of functions:
custom:
  customDomains:
    first_domain:
      domainName: abc.com
      functions:
        - get-abc
        - create-abc
      basePath: ''
      stage: ${self:provider.stage}
      createRoute53Record: true
    second_domain:
      domainName: xyz.com
      functions:
        - get-xyz
        - create-xyz
      basePath: ''
      stage: ${self:provider.stage}
      createRoute53Record: true 
  • assign customDomain per function, and overide the default customDomain
functions:
  get-abc:
    handler: handler.abc_handler
    events: 
      - http:
        path: /
        method: get
    # override default customDomain      
    customDomain:
      domainName: abc.com
      basePath: ''
      stage: ${self:provider.stage}
      createRoute53Record: true

custom:
  # default custom domain for all functions
  customDomain:
    domainName: xyz.com
    basePath: ''
    stage: ${self:provider.stage}
    createRoute53Record: true    

zirkelc avatar Oct 03 '18 17:10 zirkelc

We have a need for similar functionality: to configure multiple custom domains within the same service. Our use-case doesn't need to bind to functions directly, but to assign multiple subdomains to different base paths within a single service.

What I had in mind was just to optionally pass an array of objects (containing the current config schema) to the existing key and add a check to see if customDomain is an object or array of objects. If it is an array it would iterate them and apply the same logic it does now.

# Current configuration is maintained
custom:
  customDomain:
    domainName: api.foo.com
    stage: ci
    basePath: api
    certificateName: '*.foo.com'
    createRoute53Record: true
    endpointType: 'regional'

# Optional configuration with multiple domains
custom:
  customDomain:
  - domainName: abc.foo.com
    stage: ci
    basePath: abc
    certificateName: '*.foo.com'
    createRoute53Record: true
    endpointType: 'regional'

  - domainName: xyz.foo.com
    stage: ci
    basePath: xyz
    certificateName: '*.foo.com'
    createRoute53Record: true
    endpointType: 'regional'

@chriszirkel would this work for your use-case? To do the above and configure your functions this way:

functions:
  get-abc:
    handler: handler.abc_handler
    events: 
      - http:
        path: /abc
        method: get
  get-xyz:
    handler: handler.xyz_handler
    events: 
      - http:
        path: /xyz
        method: get

Throttlebyte avatar Oct 03 '18 22:10 Throttlebyte

Yes, to apply different basePaths could work for me, as long as those basePaths are hidden via the created custom domain in API gateway. So that I can call the custom domain and it will map to the aws domain with stage and basePath:

  • abc.foo.com/ -> 12345.us-east-1.execute-api.amazonaws.com/dev/abc/
  • xyz.foo.com/ ->12345.us-east-1.execute-api.amazonaws.com/dev/xyz/

zirkelc avatar Oct 04 '18 11:10 zirkelc

I'm not sure AWS actually supports this particular use case @chriszirkel. As far as I know, you can only point a Custom Domain at a given API Gateway, not particular functions inside that API Gateway. So I don't think you could achieve what you want whilst operating inside those limitations. Are you able to make that setup happen in the AWS Console today? Maybe I'm missing something. I think you might be able to set it up via a Cloudfront Distribution...

@Throttlebyte So just to be clear, you want xyz.foo.com/xyz and abc.foo.com/abc to point to the same API Gateway?

jconstance-amplify avatar Oct 04 '18 11:10 jconstance-amplify

@jconstance-amplify We won't need to use any path mapping, but yes- we'd like xyz.foo.com and abc.foo.com to point to the same API Gateway.

@chriszirkel I mistook which side the mapping applied to (I was thinking it mapped and effectively removed pieces of the API path, but it adds to the custom domain path to stitch in multiple services)- you may be able to hide the first part of your path the way you'd like by using stage variables: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-set-stage-variables-aws-console.html

Throttlebyte avatar Oct 05 '18 16:10 Throttlebyte

I'm not sure AWS actually supports this particular use case @chriszirkel. As far as I know, you can only point a Custom Domain at a given API Gateway, not particular functions inside that API Gateway. So I don't think you could achieve what you want whilst operating inside those limitations. Are you able to make that setup happen in the AWS Console today? Maybe I'm missing something. I think you might be able to set it up via a Cloudfront Distribution...

@Throttlebyte So just to be clear, you want xyz.foo.com/xyz and abc.foo.com/abc to point to the same API Gateway?

Yes, you're right, it seems not to be possible to point a custom domain to a function/method. The only way would be to deploy multiple API Gateways for multiple functions.

If you define multiple API Gateways as cloudformation resources within serverless.yaml, then it should easily be possible to create multiple custom domains, right? On the other hand, to manually define all those API mappings as resources seems like a big overhead to achieve that...

zirkelc avatar Oct 07 '18 08:10 zirkelc

I think It will be better, if there is a option to reference a domain to a function as below.

custom:
  customDomain:
    domain1:
      domainName:  abc.foo.com
      stage: ci
      basePath: abc
      certificateName: '*.foo.com'
      createRoute53Record: true
      endpointType: 'regional'
   domain2:
      domainName: xyz.foo.com
      stage: ci
      basePath: xyz
      certificateName: '*.foo.com'
      createRoute53Record: true
      endpointType: 'regional'

And we should be able to reference the domain like below

functions:
  get-abc:
    handler: handler.abc_handler
    events: 
      - http:
        path: /abc
        method: get
    domain: ref{customDomain.domain1}

  get-xyz:
    handler: handler.xyz_handler
    events: 
      - http:
        path: /xyz
        method: get
    domain: ref{customDomain.domain2}

sridhar562345 avatar Nov 30 '21 05:11 sridhar562345