Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .changeset/forty-turtles-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
"@effect/platform": patch
---

add helper types for HttpApi

Examples:

```ts
const group1 = HttpApiGroup.make("Group1").add(
HttpApiEndpoint.get("Endpoint1")`/`
)
const group2 = HttpApiGroup.make("Group2").add(
HttpApiEndpoint.get("Endpoint2")`/`
)
const api = HttpApi.make("TestApi").add(group1).add(group2)

// ┌─── | HttpApiGroup<"Group1", HttpApiEndpoint<"Endpoint1", "GET">, never>
// | | HttpApiGroup<"Group2", HttpApiEndpoint<"Endpoint2", "GET">, never>
// ▼
type groups = HttpApi.HttpApi.Groups<typeof api>

// ┌─── HttpApiEndpoint<"Endpoint1", "GET">
// ▼
type endpoints = HttpApi.HttpApi.EndpointsWithGroupName<typeof api, "Group1">

// ┌─── HttpApiEndpoint.Handler<HttpApiEndpoint<"Endpoint1", "GET">, never, never>
// ▼
type handler = HttpApi.HttpApi.ExtractHandlerType<
typeof api,
"Group1",
"Endpoint1",
never,
never
>
```

the latter is useful when you want to extract the handler type of a specific endpoint within a group.
69 changes: 69 additions & 0 deletions packages/platform/dtslint/HttpApi.tst.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { HttpApiError } from "@effect/platform"
import { HttpApi, HttpApiEndpoint, HttpApiGroup } from "@effect/platform"
import { describe, expect, it } from "tstyche"

const group1 = HttpApiGroup.make("Group1").add(
HttpApiEndpoint.get("Endpoint1")`/`
)
const group2 = HttpApiGroup.make("Group2").add(
HttpApiEndpoint.get("Endpoint2")`/`
)
const api = HttpApi.make("TestApi").add(group1).add(group2)

describe("HttpApi", () => {
it("add", () => {
expect<typeof api>().type.toBe<
HttpApi.HttpApi<
"TestApi",
| HttpApiGroup.HttpApiGroup<"Group1", HttpApiEndpoint.HttpApiEndpoint<"Endpoint1", "GET">, never>
| HttpApiGroup.HttpApiGroup<"Group2", HttpApiEndpoint.HttpApiEndpoint<"Endpoint2", "GET">, never>,
HttpApiError.HttpApiDecodeError
>
>()
expect(api.add(HttpApiGroup.make("NewGroup"))).type.toBe<
HttpApi.HttpApi<
"TestApi",
| HttpApiGroup.HttpApiGroup<"Group1", HttpApiEndpoint.HttpApiEndpoint<"Endpoint1", "GET">, never>
| HttpApiGroup.HttpApiGroup<"Group2", HttpApiEndpoint.HttpApiEndpoint<"Endpoint2", "GET">, never>
| HttpApiGroup.HttpApiGroup<"NewGroup", never, never>,
HttpApiError.HttpApiDecodeError
>
>()
})

it("HttpApi.Groups", () => {
expect<HttpApi.HttpApi.Groups<typeof api>>().type.toBe<
| HttpApiGroup.HttpApiGroup<"Group1", HttpApiEndpoint.HttpApiEndpoint<"Endpoint1", "GET">, never>
| HttpApiGroup.HttpApiGroup<"Group2", HttpApiEndpoint.HttpApiEndpoint<"Endpoint2", "GET">, never>
>()
expect<HttpApiGroup.HttpApiGroup.Name<HttpApi.HttpApi.Groups<typeof api>>>().type.toBe<"Group1" | "Group2">()
})

it("HttpApi.EndpointsWithGroupName", () => {
expect<HttpApi.HttpApi.EndpointsWithGroupName<typeof api, "Group1">>().type.toBe<
HttpApiEndpoint.HttpApiEndpoint<"Endpoint1", "GET">
>()
expect<HttpApi.HttpApi.EndpointsWithGroupName<typeof api, "Group2">>().type.toBe<
HttpApiEndpoint.HttpApiEndpoint<"Endpoint2", "GET">
>()
expect<HttpApiEndpoint.HttpApiEndpoint.Name<HttpApi.HttpApi.EndpointsWithGroupName<typeof api, "Group1">>>().type
.toBe<
"Endpoint1"
>()
expect<HttpApiEndpoint.HttpApiEndpoint.Name<HttpApi.HttpApi.EndpointsWithGroupName<typeof api, "Group2">>>().type
.toBe<
"Endpoint2"
>()
})

it("HttpApi.ExtractHandlerType", () => {
expect<HttpApi.HttpApi.ExtractHandlerType<typeof api, "Group1", "Endpoint1">>()
.type.toBe<
HttpApiEndpoint.HttpApiEndpoint.Handler<HttpApiEndpoint.HttpApiEndpoint<"Endpoint1", "GET">, never, never>
>()
expect<HttpApi.HttpApi.ExtractHandlerType<typeof api, "Group2", "Endpoint2">>()
.type.toBe<
HttpApiEndpoint.HttpApiEndpoint.Handler<HttpApiEndpoint.HttpApiEndpoint<"Endpoint2", "GET">, never, never>
>()
})
})
33 changes: 33 additions & 0 deletions packages/platform/src/HttpApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,39 @@ export declare namespace HttpApi {
* @category models
*/
export type AnyWithProps = HttpApi<string, HttpApiGroup.HttpApiGroup.AnyWithProps, any, any>

/**
* @since 1.0.0
* @category models
*/
export type Groups<Api> = Api extends HttpApi<
infer _Id,
infer _Groups,
infer _E,
infer _R
> ? _Groups
: never

/**
* @since 1.0.0
* @category models
*/
export type EndpointsWithGroupName<Api extends Any, GroupName extends HttpApiGroup.HttpApiGroup.Name<Groups<Api>>> =
GroupName extends HttpApiGroup.HttpApiGroup.Name<Groups<Api>> ?
HttpApiGroup.HttpApiGroup.EndpointsWithName<Groups<Api>, GroupName>
: never

/**
* @since 1.0.0
* @category models
*/
export type ExtractHandlerType<
Api extends HttpApi.Any,
GroupName extends HttpApiGroup.HttpApiGroup.Name<Groups<Api>>,
EndpointName extends HttpApiEndpoint.HttpApiEndpoint.Name<EndpointsWithGroupName<Api, GroupName>>,
E = never,
R = never
> = HttpApiEndpoint.HttpApiEndpoint.HandlerWithName<EndpointsWithGroupName<Api, GroupName>, EndpointName, E, R>
}

