New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: custom domain name creation for websocket APIs #228
Conversation
… empty websockets structure as an additional parameter (via constructPlugin)
…et-specific functions of index.ts
…e a custom domain
…tom domain and a corresponding Route53 record
…domain using API gateway V2
…tom domain and a corresponding Route53 record
… the available CloudFormation stack
… websocket) is enabled
…he websocket domain and extended 'summary printing' test to cover the function again
…ed domainSummary test part
Hi @pavel-ignatiev ! This is awesome, thanks for doing all this work. It'll take us a bit to review your PR, so stay tuned. |
…er visual recognition and fixed the test accordingly
Any update on when this will be merged and released? |
Hi @captainsidd, I think the last Travis build is frozen - could you please retrigger the build? Alternatively I can commit the new changelog which would also retrigger the build, but I think this should be done after review. |
Hi Pavel, this is awesome. I deployed your version your version and it works flawlessly. I have a suggestion for improvement, although I'm not sure it belongs here: when I define an import for WebsocketApi like this in the serverless.yml (which prior to this has been exported from another websockets stack): The generated CloudFormation update template doesn't include this import value but just uses 'WebsocketsApi', which will cause CF to create a new domain upon deploy for that particular stack. This is troublesome, as just like with REST APIs (see: https://serverless-stack.com/chapters/api-gateway-domains-across-services.html) it would be good if several WS stacks can re-use the same auto-generated domain, which the custom domain(s) can then point to. Is this behaviour coming from your PR or something in CF that hasn't been resolved by AWS yet? |
Hi @aligg73 , nice to see the feature is working! Regarding the I'll try to reproduce the problem in my env and will write back then. This would definitely take more than one week :) |
Great, let me know if I can be of any assistance in this
|
Great feature request! Really looking forward to it! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there!
Sorry for taking so long with reviewing this, we've been focusing our energies on more internal facing work.
We appreciate the massive amount of work this was, but we'd like for some changes to be made before we merge this in. The two big areas to focus on are 1) listing different custom domain configurations rather than having websockets be a subsection, and 2) DRY-ing out the code. Also, this is a major version change, as it's a significant new feature and would break existing serverless.yml
configs if customDomain now required a list (although could make that backwards compatible!).
Thanks again for undertaking this, it's always great to see community members pitch in when we don't have the bandwidth to implement new features.
certificateName: '*.foo.com' | ||
createRoute53Record: true | ||
endpointType: 'regional' | ||
websockets: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way that we could just have customDomain
take in a list of domain name configurations rather than have a separate config section just for websockets? Could also help with closing #88 if implemented correctly, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is surely a more general solution. Smth like that will be backward compatible if the plugin assumes websocket: false
when omitted in the config:
custom:
customDomain:
- domainName: serverless.foo.com
stage: ci
basePath: api
certificateName: '*.foo.com'
createRoute53Record: true
endpointType: 'regional'
- domainName: serverless-ws.foo.com
stage: ci
certificateName: '*.foo.com'
createRoute53Record: true
endpointType: 'regional'
websocket: true
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, this is along the lines of we were thinking.
|
||
let credentials; | ||
|
||
if (this.enabled || this.enabledWs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking here, but not a fan of the naming convention something
and somethingWs
- maybe specify that something
refers to rest api endpoints as a direct contrast with somethingWs
?
* If the property's value is provided, this should be boolean, otherwise an exception is thrown. | ||
* If no customDomain.websockets object exists, websocket creation is disabled. | ||
*/ | ||
public evaluateEnabledWs(): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a lot of the reasoning behind why having a list of domain configurations might be better. There's little functional difference in this function as opposed to evaluateEnabled()
- it just searches for the enabled
parameter in the websocket
section. This is repeated throughout the PR, and having a list of domain configs would make the code more DRY.
/** | ||
* Returns information about custom domain name registered in ApiGatewayV2 | ||
*/ | ||
public async getDomainInfoWs(): Promise<DomainInfoWs> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing in this function as above.
Maybe try consider having the actual API call to ApiGatewayV2 be abstracted out? i.e. have a function that takes in the endpoint type [rest vs websocket] and possibly the AWS resource [apigateway vs apigatewayv2], and function call [getDomainName]. It would cut down on the duplication of functions that largely did the same thing, just made different api calls.
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "serverless-domain-manager", | |||
"version": "3.2.6", | |||
"version": "3.3.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely a major version bump, this is a 4.0.0
change. This is a huge lift, thanks for undertaking it.
Hi @captainsidd , thanks for the insightful review! I purposefully ignored the DRY aspect in the first PR iteration in order to preserve existing test functionality, but more coherent code would be very nice for sure. I'll try to reconsider the config structure at first and will get in touch with you a little later. Update: I'm working on my thesis now, thus the refactoring will take some time... |
Anything we can do to help with this issue? 👍 |
Would anyone here be opposed to me making the necessary changes? My plan was to just fork the work @pavel-ignatiev has done, and make the changes requested by @captainsidd. Which would be
I can knock it out in no time so just me know. Thanks! |
@kenpachiii Absolutely no objections here, this would be extremely helpful! |
I made the changes. Plus some others here. #250 |
No update ? |
Can we help with the review? Really looking forward to seeing this get merged |
Any update on this, really looking forward to use it :) |
I'm closing this PR because I believe it's been implemented with #319. If you feel this PR is still needed then feel free to reopen it. |
Fixes #207
Description of Issue Fixed
This feature enhances the plugin with following functionality:
From the user perspective, it allows you to add an independent Serverless configuration for a second custom domain which will be mapped on the deployed websocket API (see also modified
README.md
in the head repository).Here is an example of the new configuration:
As stated in the
README.md
, thewebsockets
part can be omitted entirely here but if it is present, the propertywebsockets.domainName
has to be set.The property
websockets.endpointType
can be set to arbitrary value but the regional endpoint type is enforced in the code due to missing AWS support for EDGE optimized websocket endpoints.As far as I'm concerned, this isn't possible to resolve both HTTP and websocket requests on a DNS level for the same custom domain, therefore the both custom domain names have to be explicitly different.
Changes proposed in this pull request:
New wrapper class
DomainInfoWs
for the custom domain information provided by AWS API Gateway V2DomainInfo
Modifications in
types.ts
ServerlessInstance
is extended by the nested objectservice.custom.customDomain.websockets
providers.aws.sdk.ApiGatewayV2
property (note the spelling here!)Modifications in
index.ts
DomainInfoWs
is importedServerlessCustomDomain
is extended by properties which are specific for websocket custom domain name creation - reusing existing properties could be possible in some cases (ACM) but this would break backward compatibility in a general case (EDGE vs regional endpoints etc.)initializeVariables
checks which of both custom domains are enabled; if at least one custom domain is enabled, Route53 and CloudFormation client instances are created; the remaining variables are initialized separately for both custom domains if they are enabled respectivelyinitializeVariables
shows a CLI message (besides of Serverless error thrown by another function) if a custom domain is enabled but no domain name is provided in the configurationevaluateEnabled
=>evaluateEnabledWs
printDomainSummary
=>printDomainSummaryWs
createDomain
=>createDomainWs
getDomainInfo
=>getDomainInfoWs
getCertArn
=>getCertArnWs
createCustomDomain
=>createCustomDomainWs
changeResourceRecordSet
=>changeResourceRecordSetWs
deleteDomain
=>deleteDomainWs
deleteCustomDomain
=>deleteCustomDomainWs
addOutputs
=>addOutputsWs
(still not working but not critical for the domain creation)getRoute53HostedZoneId
=>getRoute53HostedZoneIdWs
domainType
anddomainName
as arguments, which I didn't implement in this PRgetWssApiId
to retrieve the websocket API ID from CloudFormationgetApiMappingWs
looks for existing API mappings for a given domain name and websocket API IDcreateApiMappingWs
creates new API mapping using API Gateway V2 for a given domain nameupdateApiMappingWs
updates an existing API mapping if found bygetApiMappingWs
deleteApiMappingWs
deletes an existing API mapping as a part ofremoveMappings
lifecycle functionsetupApiMappingWs
creates a new or updates an existing API as a part ofsetupMappings
lifecycle functionapigatewayv2.createApiMapping()
andapigatewayv2.updateApiMapping
acceptApiMappingKey
as an optional parameter. I didn't find any sensible documentation about this parameter before and thus it is currently hardcoded as an empty stringprintDomainSummaryWs
additionally prints the Hosted Zone Id of the websocket domain by analogy with Add more information to domain summary #230, the summaries for both REST and websocket domains are separated by "---" string nowUnit tests (
index.test.ts
)constructPlugin
functionconstructPlugin.serverless.service.custom.customDomain
by a nestedwebsockets
propertyconstructPlugin
call to contain an emptywebsockets: {}
objectregional
by default even if not configured at alltest