All files / src route.ts

100% Statements 37/37
100% Branches 10/10
100% Functions 9/9
100% Lines 37/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112        9x       9x                             155x 155x 155x   155x 155x   155x 155x       48x 1x     47x 29x     18x 3x     15x               5x 5x   5x             5x       23x   23x           5x 5x 5x 5x   5x 3x     2x   2x 2x   2x     2x       2x       5x       5x       9x  
import HTTP from 'http';
 
import Repository from 'repository';
import HttpMethod from 'http/enum/method';
import PathParser from 'route/utility/path-parser';
import ContentType from 'http/enum/content-type';
import UrlParameters from 'http/type/url-parameters';
import EndpointConstructor from 'interface/endpoint-constructor';
import getAcceptedContentTypes from 'http/utility/get-accepted-content-types';
 
class Route {
	private content_type: ContentType;
	private method: HttpMethod;
	private endpoint_constructor: EndpointConstructor;
	private parameter_keys: string[];
	private regex: RegExp;
 
	public constructor(
		content_type: ContentType,
		method: HttpMethod,
		path: string,
		endpoint_constructor: EndpointConstructor
	) {
		this.content_type = content_type;
		this.method = method;
		this.endpoint_constructor = endpoint_constructor;
 
		const parser = new PathParser(path);
		const parsed_path = parser.parse();
 
		this.regex = parsed_path.regex;
		this.parameter_keys = parsed_path.parameter_keys;
	}
 
	public accepts(request: HTTP.IncomingMessage): boolean {
		if (request.url === undefined) {
			return false;
		}
 
		if (this.regex.test(request.url) === false) {
			return false;
		}
 
		if (this.method !== request.method) {
			return false;
		}
 
		return this.matchesContentType(request);
	}
 
	public serve(
		request: HTTP.IncomingMessage,
		response: HTTP.ServerResponse,
		repository: Repository
	): void {
		const Constructor = this.getEndpointConstructor();
		const url_parameters = this.getUrlParametersForRequest(request);
 
		const endpoint = new Constructor(
			request,
			response,
			url_parameters,
			repository
		);
 
		endpoint.serve();
	}
 
	protected matchesContentType(request: HTTP.IncomingMessage): boolean {
		const content_types = getAcceptedContentTypes(request);
 
		return content_types.includes(this.content_type);
	}
 
	private getUrlParametersForRequest(
		request: HTTP.IncomingMessage
	): UrlParameters {
		const url = request.url || '/';
		const regex = this.getRegex();
		const match = url.match(regex);
		const result: UrlParameters = {};
 
		if (match === null) {
			return result;
		}
 
		const parameter_keys = this.getParameterKeys();
 
		parameter_keys.forEach((parameter_key, index) => {
			const parameter_value = match[index + 1];
 
			result[parameter_key] = parameter_value;
		});
 
		return result;
	}
 
	private getParameterKeys(): string[] {
		return this.parameter_keys;
	}
 
	private getRegex(): RegExp {
		return this.regex;
	}
 
	private getEndpointConstructor(): EndpointConstructor {
		return this.endpoint_constructor;
	}
}
 
export default Route;