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.0
fabrica init bookstore
cd bookstore
This creates:
bookstore/
├── .fabrica.yaml # Project configuration
├── apis.yaml # API groups/versions/resources
├── apis/ # Versioned API definitions
│ └── example.fabrica.dev/
│ └── v1/ # Hub version (default)
├── cmd/
│ └── server/ # API server (main.go with stubs)
├── internal/ # Generated code will go here
├── go.mod
├── go.sum
└── 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"`
Status BookStatus `json:"status"`
}
// BookSpec defines the desired state of Book
type BookSpec struct {
Title string `json:"title" validate:"required,min=1,max=100"`
Author string `json:"author" validate:"required,min=1,max=50"`
Description string `json:"description,omitempty" validate:"max=500"`
Price float64 `json:"price" validate:"min=0"`
InStock bool `json:"inStock"`
}
// BookStatus defines the observed state of Book
type BookStatus struct {
Phase string `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Ready bool `json:"ready"`
LastUpdated string `json:"lastUpdated,omitempty"`
}
func (r *Book) Validate(ctx context.Context) error { // Add custom validation logic here return nil }
### Step 3: Customize Your Resource
Edit `apis/example.fabrica.dev/v1/book_types.go` and modify the `BookSpec` fields as needed:
```go
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"`
LastUpdated string `json:"lastUpdated,omitempty"`
}
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 '{
"name": "golang-guide",
"title": "The Go Programming Language",
"author": "Alan Donovan",
"description": "A comprehensive guide to Go programming",
"price": 44.99,
"inStock": true
}'
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": {
"phase": "Active",
"ready": true,
"lastUpdated": "2025-10-15T10:00:00Z"
}
}
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 '{
"name": "golang-guide",
"title": "The Go Programming Language",
"author": "Alan Donovan",
"description": "Updated comprehensive guide to Go programming",
"price": 39.99,
"inStock": false
}'
curl -X DELETE http://localhost:8080/books/boo-abc123def456
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