Skip to content

Commit

Permalink
#124 Adding a QoL property to return value of inl…
Browse files Browse the repository at this point in the history
…ine endpoint specification, to make unit testing easy without extra
exports.
  • Loading branch information
stazz committed Jan 20, 2024
1 parent 6a60460 commit fea9d0e
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 25 deletions.
2 changes: 1 addition & 1 deletion endpoint-spec/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ty-ras/endpoint-spec",
"version": "2.1.0",
"version": "2.1.1",
"author": {
"name": "Stanislav Muhametsin",
"email": "346799+stazz@users.noreply.github.com",
Expand Down
5 changes: 3 additions & 2 deletions endpoint-spec/src/__test__/inline.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

import test from "ava";
import * as epValidation from "./endpoint-validation";
import inlineEndpoints, { SEEN_ARGS } from "./inline";
import inlineEndpoints, { SEEN_ARGS, endpoint, implementation } from "./inline";

test("Test that decorator-based builder works on class with instance methods", async (c) => {
c.plan(6);
c.plan(7);
const { endpoints } = inlineEndpoints;
c.deepEqual(
endpoints.length,
1,
"There must be exactly one endpoint created by application builder.",
);
c.true(endpoint.implementation === implementation);
await epValidation.validateEndpoint(c, endpoints[0], () => SEEN_ARGS);
});
27 changes: 17 additions & 10 deletions endpoint-spec/src/__test__/inline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,22 @@ const stateSpec = {
userId: false,
} as const satisfies StateSpecBase;

const endpoint = withURL.endpoint<protocol.SomeEndpoint>({})(
export const implementation: spec.InlineEndpointImplementation<
mp.DefaultStateHKT,
mp.ServerContext,
protocol.SomeEndpoint,
typeof stateSpec
> = (args) => {
SEEN_ARGS.push(args);
return {
body: "responseBody",
headers: {
responseHeader: "resHeader",
},
} as const;
};

export const endpoint = withURL.endpoint<protocol.SomeEndpoint>({})(
{
method: "GET",
responseBody: mp.responseBody(protocol.responseBody),
Expand All @@ -38,15 +53,7 @@ const endpoint = withURL.endpoint<protocol.SomeEndpoint>({})(
requestBody: app.requestBody(protocol.requestBody),
state: stateSpec,
},
(args) => {
SEEN_ARGS.push(args);
return {
body: "responseBody",
headers: {
responseHeader: "resHeader",
},
} as const;
},
implementation,
);

export const SEEN_ARGS: Array<
Expand Down
59 changes: 49 additions & 10 deletions endpoint-spec/src/api.types/url.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,57 @@ export interface AddEndpointAsInline<
TProtocolSpec,
TStateSpec
>,
implementation: MethodForEndpoint<
GetMethodArgsGeneric<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>,
void,
GetMethodReturnType<TProtocolSpec>
implementation: InlineEndpointImplementation<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>,
): common.EndpointCreationArgLeafSingle;
): InlineEndpointAdditionResult<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>;
}

/**
* This type specializes {@link MethodForEndpoint} for callbacks which are not class methods but plain functions.
* @see AddEndpointAsInline
*/
export type InlineEndpointImplementation<
TStateHKT extends dataBE.StateHKTBase,
TServerContext,
TProtocolSpec extends protocol.ProtocolSpecCore<protocol.HttpMethod, unknown>,
TStateSpec extends dataBE.MaterializeStateSpecBase<TStateHKT>,
> = MethodForEndpoint<
GetMethodArgsGeneric<TStateHKT, TServerContext, TProtocolSpec, TStateSpec>,
void,
GetMethodReturnType<TProtocolSpec>
>;

/**
* This is return type of {@link AddEndpointAsInline}.
* It contains a quality-of-life property to access the implementation provided to {@link AddEndpointAsInline}.
* This is very useful e.g. in unit test situations to test the actual implementation.
*/
export interface InlineEndpointAdditionResult<
TStateHKT extends dataBE.StateHKTBase,
TServerContext,
TProtocolSpec extends protocol.ProtocolSpecCore<protocol.HttpMethod, unknown>,
TStateSpec extends dataBE.MaterializeStateSpecBase<TStateHKT>,
> extends common.EndpointCreationArgLeafSingle {
/**
* The value of `implementation` parameter passed to {@link AddEndpointAsInline}, as-is.
*/
implementation: InlineEndpointImplementation<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>;
}

/**
* This is function interface to create the decorator for class methods acting as BE endpoints.
*
Expand Down
25 changes: 23 additions & 2 deletions endpoint-spec/src/implementation/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ const newBuilderGenericImpl = <
TEndpointSpecAdditionalDataHKT,
api.GetURLData<TValidatorHKT, typeof args>
>["endpoint"] = (mdArgs) => (specArg, implementation) => {
const instance = new InlineEndpoint();
const instance = new InlineEndpoint(implementation);
addEndpointImplementation(
fromStateSpec,
processMethod,
Expand Down Expand Up @@ -846,4 +846,25 @@ const addEndpointImplementation = <
}
};

class InlineEndpoint {}
class InlineEndpoint<
TStateHKT extends dataBE.StateHKTBase,
TServerContext,
TProtocolSpec extends protocol.ProtocolSpecCore<protocol.HttpMethod, unknown>,
TStateSpec extends dataBE.MaterializeStateSpecBase<TStateHKT>,
> implements
api.InlineEndpointAdditionResult<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>
{
public constructor(
public readonly implementation: api.InlineEndpointImplementation<
TStateHKT,
TServerContext,
TProtocolSpec,
TStateSpec
>,
) {}
}

0 comments on commit fea9d0e

Please sign in to comment.