Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schema-based config descriptions #2763

Closed
vecerek opened this issue May 16, 2024 · 3 comments
Closed

Schema-based config descriptions #2763

vecerek opened this issue May 16, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@vecerek
Copy link
Contributor

vecerek commented May 16, 2024

What is the problem this feature would solve?

Right now, if there is a more complex config, for example a file containing some JSON configuration, the caller has to first load the config, then parse it:

import { Schema } from "@effect/schema"
import { Config, Effect } from "effect"

const MyJsonSchema = Schema.parseJson(
  Schema.Struct({
    a: Schema.String
  })
)

const parseJsonConfig = Schema.decode(MyJsonSchema, { errors: "all" })

Effect.gen(function* () {
  const jsonConfig = yield* Config.string("MY_JSON_CONFIG")
  const parsedConfig = yield* parseJsonConfig(jsonConfig)
  // ...
})

What is the feature you are proposing to solve the problem?

I'd like to have an API that combines the loading of the config with its parsing. Something like:

// config module

// for simplicity's sake, otherwise it could be a dual API
export declare const schema: <const C extends string, A>(
  name: C,
  schema: Schema.Schema<A, string>,
) => Config.Config<A>

and then at the call site:

import { Schema } from "@effect/schema"
import * as Config from "./config.js"

const MyJsonSchema = Schema.parseJson(
  Schema.Struct({
    a: Schema.String
  })
)

Effect.gen(function* () {
  const parsedConfig = yield* Config.schema("MY_JSON_CONFIG", MyJsonSchema)
  // ...
})

What alternatives have you considered?

No response

@vecerek vecerek added the enhancement New feature or request label May 16, 2024
@vecerek
Copy link
Contributor Author

vecerek commented May 16, 2024

Here's a naive implementation:

import * as Schema from "@effect/schema/Schema"
import { formatErrorSync } from "@effect/schema/TreeFormatter"
import { Config, ConfigError, Either } from "effect"
import { flow } from "effect/Function"

export const schema = <const C extends string, A>(
  name: C,
  schema: Schema.Schema<A, string>,
): Config.Config<A> =>
  Config.string(name).pipe(
    Config.mapOrFail(
      flow(
        Schema.decodeEither(schema),
        Either.mapLeft((error) =>
          ConfigError.InvalidData([name], formatErrorSync(error)),
        ),
      ),
    ),
  )

@jessekelly881
Copy link
Contributor

There's already an open issue for this :P
#2346

@mikearnaldi
Copy link
Member

Closing as duplicated of #2346

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants