Skip to content

Commit

Permalink
refactor(digital-ocean): event based on correct option and removed ar…
Browse files Browse the repository at this point in the history
…gs parser strategy
  • Loading branch information
H4ad committed Aug 28, 2022
1 parent 0a29085 commit 38c61c4
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 121 deletions.
19 changes: 10 additions & 9 deletions src/@types/digital-ocean/digital-ocean-http-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { SingleValueHeaders } from '../headers';

/**
* The interface to represents the values of args send when someone calls a function using HTTP Endpoint.
* To be able to receive this event, inside your `project.yml`, instead of `web: true` change to `web: 'raw'`.
*
* {@link https://www.digitalocean.com/community/questions/digitalocean-functions-how-to-differentiate-query-params-from-body-params | Reference}
*
* @public
* @breadcrumb Types / Digital Ocean / DigitalOceanHttpEvent
Expand All @@ -16,17 +19,20 @@ export interface DigitalOceanHttpEvent {
*/
__ow_method: string;

/**
* The query porams of the request
*/
__ow_query: string;

/**
* The body of the request.
*
* @remarks From my tests it usually appears along with {@link __ow_isBase64Encoded}=true, so this body is always a base64 string.
*/
__ow_body?: string;

/**
* Indicates if body is base64, from my tests, when it appears, is always true.
* Indicates if body is base64 string
*/
__ow_isBase64Encoded?: true;
__ow_isBase64Encoded?: boolean;

/**
* The HTTP Headers of the request
Expand All @@ -37,9 +43,4 @@ export interface DigitalOceanHttpEvent {
* The path in the request
*/
__ow_path: string;

/**
* This could represent Query Params or Body Params, it's very strange behavior, but it is what it is.
*/
[key: string]: unknown;
}
122 changes: 10 additions & 112 deletions src/adapters/digital-ocean/http-function.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,92 +17,6 @@ import {

//#endregion

/**
* The result of parser strategy
*
* @breadcrumb Adapters / Digital Ocean / HttpFunctionAdapter
* @public
*/
export type ArgsParserResult = { path: string; body?: string };

/**
* The interface that represents strategy to parse `event` and get the `path` and `body` to forward to framework.
*
* @breadcrumb Adapters / Digital Ocean / HttpFunctionAdapter
* @public
*/
export interface ArgsParserStrategy {
/**
* The method to parse `event` and create path and get the body for the request.
*
* @param event - The event sent from DigitalOcean Functions
*/
parse: (event: DigitalOceanHttpEvent) => ArgsParserResult;
}

/**
* The default parser to get path and body.
*
* By default, if `__ow_body` is set, the params inside `event` will be forwarded to `queryParams`.
* If we didn't find any params, we return `__ow_body`.
* If `__ow_body` is not set, all params is forwarded inside `body`.
*
* @example
* ```typescript
* const strategy = new DefaultArgsParserStrategy();
* const __ow_path = '/test';
*
* // url called: /test?page=1, with body being an image
* console.log(strategy.parse({ __ow_path, __ow_body: 'base64', page: '1' }));
* // { path: '/test?page=1', body: 'base64' }
*
* // url called: /test, with body being an image
* console.log(strategy.parse({ __ow_path, __ow_body: 'base64' }));
* // { path: '/test', body: 'base64' }
*
* // url called: /test?page=1
* console.log(strategy.parse({ __ow_path, page: '1' }));
* // { path: '/test', body: '{"page":"1"}' }
*
* // url called: /test, with body being { test: true }
* console.log(strategy.parse({ __ow_path, test: true }));
* // { path: '/test', body: '{"test":true}' }
* ```
*
* @breadcrumb Adapters / Digital Ocean / HttpFunctionAdapter
* @public
*/
export class DefaultArgsParserStrategy implements ArgsParserStrategy {
/**
* {@inheritDoc}
*/
public parse(event: DigitalOceanHttpEvent): ArgsParserResult {
const paramKeys = Object.keys(event).filter(key => !key.startsWith('__ow'));

if (paramKeys.length === 0)
return { path: event.__ow_path, body: event.__ow_body };

const params: Record<string, any> = Object.entries(event)
.filter(([key]) => !key.startsWith('__ow'))
.reduce((acc, [key, value]) => {
acc[key] = value;

return acc;
}, {});

if (event.__ow_body) {
const path = getPathWithQueryStringParams(event.__ow_path, params);

return { path, body: event.__ow_body };
}

return {
path: event.__ow_path,
body: JSON.stringify(params),
};
}
}

/**
* The options to customize the {@link HttpFunctionAdapter}
*
Expand All @@ -116,14 +30,6 @@ export interface HttpFunctionAdapterOptions {
* @defaultValue ''
*/
stripBasePath?: string;

/**
* Because DigitalOcean don't tell us if param inside args is query param or body param, we need to guess.
* By default, we use {@link DefaultArgsParserStrategy} which prefers send params inside body instead query param.
*
* @defaultValue {@link DefaultArgsParserStrategy}
*/
argsParserStrategy?: ArgsParserStrategy;
}

/**
Expand Down Expand Up @@ -179,23 +85,15 @@ export class HttpFunctionAdapter
* {@inheritDoc}
*/
public getRequest(event: DigitalOceanHttpEvent): AdapterRequest {
if (!event.__ow_path) event.__ow_path = '/';

event.__ow_path = this.getPathStrippedPath(event.__ow_path);

const headers = event.__ow_headers;
const method = event.__ow_method;
const argsParserStrategy = getDefaultIfUndefined(
this.options?.argsParserStrategy,
new DefaultArgsParserStrategy(),
);
const { path, body: rawBody } = argsParserStrategy.parse(event);
const path = this.getPathFromEvent(event);

let body: Buffer | undefined;

if (rawBody) {
if (event.__ow_body) {
const [bufferBody, contentLength] = getEventBodyAsBuffer(
rawBody,
event.__ow_body,
!!event.__ow_isBase64Encoded,
);

Expand Down Expand Up @@ -259,21 +157,21 @@ export class HttpFunctionAdapter
//#region Protected Methods

/**
* Get path from event
* Get path from event with query strings
*
* @param path - The original path
* @param event - The event sent by digital ocean
*/
protected getPathStrippedPath(path: string): string {
protected getPathFromEvent(event: DigitalOceanHttpEvent): string {
const stripBasePath = getDefaultIfUndefined(
this.options?.stripBasePath,
'',
);

if (!stripBasePath) return path;

const replaceRegex = new RegExp(`^${stripBasePath}`);

return path.replace(replaceRegex, '');
const path = event.__ow_path.replace(replaceRegex, '');
const queryParams = event.__ow_query;

return getPathWithQueryStringParams(path, queryParams || {});
}

//#endregion
Expand Down

0 comments on commit 38c61c4

Please sign in to comment.