summaryrefslogtreecommitdiff
path: root/u/server/filter/json.ts
blob: 527d483ec189ae0c56a789cbf84d872023638cd9 (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
43
44
45
46
47
48
49
50
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');
export const jsonModel =
    <MessageT>(jsonTransformer: JsonTransformer<MessageT>): RequestFilter<MessageT> =>
    (r: ITraceable<PenguenoRequest, ServerTrace>) =>
        r
            .bimap(TraceUtil.withFunctionTrace(jsonModel))
            .bimap(TraceUtil.withMetricTrace(ParseJsonMetric))
            .map((j) =>
                Either.fromFailableAsync<Error, MessageT>(<Promise<MessageT>>j.get().json()).then((either) =>
                    either.mapLeft((errReason) => {
                        j.trace.addTrace(LogLevel.WARN).trace(errReason);
                        return new PenguenoError('seems to be invalid JSON (>//<) can you fix?', 400);
                    }),
                ),
            )
            .peek(
                TraceUtil.promiseify((traceableEither) =>
                    traceableEither
                        .get()
                        .fold(({ isLeft }) =>
                            traceableEither.trace.trace(ParseJsonMetric[isLeft ? 'failure' : 'success']),
                        ),
                ),
            )
            .map(
                TraceUtil.promiseify((traceableEitherJson) =>
                    traceableEitherJson
                        .get()
                        .mapRight((j) => traceableEitherJson.move(j))
                        .flatMap(jsonTransformer),
                ),
            )
            .get();