serverless-application-model
serverless-application-model copied to clipboard
Handling AWS::NoValue in Api resources
Description:
I was hoping to make use of the new Domain
property on Api resources, but conditionally based on a template parameter. Attempting to set the Domain
to !Ref AWS::NoValue
(for the case where no DomainName
is desired) fails with a message that suggests it's not removing the Domain
property and is expecting real configuration in it. Here's what I tried in the Api
configuration:
Domain:
!If
- HasDomainName
- DomainName: !Ref DomainName
CertificateArn: !Ref DomainCertificateArn
- !Ref AWS::NoValue
And the message I got:
Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [EventApi] is invalid. Custom Domains only works if both DomainName and CertificateArn are provided
Steps to reproduce the issue:
- Create an
AWS::Serverless::Api
resource withDomain
property specified as in above example withHasDomainName
condition (evaluating to false). - Deploy the SAM template.
- Check the results.
Observed result:
Deploy fails with message: "Custom Domains only works if both DomainName and CertificateArn are provided"
Expected result:
DomainName
and BasePathMapping
resources created as if I had applied the conditional on each of them, such as:
ApiCustomDomain:
Type: AWS::ApiGateway::DomainName
Condition: HasDomainName
Properties:
DomainName: !Ref DomainName
RegionalCertificateArn: !Ref DomainCertificateArn
EndpointConfiguration:
Types:
- REGIONAL
ApiBasePath:
Type: AWS::ApiGateway::BasePathMapping
Condition: HasDomainName
Properties:
DomainName: !Ref ApiCustomDomain
RestApiId: !Ref EventApi
Stage: !Ref EventApi.Stage
Any progress with this? Is there a workaround other that manually setting the domain name and certificate in the AWS console for those you want it?
I think the same is true for Auth / ResourcePolicy as well.
I tried this every way I could think of:
- Moving the conditional to each function (
RestApiId
does not supportAWS::NoValue
) - Adding all Parameters under the conditional
- Using a mix of Mappings and higher level conditionals
We ended up needing to add a (manual or scripted) pre-deploy step that just removes the entire Domain config part if a domain isn't desired. I'd love to see a way to conditionally set a domain on an API.
Thanks a lot guys. I was able to reproduce the issue. the problem is in this peace of code. We raise an exception if the Domain
is provided but without DomainName
or CertificateArn
. When passing AWS::NoValue
we receive a Domain={'Ref': 'AWS::NoValue'}
that is why the exception is raised.
I'm labeling this for internal review as this is a common issue affecting many other areas as well.
I believe the error extends beyond just AWS::NoValue. I am trying to conditionally set the Domain configuration to support a Gov Cloud deployment and get the same error despite each option in the condition containing the DomainName
and CertificateARN
. Template below for reference:
Domain:
!If
- GovCloudCondition
- DomainName: !Ref DomainName
CertificateArn: !Ref CertificateARN
EndpointConfiguration: REGIONAL
- CertificateArn: !Ref CertificateARN
DomainName: !Ref DomainName
EndpointConfiguration: EDGE
That yields the same error above:
[Error found when transforming the template] Error transforming template: Resource with id [SageMakerApi] is invalid. Custom Domains only works if both DomainName and CertificateArn are provided
Hi, is there any new on this? I am writing a SAM template, and am forced to define three AWS::Serverless::Api
resources conditionally to handle cases such as:
- The user wants to specify a vpc endpoint or not (create PRIVATE/REGIONAL API)
- The user wants to specify a custom domain name or not
Ideally I would like to define a single resource and conditionally add a Domain
or an Auth/ResourcePolicy
, etc.
Unfortunately, no progress I'm aware of at the time. Conditionally defining AWS::Serverless::Api
resources seems to be the current work around. I think if you define your template in yaml, you can eliminate some of the duplication by using "Anchors" and "References".
Hi @elbayaaa I am curious how you are able to conditionally define multiple AWS::Serverless::Api
and select between them based on issue #1470. If I have an AWS::Serverless::Function
that uses the REST API for events, and I don't want one to use a domain (for example), do I have to define multiple lambda functions, one for each environment?
Having the same issue when defining conditional domains. Any workaround?
Having a similar issue as holt-cader trying to define conditional EndpointConfiguration. Intrinsic functions do not work inside Domain per AWS support. Hoping this gets resolved.
"""In the above snippet you are using “EndpointConfiguration” which further holds the condition under “DomainName” . Domain property was unable to to accept value through Intrinsic Function ’If' and from the testing I have performed
It seems there is no issue with your template but this feature is not being supported by AWS till now."""
Domain:
DomainName: www.example.com
CertificateArn: !Sub 'my:::arn'
EndpointConfiguration:
!If
- IsCA
- EDGE
- REGIONAL
"FAILED" Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FormApiGateway] is invalid. EndpointConfiguration for Custom Domains must be one of ['EDGE', 'REGIONAL', 'PRIVATE']."
I thought I found a work-around but actually found another bug. I created 2 APIs so the entire API definition was dependent on my condition. Unfortunately, the following fails validation with sam validate:
MyFunction:
Type: AWS::Serverless::Function
Properties:
Events:
MyApi:
Type: Api
Properties:
RestApiId: !If [ IsNotDev, !Ref ValidApiRef1, !Ref ValidApiRef2 ]
Path: /site-customization
Method: POST
Here is the error:
Error: [InvalidResourceException('MyFunction', 'Event with id [MyApi] is invalid. Api Event must reference an Api in the same template.')] ('MyFunction', 'Event with id [MyApi] is invalid. Api Event must reference an Api in the same template.')
I faced the same problem for an HTTP API and found a work-around which seems to be fine: set the custom domain using "native" CloudFormation resources in place of SAM "Domain" attribute. I don't know if something similar can also work for REST APIs, I post it here anyway as this topic appears to be the most related to my problem.
Resources:
Api:
Type: AWS::Serverless::HttpApi
# put any necessary properties excluding the domain
ApiDomain:
Type: AWS::ApiGatewayV2::DomainName
Condition: HasDomainName
Properties:
DomainName: !Ref DomainName
DomainNameConfigurations:
- CertificateArn: !Ref DomainCertificateArn
ApiDomainMapping:
Type: AWS::ApiGatewayV2::ApiMapping
Condition: HasDomainName
Properties:
ApiId: !Ref Api
Stage: $default # unless a different StageName is used in Api
DomainName: !Ref ApiDomain
You might be able to get this to work by adding AWS::LanguageExtensions
to Transform
as such:
Transform:
- AWS::LanguageExtensions
- AWS::Serverless-2016-10-31
AWS::LanguageExtensions
resolves intrinsic functions if the value is known when Transform
s are run.
See https://github.com/aws/serverless-application-model/issues/2533 for more information.
Closing in favor of https://github.com/aws/serverless-application-model/issues/2533.