const Proto = {
Expand Down
6 changes: 4 additions & 2 deletions packages/platform/src/HttpApiBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,10 @@ export const handler = <
Groups extends HttpApiGroup.HttpApiGroup.Any,
ApiError,
ApiR,
const GroupName extends Groups["identifier"],
const Name extends HttpApiGroup.HttpApiGroup.EndpointsWithName<Groups, GroupName>["name"],
const GroupName extends HttpApiGroup.HttpApiGroup.Name<Groups>,
const Name extends HttpApiEndpoint.HttpApiEndpoint.Name<
HttpApiGroup.HttpApiGroup.EndpointsWithName<Groups, GroupName>
>,
R
>(
_api: HttpApi.HttpApi<ApiId, Groups, ApiError, ApiR>,
Expand Down
4 changes: 2 additions & 2 deletions packages/platform/src/HttpApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export type Client<Groups extends HttpApiGroup.Any, E, R> = Simplify<
& {
readonly [Group in Extract<Groups, { readonly topLevel: false }> as HttpApiGroup.Name<Group>]: Client.Group<
Group,
Group["identifier"],
HttpApiGroup.Name<Groups>,
E,
R
>
Expand All @@ -51,7 +51,7 @@ export declare namespace Client {
* @since 1.0.0
* @category models
*/
export type Group<Groups extends HttpApiGroup.Any, GroupName extends Groups["identifier"], E, R> =
export type Group<Groups extends HttpApiGroup.Any, GroupName extends HttpApiGroup.Name<Groups>, E, R> =
[HttpApiGroup.WithName<Groups, GroupName>] extends
[HttpApiGroup<infer _GroupName, infer _Endpoints, infer _GroupError, infer _GroupErrorR>] ? {
readonly [Endpoint in _Endpoints as HttpApiEndpoint.Name<Endpoint>]: Method<
Expand Down
41 changes: 28 additions & 13 deletions packages/platform/src/HttpApiEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,19 +509,25 @@ export declare namespace HttpApiEndpoint {
* @since 1.0.0
* @category models
*/
export type WithName<Endpoints extends Any, Name extends string> = Extract<Endpoints, { readonly name: Name }>
export type WithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = Extract<
Endpoints,
{ readonly name: Name }
>

/**
* @since 1.0.0
* @category models
*/
export type ExcludeName<Endpoints extends Any, Name extends string> = Exclude<Endpoints, { readonly name: Name }>
export type ExcludeName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = Exclude<
Endpoints,
{ readonly name: Name }
>

/**
* @since 1.0.0
* @category models
*/
export type HandlerWithName<Endpoints extends Any, Name extends string, E, R> = Handler<
export type HandlerWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>, E, R> = Handler<
WithName<Endpoints, Name>,
E,
R
Expand All @@ -531,41 +537,50 @@ export declare namespace HttpApiEndpoint {
* @since 1.0.0
* @category models
*/
export type HandlerRawWithName<Endpoints extends Any, Name extends string, E, R> = HandlerRaw<
WithName<Endpoints, Name>,
E,
R
>
export type HandlerRawWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>, E, R> =
HandlerRaw<
WithName<Endpoints, Name>,
E,
R
>

/**
* @since 1.0.0
* @category models
*/
export type SuccessWithName<Endpoints extends Any, Name extends string> = Success<WithName<Endpoints, Name>>
export type SuccessWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = Success<
WithName<Endpoints, Name>
>

/**
* @since 1.0.0
* @category models
*/
export type ErrorWithName<Endpoints extends Any, Name extends string> = Error<WithName<Endpoints, Name>>
export type ErrorWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = Error<
WithName<Endpoints, Name>
>

/**
* @since 1.0.0
* @category models
*/
export type ContextWithName<Endpoints extends Any, Name extends string> = Context<WithName<Endpoints, Name>>
export type ContextWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = Context<
WithName<Endpoints, Name>
>

/**
* @since 1.0.0
* @category models
*/
export type ErrorContextWithName<Endpoints extends Any, Name extends string> = ErrorContext<WithName<Endpoints, Name>>
export type ErrorContextWithName<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>> = ErrorContext<
WithName<Endpoints, Name>
>

/**
* @since 1.0.0
* @category models
*/
export type ExcludeProvided<Endpoints extends Any, Name extends string, R> = Exclude<
export type ExcludeProvided<Endpoints extends Any, Name extends HttpApiEndpoint.Name<Endpoints>, R> = Exclude<
R,
| HttpRouter.HttpRouter.DefaultServices
| HttpRouter.HttpRouter.Provided
Expand Down
15 changes: 10 additions & 5 deletions packages/platform/src/HttpApiGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ export declare namespace HttpApiGroup {
* @since 1.0.0
* @category models
*/
export type WithName<Group, Name extends string> = Extract<Group, { readonly identifier: Name }>
export type WithName<Group extends Any, Name extends HttpApiGroup.Name<Group>> = Extract<
Group,
{ readonly identifier: Name }
>

/**
* @since 1.0.0
Expand All @@ -198,7 +201,9 @@ export declare namespace HttpApiGroup {
* @since 1.0.0
* @category models
*/
export type EndpointsWithName<Group extends Any, Name extends string> = Endpoints<WithName<Group, Name>>
export type EndpointsWithName<Group extends Any, Name extends HttpApiGroup.Name<Group>> = Endpoints<
WithName<Group, Name>
>

/**
* @since 1.0.0
Expand Down Expand Up @@ -227,7 +232,7 @@ export declare namespace HttpApiGroup {
* @since 1.0.0
* @category models
*/
export type ErrorWithName<Group extends Any, Name extends string> = Error<WithName<Group, Name>>
export type ErrorWithName<Group extends Any, Name extends HttpApiGroup.Name<Group>> = Error<WithName<Group, Name>>

/**
* @since 1.0.0
Expand Down Expand Up @@ -271,13 +276,13 @@ export declare namespace HttpApiGroup {
* @since 1.0.0
* @category models
*/
export type ContextWithName<Group extends Any, Name extends string> = Context<WithName<Group, Name>>
export type ContextWithName<Group extends Any, Name extends HttpApiGroup.Name<Group>> = Context<WithName<Group, Name>>

/**
* @since 1.0.0
* @category models
*/
export type MiddlewareWithName<Group extends Any, Name extends string> = Middleware<
export type MiddlewareWithName<Group extends Any, Name extends HttpApiGroup.Name<Group>> = Middleware<
WithName<Group, Name>
>
}
Expand Down