getlift / lift

Expanding Serverless Framework beyond functions using the AWS CDK
MIT License
912 stars 109 forks source link

Pass origin path in REST scenario #364

Open jaulz opened 10 months ago

jaulz commented 10 months ago

Start from the Use-case

Unfortunately, I still need to use the REST protocol of the API Gateway (because v2 is not available in Switzerland) but that means that there is an ugly stage prefix in the URL (even with a custom domain). It would be nice if we could pass the origin path to the default origin of the CloudFront distribution so we can hide the stage prefix from end users.

Example Config

service: ${env:APP_ID}

frameworkVersion: '3'

configValidationMode: error

custom:
  rootDomain: example.org
  appName: Test
  appId: ${self:service}
  domain: ${self:custom.appId}.${self:custom.rootDomain}

plugins:
    - ./vendor/bref/bref
    - serverless-lift

provider:
    name: aws
    region: eu-central-2
    stage: production
    memorySize: 1024

package:
    # Files and directories to include/exclude from deployment
    patterns:
        - '!.husky/**'
        - '!.vscode/**'
        - '!.yarn/**'
        - '!node_modules/**'
        - '!public/storage'
        - '!resources/assets/**'
        - '!storage/**'
        - '!tests/**'

functions:
    # This function runs the Laravel website/API
    web:
        handler: public/index.php
        runtime: php-81-fpm
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        events:
            - http: 'ANY /'
            - http: 'ANY /{proxy+}'

constructs:
    app:
        type: server-side-website
        domain: ${self:custom.domain}
        certificate: ...
        # Either "rest" (v1) or "http" (v2, the default) but right now only v1 is available in Switzerland
        apiGateway: 'rest'
        assets:
            '/build/*': public/build
            '/css/*': public/css
            '/fonts/*': public/fonts
            '/js/*': public/js
            '/favicon.ico': public/favicon.ico
            '/robots.txt': public/robots.txt

resources:
    Resources:
        Storage:
            Type: AWS::S3::Bucket
        CacheTable:
            Type: AWS::DynamoDB::Table
            Properties:
                AttributeDefinitions: # only keys are defined here, other attributes are dynamic
                    -   AttributeName: id # adds a mandatory id field
                        AttributeType: S # the type of id is a string
                BillingMode: PAY_PER_REQUEST # billed for each request instead of paying for a constant capacity
                TimeToLiveSpecification: # deletes cache keys automatically based on a ttl field which contains a timestamp
                    AttributeName: ttl
                    Enabled: true
                KeySchema:
                    -   AttributeName: id
                        KeyType: HASH # the type of key, HASH means partition key (similar to primary keys in SQL)
        Route53Record:
            Type: AWS::Route53::RecordSet
            Properties:
                HostedZoneId: ...
                Name: ${self:custom.domain}
                Type: A
                AliasTarget:
                    HostedZoneId: Z2FDTNDATAQYW2 # Cloudfront Route53 HostedZoneId. This does not change.
                    DNSName: ${construct:app.cname}

Implementation Idea

As far as I could see we simply need to pass the name of the stage to the default origin (e.g. originPath: '/production',): https://github.com/getlift/lift/blob/fc3cfc364f2ee7c701a5e7c77da72e2b62f505b4/src/constructs/aws/ServerSideWebsite.ts#L135-L138

mnapoli commented 9 months ago

Interesting, it seems like a bug.

The issue is not clear enough, but what I interpret is that server-side-website used with REST API and a custom domain:

That is a bug. mydomain.com should work, the stage prefix should be invisible with a custom domain.

As far as I could see we simply need to pass the name of the stage to the default origin (e.g. originPath: '/production',):

That sounds indeed like a good solution, it's something we missed when implementing it originally. I think we would merge a PR that fixes that.

Note: HTTP APIs (v1) shouldn't be impacted.