Skip to content

Commit d96a1a4

Browse files
author
Martin Pirkl
authored
Merge pull request #207 from enter-at/feat/request-timeout-error
Request timeout error
2 parents 9406efc + e581bdb commit d96a1a4

9 files changed

Lines changed: 272 additions & 61 deletions

package-lock.json

Lines changed: 0 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/error/RequestTimeoutError.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {LambdaHandlerError} from './LambdaHandlerError';
2+
3+
export class RequestTimeoutError extends LambdaHandlerError {
4+
public readonly name = 'RequestTimeoutError';
5+
}

src/error/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export {InternalServerError} from './InternalServerError';
55
export {NotFoundError} from './NotFoundError';
66
export {FormatError} from './FormatError';
77
export {ValidationError} from './ValidationError';
8+
export {RequestTimeoutError} from './RequestTimeoutError';
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { APIGatewayProxyHandler } from "./APIGatewayProxyHandler";
2+
import { APIGatewayProxyEvent, Handler, APIGatewayProxyResult, Context } from "aws-lambda";
3+
import {
4+
RequestTimeoutError,
5+
InternalServerError,
6+
NotFoundError,
7+
ValidationError,
8+
FormatError,
9+
ForbiddenError,
10+
BadRequestError,
11+
} from "../error";
12+
import * as ContextFactory from "../../test/fixtures/ContextFactory";
13+
import * as APIGatewayProxyEventFactory from "../../test/fixtures/APIGatewayProxyEventFactory";
14+
15+
describe(APIGatewayProxyHandler.name, () => {
16+
let handler: APIGatewayProxyHandler;
17+
let context: Context;
18+
let event: APIGatewayProxyEvent;
19+
20+
beforeEach(() => {
21+
handler = new APIGatewayProxyHandler();
22+
context = ContextFactory.factory();
23+
event = APIGatewayProxyEventFactory.factory();
24+
});
25+
26+
it("handles BadRequestError response correctly", async () => {
27+
const fn = handler.wrapper(() => {
28+
throw new BadRequestError("BadRequestError message");
29+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
30+
31+
const result = await fn(event, context, () => {});
32+
expect(result).toMatchSnapshot();
33+
});
34+
35+
it("handles ForbiddenError response correctly", async () => {
36+
const fn = handler.wrapper(() => {
37+
throw new ForbiddenError("ForbiddenError message");
38+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
39+
40+
const result = await fn(event, context, () => {});
41+
expect(result).toMatchSnapshot();
42+
});
43+
44+
it("handles FormatError response correctly", async () => {
45+
const fn = handler.wrapper(() => {
46+
throw new FormatError("FormatError message");
47+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
48+
49+
const result = await fn(event, context, () => {});
50+
expect(result).toMatchSnapshot();
51+
});
52+
53+
it("handles InternalServerError response correctly", async () => {
54+
const fn = handler.wrapper(() => {
55+
throw new InternalServerError("InternalServerError message");
56+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
57+
58+
const result = await fn(event, context, () => {});
59+
expect(result).toMatchSnapshot();
60+
});
61+
62+
it("handles NotFoundError response correctly", async () => {
63+
const fn = handler.wrapper(() => {
64+
throw new NotFoundError("NotFoundError message");
65+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
66+
67+
const result = await fn(event, context, () => {});
68+
expect(result).toMatchSnapshot();
69+
});
70+
71+
it("handles RequestTimeoutError response correctly", async () => {
72+
const fn = handler.wrapper(() => {
73+
throw new RequestTimeoutError("RequestTimeoutError message");
74+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
75+
76+
const result = await fn(event, context, () => {});
77+
expect(result).toMatchSnapshot();
78+
});
79+
80+
it("handles ValidationError response correctly", async () => {
81+
const fn = handler.wrapper(() => {
82+
throw new ValidationError("ValidationError message");
83+
}) as Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
84+
85+
const result = await fn(event, context, () => {});
86+
expect(result).toMatchSnapshot();
87+
});
88+
});

src/handler/APIGatewayProxyHandler.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
1-
import {APIGatewayProxyEvent, APIGatewayProxyResult} from 'aws-lambda';
2-
import {BadRequestError, FormatError, NotFoundError, ValidationError} from '../error';
3-
import {ContentTypeHeader, CORSHeader, IHeader, IHeaders} from '../header';
4-
import {badRequest, IAPIGatewayResponse, internalServerError, noContent, notFound, ok} from '../response';
5-
import {BaseHandler, IBaseHandlerArguments} from './BaseHandler';
1+
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
2+
import { BadRequestError, FormatError, NotFoundError, ValidationError, RequestTimeoutError, ForbiddenError } from '../error';
3+
import { ContentTypeHeader, CORSHeader, IHeader, IHeaders } from '../header';
4+
import {
5+
badRequest,
6+
IAPIGatewayResponse,
7+
internalServerError,
8+
noContent,
9+
notFound,
10+
ok,
11+
requestTimeout,
12+
forbidden,
13+
} from '../response';
14+
import { BaseHandler, IBaseHandlerArguments } from './BaseHandler';
615

716
export interface IAPIGatewayProxyHandlerArguments extends IBaseHandlerArguments {
817
cors?: CORSHeader;
918
}
1019

1120
export class APIGatewayProxyHandler extends BaseHandler {
12-
1321
private static handleError(err: Error): IAPIGatewayResponse {
1422
if (err instanceof NotFoundError) {
1523
return notFound(err.details);
1624
}
1725
if (err instanceof BadRequestError || err instanceof FormatError || err instanceof ValidationError) {
1826
return badRequest(err.details);
1927
}
28+
if (err instanceof RequestTimeoutError) {
29+
return requestTimeout(err.details);
30+
}
31+
if (err instanceof ForbiddenError) {
32+
return forbidden(err.details);
33+
}
2034
return internalServerError();
2135
}
2236

@@ -50,7 +64,7 @@ export class APIGatewayProxyHandler extends BaseHandler {
5064
return event;
5165
} catch (err) {
5266
if (err instanceof FormatError) {
53-
throw new FormatError([{body: [err.details]}]);
67+
throw new FormatError([{ body: [err.details] }]);
5468
}
5569
throw err;
5670
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`APIGatewayProxyHandler handles BadRequestError response correctly 1`] = `
4+
Object {
5+
"body": "{\\"errors\\":[{\\"name\\":\\"BadRequestError\\",\\"details\\":\\"BadRequestError message\\"}]}",
6+
"headers": Object {
7+
"Access-Control-Allow-Credentials": true,
8+
"Access-Control-Allow-Origin": "*",
9+
"Content-Type": "application/json",
10+
},
11+
"statusCode": 400,
12+
}
13+
`;
14+
15+
exports[`APIGatewayProxyHandler handles ForbiddenError response correctly 1`] = `
16+
Object {
17+
"body": "{\\"errors\\":[{\\"name\\":\\"ForbiddenError\\",\\"details\\":\\"ForbiddenError message\\"}]}",
18+
"headers": Object {
19+
"Access-Control-Allow-Credentials": true,
20+
"Access-Control-Allow-Origin": "*",
21+
"Content-Type": "application/json",
22+
},
23+
"statusCode": 403,
24+
}
25+
`;
26+
27+
exports[`APIGatewayProxyHandler handles FormatError response correctly 1`] = `
28+
Object {
29+
"body": "{\\"errors\\":[{\\"name\\":\\"BadRequestError\\",\\"details\\":\\"FormatError message\\"}]}",
30+
"headers": Object {
31+
"Access-Control-Allow-Credentials": true,
32+
"Access-Control-Allow-Origin": "*",
33+
"Content-Type": "application/json",
34+
},
35+
"statusCode": 400,
36+
}
37+
`;
38+
39+
exports[`APIGatewayProxyHandler handles InternalServerError response correctly 1`] = `
40+
Object {
41+
"body": "{\\"errors\\":[{\\"name\\":\\"InternalServerError\\",\\"details\\":\\"InternalServerError\\"}]}",
42+
"headers": Object {
43+
"Access-Control-Allow-Credentials": true,
44+
"Access-Control-Allow-Origin": "*",
45+
"Content-Type": "application/json",
46+
},
47+
"statusCode": 500,
48+
}
49+
`;
50+
51+
exports[`APIGatewayProxyHandler handles NotFoundError response correctly 1`] = `
52+
Object {
53+
"body": "{\\"errors\\":[{\\"name\\":\\"NotFoundError\\",\\"details\\":\\"NotFoundError message\\"}]}",
54+
"headers": Object {
55+
"Access-Control-Allow-Credentials": true,
56+
"Access-Control-Allow-Origin": "*",
57+
"Content-Type": "application/json",
58+
},
59+
"statusCode": 404,
60+
}
61+
`;
62+
63+
exports[`APIGatewayProxyHandler handles RequestTimeoutError response correctly 1`] = `
64+
Object {
65+
"body": "{\\"errors\\":[{\\"name\\":\\"RequestTimeoutError\\",\\"details\\":\\"RequestTimeoutError message\\"}]}",
66+
"headers": Object {
67+
"Access-Control-Allow-Credentials": true,
68+
"Access-Control-Allow-Origin": "*",
69+
"Content-Type": "application/json",
70+
},
71+
"statusCode": 408,
72+
}
73+
`;
74+
75+
exports[`APIGatewayProxyHandler handles ValidationError response correctly 1`] = `
76+
Object {
77+
"body": "{\\"errors\\":[{\\"name\\":\\"BadRequestError\\",\\"details\\":\\"ValidationError message\\"}]}",
78+
"headers": Object {
79+
"Access-Control-Allow-Credentials": true,
80+
"Access-Control-Allow-Origin": "*",
81+
"Content-Type": "application/json",
82+
},
83+
"statusCode": 400,
84+
}
85+
`;

src/response.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {APIGatewayProxyResult} from 'aws-lambda';
22
import * as httpStatusCode from 'http-status-codes';
3-
import {BadRequestError, ForbiddenError, InternalServerError, LambdaHandlerError, NotFoundError} from './error';
3+
import {BadRequestError, ForbiddenError, InternalServerError, LambdaHandlerError, NotFoundError, RequestTimeoutError} from './error';
44

55
export interface IAPIGatewayResponse extends APIGatewayProxyResult {
66
body: any | undefined;
@@ -31,6 +31,11 @@ export function notFound(details: string | undefined): IAPIGatewayResponse {
3131
return buildResult<NotFoundError>(error, httpStatusCode.NOT_FOUND);
3232
}
3333

34+
export function requestTimeout(details: string | undefined): IAPIGatewayResponse {
35+
const error: RequestTimeoutError = new RequestTimeoutError(details);
36+
return buildResult<RequestTimeoutError>(error, httpStatusCode.REQUEST_TIMEOUT);
37+
}
38+
3439
export function ok<T>(result: T): IAPIGatewayResponse {
3540
return buildResult<T>(result, httpStatusCode.OK);
3641
}

0 commit comments

Comments
 (0)