summaryrefslogtreecommitdiff
path: root/lib/server/filter/json.ts
blob: bc53d47885342b84cac2d8edfc42d800cbd21b11 (plain)
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
import {
    Either,
    type IEither,
    type ITraceable,
    LogLevel,
    Metric,
    PenguenoError,
    type PenguenoRequest,
    type RequestFilter,
    type ServerTrace,
    TraceUtil,
} from '@emprespresso/pengueno';

export interface JsonTransformer<R, ParsedJson = unknown> {
    (json: ITraceable<ParsedJson, ServerTrace>): IEither<PenguenoError, R>;
}

const ParseJsonMetric = Metric.fromName('JsonParse').asResult();
export const jsonModel =
    <MessageT>(jsonTransformer: JsonTransformer<MessageT>): RequestFilter<MessageT> =>
    (r: ITraceable<PenguenoRequest, ServerTrace>) =>
        r
            .flatMap(TraceUtil.withFunctionTrace(jsonModel))
            .flatMap(TraceUtil.withMetricTrace(ParseJsonMetric))
            .map((j) =>
                Either.fromFailableAsync<Error, MessageT>(<Promise<MessageT>>j.get().req.json()).then((either) =>
                    either.mapLeft((errReason) => {
                        j.trace.traceScope(LogLevel.WARN).trace(errReason);
                        return new PenguenoError('seems to be invalid JSON (>//<) can you fix?', 400);
                    }),
                ),
            )
            .flatMapAsync(TraceUtil.promiseify(TraceUtil.traceResultingEither(ParseJsonMetric)))
            .map(
                TraceUtil.promiseify((traceableEitherJson) =>
                    traceableEitherJson
                        .get()
                        .mapRight((j) => traceableEitherJson.move(j))
                        .flatMap(jsonTransformer),
                ),
            )
            .get();