Muzak logomuzak
v0.1.10

Introduction

Muzak is a web framework for Go. You use it to build HTTP APIs: a function becomes a route, the input type of that function is the request, and the return type is the response body. Both are checked when you compile, not when a request arrives.

The framework is built on net/http and Go 1.27, with no third-party dependencies at all. The pieces you reach for every day (routing, request binding, validation, dependency injection, configuration, logging, OpenAPI) are part of the framework, not separate modules you have to wire together yourself.

Here is a complete application. It answers GET /users/{username} with a JSON object.

package main

import (
    "log"

    "muzak.dev/framework"
)

type Params struct {
    Username string `path:"username" doc:"The username to look up"`
}

type UserOut struct {
    Username string `json:"username"`
}

func main() {
    app := muzak.New(muzak.AppOptions{Title: "Hello", Version: "1.0.0"})

    app.Get("/users/{username}", func(ctx *muzak.Context, in Params) (UserOut, error) {
        return UserOut{Username: in.Username}, nil
    })

    log.Fatal(app.RunSignals())
}

Params is the request. UserOut is the response. You never write the type arguments for app.Get: Go 1.27 added generic methods and generalized function type inference, so the router reads both types off the handler literal.

What you get

  • Routing from typed functions. A handler is func(ctx *muzak.Context, in In) (Out, error). There is no wrapper type around the response and no filtering pass at run time, so a field you did not declare on Out cannot leak.
  • Typed request data. Struct tags say where each field comes from: path, query, header, cookie, form, file, or the JSON body when a field carries none of them. Bad input is rejected with 422 before your function runs.
  • Validation against the field itself. v.String(&in.Email).Trim().Lower().Required().Email() names the field by address, so renaming it is a change the compiler checks and there is no tag string to typo.
  • Dependency injection in two shapes. A guard validates and produces nothing; a provider produces a typed value that the handler reads with muzak.From[T](ctx).
  • Nested routers. A package exports its own router and stays unaware of the prefix, tags and guards it will eventually run under. The application decides where things mount.
  • OpenAPI for free. Routes, models and validation rules produce an OpenAPI 3.1 document at /openapi.json and a self-contained documentation page at /docs.
  • API versioning. A route declares the version or versions it answers, read from the path, a header, the Accept header or a function of your own.
  • Real-time built in. Router.WS speaks RFC 6455 WebSockets and Router.SSE serves typed server-sent events, both behind the same middleware, guards and binding as any other route.
  • Safe defaults. Every listener timeout is non-zero, bodies are capped, unknown JSON members are rejected, CORS denies everything until a policy is written, and a panic becomes a generic 500 with the stack in the log rather than in the response.

What a bigger application looks like

Each router is written on its own. The application decides where they mount and what protects them, and that decision lives in one visible place.

settings := muzak.MustLoadConfig[core.Settings](muzak.EnvFile(".env"))

app := muzak.New(muzak.AppOptions{
    Title:   "Awesome API",
    Version: "1.0.0",
    Addr:    settings.Addr,
},
    muzak.WithDependencies(core.GetQueryToken),
    muzak.WithSingleton(settings),
)

app.Include(routers.Users())
app.Include(routers.Items())
app.Include(routers.Admin(),
    muzak.WithPrefix("/admin"),
    muzak.WithTags("admin"),
    muzak.WithDependencies(core.GetTokenHeader(settings)),
)

log.Fatal(app.RunSignals())

App embeds *Router, so app.Get(...) works at the root using the same generic methods any nested router uses.

Where to go next

Start with First Steps to create a project and run it. After that, Routers covers paths and methods, Request Data covers how the input struct is filled in, and Dependencies shows how services and resources reach your handlers.

Open source under MIT / Apache-2.0 · sustained by the people who ship on it.Built on net/http, and nothing else.