Simple guides introducing Fabrica with hands-on examples.
This guide will walk you through creating your first REST API with Fabrica in about 15 minutes.
Install the Fabrica CLI:
go install github.com/openchami/fabrica/cmd/fabrica@latest
Verify installation:
fabrica --version
# Output: fabrica version v0.4.5
fabrica init bookstore
cd bookstore
This creates:
bookstore/
├── .fabrica.yaml # Project configuration
├── apis # Versioned API definitions
│ └── example.fabrica.dev
│ └── v1 # Hub version (default)
├── apis.yaml # API groups/versions/resources
├── cmd
│ └── server # API server (main.go with stubs)
│ └── main.go
├── go.mod
├── internal # Generated code will go here
│ └── storage
│ └── storage.go
└── README.md
fabrica add resource Book
This creates apis/example.fabrica.dev/v1/book_types.go:
package v1
import (
"context"
"github.com/openchami/fabrica/pkg/fabrica"
)
// Book represents a book resource
type Book struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata fabrica.Metadata `json:"metadata"`
Spec BookSpec `json:"spec" validate:"required"`
Status BookStatus `json:"status,omitempty"`
}
// BookSpec defines the desired state of Book
type BookSpec struct {
Description string `json:"description,omitempty" validate:"max=200"`
// Add your spec fields here
}
// BookStatus defines the observed state of Book
type BookStatus struct {
Phase string `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Ready bool `json:"ready"`
// Add your status fields here
}
// Validate implements custom validation logic for Book
func (r *Book) Validate(ctx context.Context) error {
// Add custom validation logic here
return nil
}
Edit apis/example.fabrica.dev/v1/book_types.go and modify the BookSpec fields as needed:
type BookSpec struct {
Title string `json:"title" validate:"required,min=1,max=200"`
Author string `json:"author" validate:"required,min=1,max=100"`
Description string `json:"description,omitempty" validate:"max=500"`
Price float64 `json:"price" validate:"min=0"`
InStock bool `json:"inStock"`
}
type BookStatus struct {
Phase string `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Ready bool `json:"ready"`
}
fabrica generate
Output:
🔧 Generating code...
📦 Found 1 resource(s): Book
├─ Registering Book...
├─ Generating handlers...
├─ Generating storage...
├─ Generating OpenAPI spec...
├─ Generating client code...
└─ Done!
✅ Code generation complete!
This generates:
cmd/server/handlers_generated.go - REST handlersinternal/storage/storage_generated.go - Storage operationscmd/server/openapi_generated.go - OpenAPI specpkg/client/client_generated.go - Go client libraryAfter code generation, update your Go module dependencies:
go mod tidy
This resolves all the new imports that were added by the code generator.
go run ./cmd/server/
Your API is now running at http://localhost:8080!
curl -X POST http://localhost:8080/books \
-H "Content-Type: application/json" \
-d '{
"spec": {
"title": "The Go Programming Language",
"author": "Alan Donovan",
"description": "A comprehensive guide to Go programming",
"price": 44.99,
"inStock": true
},
"metadata": {
"name": "golang-guide"
}
}'
Response:
{
"apiVersion": "v1",
"kind": "Book",
"metadata": {
"name": "golang-guide",
"uid": "boo-abc123def456",
"createdAt": "2025-10-15T10:00:00Z",
"updatedAt": "2025-10-15T10:00:00Z"
},
"spec": {
"title": "The Go Programming Language",
"author": "Alan Donovan",
"description": "A comprehensive guide to Go programming",
"price": 44.99,
"inStock": true
},
"status": {
"ready": false,
}
}
curl http://localhost:8080/books
curl http://localhost:8080/books/boo-abc123def456
curl -X PUT http://localhost:8080/books/boo-abc123def456 \
-H "Content-Type: application/json" \
-d '{
"spec": {
"title": "The Go Programming Language",
"author": "Alan Donovan",
"description": "Updated comprehensive guide to Go programming",
"price": 39.99,
"inStock": false
},
"metadata": {
"name": "golang-guide"
}
}'
curl -X DELETE http://localhost:8080/books/boo-abc123def456
Fabrica also generates a CLI client in cmd/client/ that provides a convenient way to interact with your API:
# List books
go run ./cmd/client/ book list
# List books with debug logging
go run ./cmd/client/ --log-level debug book list
# Create a book
go run ./cmd/client/ book create --spec '{"title":"The Go Programming Language","author":"Donovan & Kernighan","price":44.99,"inStock":true}' -o json
# Get output as JSON and process with jq
go run ./cmd/client/ book list -o json | jq '.[0].metadata.uid'
# Debug API interactions
go run ./cmd/client/ -l debug book create --spec '{"title":"Test Book"}' -o json 2> debug.log
The --log-level debug flag is particularly useful when troubleshooting API interactions, as it shows all HTTP requests and responses including headers and bodies.
Fabrica uses a Kubernetes-style resource model with a flattened envelope pattern:
type Book struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
Spec BookSpec `json:"spec"`
Status BookStatus `json:"status,omitempty"`
}
Key concepts:
Fabrica uses struct tag validation for request validation:
type BookSpec struct {
Title string `json:"title" validate:"required,min=1,max=200"`
Price float64 `json:"price" validate:"min=0"`
Author string `json:"author" validate:"required,min=1,max=100"`
}
Common validators:
required - Field must be presentmin=N,max=N - Length/value constraintsgt=N,lt=N - Numeric comparisonsemail, url, ip - Format validatorsoneof=a b c - Enum validationPerfect for development:
backend, err := storage.NewFileBackend("./data")
Data stored in ./data/ directory as JSON files.
Use Ent for production:
fabrica init myapp --storage=ent --db=postgres
See Storage Guide for details.
Now that you have a working API:
fabrica add resource Authorinternal/middleware/pkg/client/go build cmd/server/main.gofabrica add resource Author
# Edit apis/example.fabrica.dev/v1/author_types.go
fabrica generate
# After editing resource definitions
fabrica generate
go build -o bookstore-api cmd/server/main.go
./bookstore-api
go test ./...
Fix: Run go mod tidy after fabrica generate to resolve all new imports created by the code generator.
Fix: Make sure your resource has the flattened envelope structure:
type MyResource struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
Spec MyResourceSpec `json:"spec"`
}
Fix: Update fabrica: go install github.com/openchami/fabrica/cmd/fabrica@latest