airtasker/spot

Support Duplicate Header Keys

abonander opened this issue · 0 comments

Is your feature request related to a problem? Please describe.
I have a couple routes that swap a short-lived cookie for a long-lived one, which means two Set-Cookie headers:

export interface DeleteEmailConfirmCookie {
    /**
    * Unsets a cookie previously set by the route to submit a confirmation email (for registration and resetting the user's password)
    * so that it cannot be used again (accidentally or maliciously).
    */
    'Set-Cookie': 'X-Email-Confirm-Token=',
}

export interface NewSessionCookie {
    /**
    * Sets a new long-lived session cookie marking the user as logged in.
    */
    'Set-Cookie': 'X-Auth-Session=<session token>'
}

I was surprised to find that spot implicitly supports the & operator, however it didn't function as I wanted:

/**
 * Implements "Forgot Password?" functionality. Email must have previously been confirmed by another route.
 */
@endpoint({
    method: 'POST',
    path: '/v1/password'
})
class ResetPassword {
    @request
    request(@headers headers: EmailConfirmCookie, @body body: {
        /**
         * The new password to set for the user.
         */
        password: String
    }) {
    }

    /**
     * Returns no body but sets a session cookie flagging the user as logged in.
     *
     * Also deletes the `X-Email-Confirm-Token` cookie.
     */
    @response({status: 204})
    response(
        @headers headers: NewSessionCookie & DeleteEmailConfirmCookie) {
    }
}

The rendered docs only show the Set-Cookie key from DeleteEmailConfirmCookie.

Describe the solution you'd like
The solution I'm thinking of would be to allow providing an array/tuple of types, and spot can merge them internally:

    @response({status: 204})
    response(
        @headers headers: [NewSessionCookie, DeleteEmailConfirmCookie]) {
    }

Describe alternatives you've considered
I've no experience with decorators but I'm assuming making the & operator work as expected is not feasible, because that's a limitation due to language semantics.

Trying to make a new interface with extends NewSessionCookie, DeleteEmailConfirmCookie is rejected by Typescript for similar reasons.

What I also tried was two @headers declarations but that was rejected:

    @response({status: 204})
    response(
        @headers newSession: NewSessionCookie, @headers deleteEmailConfirm: DeleteEmailConfirmCookie) {
    }

I imagine it would be possible to make that work but I'm not sure I like how that looks anyway.

Additional context
Add any other context or screenshots about the feature request here.