Design-first
Write your API once in a small DSL. Get types, validators, handlers, and an OpenAPI spec from the same source.
A design-first Go framework on net/http. Zero overhead.
package design
type CreateUserReq {
name string @length(1, 80)
email string @format(email)
age int? @gte(0) @lte(150)
}
type User {
id string
name string
email string
age int?
}
@prefix("/v1")
service UserService {
@doc("Create a new user.")
post CreateUser /users {
request CreateUserReq
response User
}
}$ craftgo gen design
craftgo: generated 1 package(s) under .Four files generated, one folder structure to fill in:
internal/types/design/types.go - Go structs with Validate() methodsinternal/transport/user-service/create-user.go - HTTP handler wired to your logicinternal/service/user-service/create-user.go - business logic stub for you to filldocs/openapi.yaml - OpenAPI 3.1 specYou write the business logic. Everything else is generated.
// internal/service/user-service/create-user.go
func (s *Service) CreateUser(ctx context.Context, req *types.CreateUserReq) (*types.User, error) {
user := types.User{
ID: uuid.NewString(),
Name: req.Name,
Email: req.Email,
Age: req.Age,
}
if err := s.svcCtx.UserStore.Save(ctx, &user); err != nil {
return nil, err
}
return &user, nil
}That is it. The handler decodes JSON, runs the validators, calls your code, encodes the response. Re-run craftgo gen after any DSL change. Logic files are scaffold-once and stay yours.
If you use Claude, ChatGPT, Cursor, GitHub Copilot, or another LLM to draft your .craftgo files, paste this URL into your prompt:
https://craftgodotdev.github.io/craftgo/llmsThe page is a single-file consolidated reference: every keyword, every decorator, every CLI command, the generated layout, and common patterns. Designed for AI ingestion, not human reading. Your assistant will know the spec end-to-end and stop hallucinating non-existent decorators.
Example prompt:
Read https://craftgodotdev.github.io/craftgo/llms then design a craftgo DSL file for a
Tasks service with create / list / get / update / delete endpoints.
Use a Status enum (Pending / InProgress / Done) and validate the
title with @length(1, 200).