Skip to content

Patches

Harry Rabin edited this page Aug 12, 2022 · 13 revisions

Patches are designed to separate logic between accepting the request and generating the response. The pattern we recommend is that your entry function is in charge of parsing URL parameters and query strings, setting defaults, etc. and putting all necessary data in one place for your exit function to use, so that the exit function is guaranteed to succeed.

In fact, we've included an easy way to guarantee data safety for exit. entry returns a generic type, though you may not initially realize it because it defaults to void.

A more realistic and data-safe version of the UserPage example in the template project might look something like this:

interface UserPageData {
    username: string;
    followerCount: number;
    bio: string;
}

class UserPage extends Patch<UserPageData> {
    async entry(req: PBRequest): Promise<UserPageData> {
        this.parseRouteParams(req);
        
        const username = this.routeParameters.username;
        const data = await database.users.get(username);
        if (data === null)
            throw PBUtils.TemplateResponse("user-not-found", {user: username});
        
        return  {
            username: username,
            followerCount: data.followerCount,
            bio: data.bio
        }
    }

    exit(data: UserPageData): Response {
        return PBUtils.TemplateResponse('user-page', data);
    }
}

User-defined methods

Required: entry(req: PBRequest): Data | Promise<Data>

...

Required: exit(data: Data): Response | Promise<Response>

...

Optional: intercept(req: PBRequest): boolean

Note: there is a related public function called __safe_intercept, which should not be overridden or used by you. This is only used internally by PatchBay.

This function is generally for edge cases, but can be very useful. It's a special function that allows the Patch to return control to the router and fall through before it runs. Think of the name as a question: if you want it to intercept and hand control back to the parent, return true; if you want it to continue without intercepting, return false.

You can use this inside intercept, but the properties will not be preserved from the last time the patch ran, nor will they be preserved for the next run, so use it carefully and sparingly.

One use of this function is to have separate patches for different HTTP methods on the same route:

class GetTweet extends Patch {
    intercept(req: PBRequest): boolean {
        return req.method !== "GET"
    }
    // ...
}

class PostTweet extends Patch {
    intercept(req: PBRequest): boolean {
        return req.method !== "POST"
    }
    // ...
}

class CatchallTweet extends Patch {
    // leave intercept undefined
    // ...
}

// Then the router's patchables should look like:
[
    new GetTweet("/tweet"),
    new PostTweet("/tweet"),
    new CatchallTweet("/tweet")
]

Inherited properties/methods

parseRouteParams(req: PBReques)