forked from zenstackhq/zenstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi-handler.service.ts
More file actions
56 lines (52 loc) · 2.5 KB
/
api-handler.service.ts
File metadata and controls
56 lines (52 loc) · 2.5 KB
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
import { DbClientContract } from '@zenstackhq/runtime';
import { HttpException, Inject, Injectable, Scope } from "@nestjs/common";
import { HttpAdapterHost, REQUEST } from "@nestjs/core";
import { loadAssets } from "../shared";
import { RPCApiHandler } from '../api/rpc';
import { ENHANCED_PRISMA } from "./zenstack.constants";
import { ApiHandlerOptions } from './interfaces';
/**
* The ZenStack API handler service for NestJS. The service is used to handle API requests
* and forward them to the ZenStack API handler. It is platform agnostic and can be used
* with any HTTP adapter.
*/
@Injectable({ scope: Scope.REQUEST })
export class ApiHandlerService {
constructor(
private readonly httpAdapterHost: HttpAdapterHost,
@Inject(ENHANCED_PRISMA) private readonly prisma: DbClientContract,
@Inject(REQUEST) private readonly request: unknown
) { }
async handleRequest(options?: ApiHandlerOptions): Promise<unknown> {
const { modelMeta, zodSchemas } = loadAssets(options || {});
const requestHandler = options?.handler || RPCApiHandler();
const hostname = this.httpAdapterHost.httpAdapter.getRequestHostname(this.request);
const requestUrl = this.httpAdapterHost.httpAdapter.getRequestUrl(this.request);
// prefix with http:// to make a valid url accepted by URL constructor
const url = new URL(`http://${hostname}${requestUrl}`);
const method = this.httpAdapterHost.httpAdapter.getRequestMethod(this.request);
const path = options?.baseUrl && url.pathname.startsWith(options.baseUrl) ? url.pathname.slice(options.baseUrl.length) : url.pathname;
const searchParams = url.searchParams;
const query = Object.fromEntries(searchParams);
const requestBody = (this.request as { body: unknown }).body;
const response = await requestHandler({
method,
path,
query,
requestBody,
prisma: this.prisma,
modelMeta,
zodSchemas,
logger: options?.logger,
});
// handle handler error
// if response code >= 400 throw nestjs HttpException
// the error response will be generated by nestjs
// caller can use try/catch to deal with this manually also
if (response.status >= 400) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
throw new HttpException(response.body as Record<string, any>, response.status)
}
return response.body
}
}