From 84f31c529754ad73f7d4321b0e5fdaf211e81fc9 Mon Sep 17 00:00:00 2001 From: Aryaman Dhingra Date: Fri, 2 Aug 2024 13:44:53 -0400 Subject: [PATCH] feat: add optional name param to httpRequest DX-634 --- packages/io-ts-http/src/combinators.ts | 6 +-- packages/io-ts-http/src/httpRequest.ts | 4 +- packages/io-ts-http/test/httpRequest.test.ts | 39 +++++++++++++++++++- packages/io-ts-http/test/utils.ts | 5 +++ 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/packages/io-ts-http/src/combinators.ts b/packages/io-ts-http/src/combinators.ts index 180fb927..2eff95fd 100644 --- a/packages/io-ts-http/src/combinators.ts +++ b/packages/io-ts-http/src/combinators.ts @@ -1,4 +1,4 @@ -import { pipe } from 'fp-ts/pipeable'; +import { pipe } from 'fp-ts/function'; import * as E from 'fp-ts/Either'; import * as R from 'fp-ts/Record'; import * as t from 'io-ts'; @@ -101,12 +101,12 @@ export const flattened = ( const innerProps = props[key]; flatProps = { ...flatProps, ...innerProps }; } - const flatCodec = t.exact(optionalized(flatProps)); + const flatCodec = t.exact(optionalized(flatProps), name); const nestedProps = R.map((innerProps: t.Props) => t.exact(optionalized(innerProps)))( props, ); - const nestedCodec = t.strict(nestedProps); + const nestedCodec = t.strict(nestedProps, name); return new t.Type( name, diff --git a/packages/io-ts-http/src/httpRequest.ts b/packages/io-ts-http/src/httpRequest.ts index ac3db2f2..b48bc2ec 100644 --- a/packages/io-ts-http/src/httpRequest.ts +++ b/packages/io-ts-http/src/httpRequest.ts @@ -52,8 +52,8 @@ type EmitPropsErrors

= { export function httpRequest< Props extends HttpRequestCombinatorProps & EmitPropsErrors, ->(props: Props) { - return flattened('httpRequest', { +>(props: Props, name?: string) { + return flattened(name ?? 'httpRequest', { query: {}, params: {}, ...(props as Omit), diff --git a/packages/io-ts-http/test/httpRequest.test.ts b/packages/io-ts-http/test/httpRequest.test.ts index 1567716a..bf170e94 100644 --- a/packages/io-ts-http/test/httpRequest.test.ts +++ b/packages/io-ts-http/test/httpRequest.test.ts @@ -1,10 +1,11 @@ import { describe, it } from 'node:test'; import { strict as assert } from 'node:assert'; - +import * as PathReporter from 'io-ts/lib/PathReporter'; import * as NEA from 'fp-ts/NonEmptyArray'; import * as t from 'io-ts'; import { nonEmptyArray, JsonFromString, NumberFromString } from 'io-ts-types'; -import { assertRight } from './utils'; + +import { assertLeft, assertRight } from './utils'; import { optional } from '../src/combinators'; import * as h from '../src/httpRequest'; @@ -138,4 +139,38 @@ describe('httpRequest', () => { // tslint:disable-next-line: no-unused-expression void _codec; }); + + it('Displays error with codec name on decode', () => { + const request = h.httpRequest( + { + params: {}, + query: { + foo: t.string, + }, + body: { + bar: t.number, + }, + }, + 'TestRequestWithCodecName', + ); + + const test = { + params: {}, + query: { + foo: 'hello', + }, + body: { + bar: 'world', + }, + }; + + const errors = assertLeft(request.decode(test)); + const validationErrors = PathReporter.failure(errors); + const validationMessage = validationErrors.join('\n'); + + assert( + validationMessage.includes('TestRequestWithCodecName'), + 'Expected error to include codec name', + ); + }); }); diff --git a/packages/io-ts-http/test/utils.ts b/packages/io-ts-http/test/utils.ts index d3d78ee7..52bb5aea 100644 --- a/packages/io-ts-http/test/utils.ts +++ b/packages/io-ts-http/test/utils.ts @@ -7,6 +7,11 @@ export const assertRight = E.getOrElseW(() => { throw new Error('Failed to decode object'); }); +export const assertLeft = (e: E.Either) => { + assert(E.isLeft(e), 'Expected a failure, got a success'); + return e.left; +}; + export const assertEncodes = (codec: t.Mixed, test: unknown, expected = test) => { const encoded = codec.encode(test); assert.deepEqual(encoded, expected);