| 61 | * @since 4.0.0 |
| 62 | */ |
| 63 | export const layer = <Id extends string, Groups extends HttpApiGroup.Constraint>( |
| 64 | api: HttpApi.HttpApi<Id, Groups>, |
| 65 | options?: { |
| 66 | readonly openapiPath?: `/${string}` | undefined |
| 67 | } |
| 68 | ): Layer.Layer< |
| 69 | never, |
| 70 | never, |
| 71 | | Etag.Generator |
| 72 | | HttpRouter.HttpRouter |
| 73 | | FileSystem |
| 74 | | HttpPlatform |
| 75 | | Path |
| 76 | | HttpApiGroup.ToService<Id, Groups> |
| 77 | > => |
| 78 | HttpRouter.use(Effect.fnUntraced(function*(router) { |
| 79 | const services = yield* Effect.context< |
| 80 | | Etag.Generator |
| 81 | | HttpRouter.HttpRouter |
| 82 | | FileSystem |
| 83 | | HttpPlatform |
| 84 | | Path |
| 85 | >() |
| 86 | const routes: Array<HttpRouter.Route<any, any>> = [] |
| 87 | const availableGroups = Array.from(services.mapUnsafe.keys()).filter((key) => |
| 88 | key.startsWith("effect/httpapi/HttpApiGroup/") |
| 89 | ) |
| 90 | const groups = Object.values(api.groups) as ReadonlyArray<HttpApiGroup.Top> |
| 91 | for (const group of groups) { |
| 92 | const groupRoutes = services.mapUnsafe.get(group.key)?.routes as Array<HttpRouter.Route<any, any>> |
| 93 | if (groupRoutes === undefined) { |
| 94 | const available = availableGroups.length === 0 ? "none" : availableGroups.join(", ") |
| 95 | return yield* Effect.die( |
| 96 | `HttpApiGroup "${group.identifier}" not found (key: "${group.key}"). Did you forget to provide HttpApiBuilder.group(api, "${group.identifier}", ...)? Available groups: ${available}` |
| 97 | ) |
| 98 | } |
| 99 | routes.push(...groupRoutes) |
| 100 | } |
| 101 | yield* (router.addAll(routes) as Effect.Effect<void>) |
| 102 | if (options?.openapiPath) { |
| 103 | const spec = OpenApi.fromApi(api) |
| 104 | yield* router.add("GET", options.openapiPath, Effect.succeed(Response.jsonUnsafe(spec))) |
| 105 | } |
| 106 | })) |
| 107 | |
| 108 | /** |
| 109 | * Create a `Layer` that implements all endpoints in an `HttpApi` group. |