Skip to content

Repository files navigation

Next Effect cover

Next Effect

npm version npm downloads Github Actions

Easily use Effect for Next.js Route Handlers, Server Actions, Pages and Forms

Next Effect is a library that makes it easy to use Effect for Next.js Route Handlers, Server Actions, Pages and Forms. It provides helpful utilities for working with Next.js using Effect.

Features

⚡️ Quickstart

  1. Install the Neft Effect package
$ pnpx jsr add next-effect
  1. Create a Server Action handler
import { makeServerActionHandler } from "next-effect"

export class InternalServerError extends S.TaggedError<InternalServerError>()("InternalServerError", {
  success: S.Boolean,
  message: S.String,
  reason: S.String,
}) {}

export class InvalidPayload extends S.TaggedError<InvalidPayload>()("InvalidPayload", {
  success: S.Boolean,
  message: S.String,
  reason: S.String,
}) {}

export const invalidPayload = new InvalidPayload({ success: false, message: "Invalid payload", reason: 'invalid-payload' })
export const internalServerError = new InternalServerError({ success: false, message: "Internal server error", reason: 'internal-server-error' })

const makeServerAction = makeServerActionHandler({
  errors: {
    invalidPayload: ({ error, schema, payload }) => invalidPayload,
    unexpected: (cause: Cause.Cause<unknown>) => internalServerError,
  },
})

// lib/actions/create-team.ts
export const CreateTeamPayload = S.Struct({
  name: S.String,
  userId: S.String,
})

export const CreateTeamFailedError extends S.TaggedError<CreateTeamFailedError>()("CreateTeamFailedError", {
  success: S.Boolean,
  message: S.String,
  reason: S.String,
}) {}

export const CreateTeamSuccess = S.Struct({
  success: S.Literal(true),
  message: S.String,
})

export const createTeam = makeServerAction(CreateTeamPayload, async (payload: S.Schema.Type<typeof CreateTeamPayload>) => Effect.gen(function* () {
  const random = yield* Random.next
  if (random > 0.5) {
    return yield* Effect.fail(new CreateTeamFailedError({ success: false, message: "Failed to create team", reason: 'create-team-failed' }))
  }
  return CreateTeamSuccess.make({
    success: true,
    message: "Team created successfully.",
  })
}))

// components/create-team.tsx
export const CreateTeamForm = () => {
  async function createTeam() {
    const result: CreateTeamSuccess | CreateTeamFailedError | InvalidPayload | InternalServerError = await createTeam({ name: 'John Doe', userId: '123' })

    // 👇 We can easily handle errors, since all our errors are fully typed
    if (result._tag === "CreateTeamFailedError") {
      sonner.error("Oops! Failed to create team: " + result.message)
    }

    // Continue…
  }
}
  1. Create a Route Handler
export class InternalServerError extends S.TaggedError<InternalServerError>()("InternalServerError", {
  success: S.Boolean,
  message: S.String,
  reason: S.String,
}) {}

export class InvalidPayload extends S.TaggedError<InvalidPayload>()("InvalidPayload", {
  success: S.Boolean,
  message: S.String,
  reason: S.String,
}) {}

export const invalidPayload = new InvalidPayload({ success: false, message: "Invalid payload", reason: 'invalid-payload' })
export const internalServerError = new InternalServerError({ success: false, message: "Internal server error", reason: 'internal-server-error' })

const createRouteHandler = makeRouteHandler({
  errors: {
    invalidPayload: ({ error, schema, payload }) => invalidPayload,
    unexpected: (cause: Cause.Cause<unknown>) => internalServerError
  },
  // 👇 Define your response types here (these are used for extracting response status codes, encoding etc.)
  responses: [Unauthorized, TestSuccess, TextResponse, BytesResponse]
})

export const GET = createRouteHandler(Effect.sync(() => {
  const name = yield* Next.ensureRequestSchema(S.Struct({ name: S.String }))
  return { success: true, message: `API key created for ${name.name}.` }
}))
  1. Create a Form Handler
// todo: write this

🎥 Write Server Actions using Effect

TODO Write Docs

⛓️ Write Forms using Effect

TODO Write docs

💻 Development

  • Clone this repository
  • Install dependencies using deno install
  • Run the tests using deno test

License

Made with ❤️ in Helsinki, Finland.

Published under MIT License.

TODO

  • OTEL setup
    • Work with Effect Dev Tools
  • Request tracing
    • Easily add context to traces
  • Way to define response types / errors
  • Schemas to define response types (raw, text), status codes
  • Headers

About

Easily use Effect for Next.js Route Handlers, Server Actions, Pages and Forms

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages