effect-http icon indicating copy to clipboard operation
effect-http copied to clipboard

TestClient generated using NodeTesting requires body, path, query, params as `any`

Open arijoon opened this issue 1 year ago • 3 comments

Example:

import { HttpServerRequest } from '@effect/platform'
import { Schema } from '@effect/schema'
import { Effect, flow, pipe } from 'effect'
import { Api, RouterBuilder, Security } from 'effect-http'
import { NodeTesting } from 'effect-http-node'

const AuthorizationSchema = Schema.Struct({ authorization: Schema.String })
export const authHeader = Security.make(
  pipe(
    HttpServerRequest.schemaHeaders(
      AuthorizationSchema,
    ),
  ),
  {
    myApiKey: {
      name: 'Authorization',
      type: 'apiKey',
      in: 'header',
      description: 'signed authorization token',
    },
  },
)

export const addAuthHeader = Api.setRequestHeaders(
  AuthorizationSchema,
)

export const addAuth = flow(
  Api.setSecurity(authHeader),
  addAuthHeader,
)

const testApi = Api.make().pipe(
  Api.addEndpoint(
    pipe(
      Api.get('test', '/test'),
      Api.setResponseBody(Schema.String),
      addAuth,
    ),
  ),
)

const app = RouterBuilder.make(testApi).pipe(
  RouterBuilder.handle(
    'test',
    _ => Effect.succeed('ok'),
  ),
  RouterBuilder.build,
)

const testClient = NodeTesting.make(app, testApi)

// Using the client:
Effect
  .gen(function*() {
    const client = yield* testClient
    const result = yield* client.test({
      headers: { authorization: 'somevalue' },
      body: undefined,
      query: undefined,
      path: undefined,
    })
  })

Seems like extra props in type show as any. Since they are not defined on the spec, they shouldn't be allowed image

Updated the code, it seems to come from the flow based addition of security

arijoon avatar Aug 01 '24 17:08 arijoon

Hey, I'm not able to reproduce. Please make sure there are no mismatching dependency versions in your package or other type errors. Otherwise, I'll need a repro to take a look.

import { Schema } from "@effect/schema"
import { Effect, pipe } from "effect"
import { Api, RouterBuilder } from "effect-http"
import { NodeTesting } from "effect-http-node"

const testApi = Api.make().pipe(
  Api.addEndpoint(
    pipe(
      Api.get("test", "/test"),
      Api.setResponseBody(Schema.String)
    )
  )
)

const app = RouterBuilder.make(testApi).pipe(
  RouterBuilder.handle(
    "test",
    () => Effect.succeed("ok")
  ),
  RouterBuilder.build
)

const testClient = NodeTesting.make(app, testApi)

// Using the client:
Effect.gen(function*() {
  const client = yield* testClient
  // test: (input: {}, map?: ((request: HttpClientRequest) => HttpClientRequest) | undefined) => Effect.Effect<string, ClientError<number>, never>
  const result = yield* client.test({})
  console.log(result)
})

sukovanej avatar Aug 01 '24 17:08 sukovanej

my appologies @sukovanej , It was coming from the Seucurity addition which I didn't have in the original example. Updated the example to include it. Using flow to compose it causes the type issue. Directly adding them without using flow works fine.

I'm unsure if this is a typescript limitation or the types can be improved to handle the case of using flow to perform partial composition as well

arijoon avatar Aug 02 '24 08:08 arijoon

I'll try to dig deeper, but it is very probably an issue with the flow. On the type level, once generics get involved (which is the case in here) you need to be careful with the flow because things can go downhill pretty easily.

sukovanej avatar Aug 03 '24 21:08 sukovanej