Simple guides introducing Fabrica with hands-on examples.
Goal: Build and run a working REST API without learning Kubernetes concepts or advanced patterns.
This guide treats Fabrica as a code generator for simple CRUD APIs. We’ll hide the advanced features and focus on getting you productive quickly.
A simple REST API for managing products with these endpoints:
POST /products - Create a productGET /products - List all productsGET /products/{id} - Get a specific productPUT /products/{id} - Update a productDELETE /products/{id} - Delete a productNo databases to configure. Everything runs in-memory to keep it simple.
go install github.com/openchami/fabrica/cmd/fabrica@latest
Verify installation:
fabrica --version
# Output: fabrica version v0.4.0
Create a new project with minimal complexity:
# Initialize simple project (creates myshop directory)
fabrica init myshop
# Enter project directory
cd myshop
gh repo create)If you’ve already created a repository with GitHub CLI or template:
# Create repo from template (example)
gh repo create myshop --template myorg/template --public
cd myshop
# Initialize Fabrica in current directory
fabrica init .
This will preserve existing files like .git, README.md, LICENSE, etc.
By default, fabrica init creates a project with a single v1 API version and the group example.fabrica.dev. You can customize this:
# Create project with custom API group
fabrica init myshop \
--group myorg.api
# Or use interactive mode for guided setup
fabrica init myshop --interactive
Available init flags:
--group - API group name (default: example.fabrica.dev)--module - Go module path--validation-mode - Validation: strict, warn, or disabled (default: strict)--events - Enable CloudEvents support--storage-type - Storage backend: file or ent (default: file)--db - Database driver for ent: sqlite, postgres, or mysql (default: sqlite)Both options create:
.fabrica.yaml with project configurationapis.yaml with API group and version configuration (default: example.fabrica.dev group, v1 version)go.mod with necessary dependenciescmd/, apis/, etc.)apis/example.fabrica.dev/v1/You’ll see:
✓ Created .fabrica.yaml
✓ Created apis.yaml
✓ Created go.mod
✓ Created README.md (or skipped if exists)
✓ Created basic project structure
Your project is ready! Next steps:
1. fabrica add resource Product
2. fabrica generate
3. go mod tidy
4. go run ./cmd/server/
Use the Fabrica CLI to create a Product resource:
fabrica add resource Product
This command creates a resource definition in your project’s versioned API directory. By default, resources are created in the hub (storage) version at apis/example.fabrica.dev/v1/product_types.go:
Available add resource flags:
--version - Target API version (default: storage version from apis.yaml)--force - Force adding to non-alpha versions--with-validation - Include validation tags (default: true)--with-status - Include Status struct (default: true)package v1
import (
"context"
"github.com/openchami/fabrica/pkg/fabrica"
)
// Product represents a Product resource
type Product struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata fabrica.Metadata `json:"metadata"`
Spec ProductSpec `json:"spec" validate:"required"`
Status ProductStatus `json:"status,omitempty"`
}
// ProductSpec defines the desired state of Product
type ProductSpec struct {
Name string `json:"name" 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"`
}
// ProductStatus defines the observed state of Product
type ProductStatus struct {
Phase string `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Ready bool `json:"ready"`
LastUpdated string `json:"lastUpdated,omitempty"`
}
func (r *Product) Validate(ctx context.Context) error {
// Add custom validation logic here
return nil
}
Customize the Spec: You can edit the fields in ProductSpec as needed. Your resource definitions stay in the versioned API directory (apis/<group>/<version>/).
Now generate the REST API handlers, storage, and routes:
fabrica generate
This command:
Product resourceYou’ll see:
🔧 Generating code...
📦 Found 1 resource(s): Product
├─ Registering Product...
├─ Generating handlers...
├─ Generating storage...
├─ Generating OpenAPI spec...
└─ Done!
✅ Code generation complete!
After code generation, update your Go module dependencies:
go mod tidy
This resolves all the new imports that were added by the code generator.
Start the server:
go run ./cmd/server/
You’ll see:
Starting Fabrica server...
✓ Loaded Product handlers
✓ Registered routes
Server listening on :8080
Your API is now running at http://localhost:8080!
Open a new terminal and try the API:
curl -X POST http://localhost:8080/products \
-H "Content-Type: application/json" \
-d '{
"name": "laptop-pro",
"displayName": "MacBook Pro",
"description": "15-inch MacBook Pro with M2 chip",
"price": 1999.99,
"inStock": true
}'
Response:
{
"apiVersion": "v1",
"kind": "Product",
"metadata": {
"name": "laptop-pro",
"uid": "pro-abc123def456",
"createdAt": "2025-10-15T10:30:00Z",
"updatedAt": "2025-10-15T10:30:00Z"
},
"spec": {
"name": "MacBook Pro",
"description": "15-inch MacBook Pro with M2 chip",
"price": 1999.99,
"inStock": true
},
"status": {
"phase": "Active",
"ready": true,
"lastUpdated": "2025-10-15T10:30:00Z"
}
}
curl http://localhost:8080/products
Response (flat JSON array):
[
{
"apiVersion": "v1",
"kind": "Product",
"metadata": {
"name": "laptop-pro",
"uid": "pro-abc123def456",
"createdAt": "2025-10-15T10:30:00Z",
"updatedAt": "2025-10-15T10:30:00Z"
},
"spec": {
"name": "MacBook Pro",
"description": "15-inch MacBook Pro with M2 chip",
"price": 1999.99,
"inStock": true
},
"status": {
"phase": "Active",
"ready": true,
"lastUpdated": "2025-10-15T10:30:00Z"
}
}
]
curl http://localhost:8080/products/pro-abc123def456
curl -X PUT http://localhost:8080/products/pro-abc123def456 \
-H "Content-Type: application/json" \
-d '{
"name": "laptop-pro",
"displayName": "MacBook Pro M3",
"description": "Latest 15-inch MacBook Pro with M3 chip",
"price": 2199.99,
"inStock": true
}'
curl -X DELETE http://localhost:8080/products/pro-abc123def456
Response:
{
"message": "Product deleted successfully"
}
Let’s peek under the hood (but don’t worry, you don’t need to edit these files):
myshop/
├── .fabrica.yaml # Project configuration
├── apis.yaml # API group and versioning config
├── go.mod # Dependencies
├── README.md # Project README
├── apis/
│ └── example.fabrica.dev/ # API group directory
│ └── v1/
│ ├── product_types.go # Your resource definition (you edited this)
│ └── ...
├── cmd/
│ └── server/
│ ├── main.go # Server entry point (with stubs)
│ ├── product_handlers_generated.go # HTTP handlers (generated)
│ ├── routes_generated.go # URL routing (generated)
│ ├── models_generated.go # Server types (generated)
│ └── openapi_generated.go # OpenAPI spec (generated)
└── internal/
└── storage/
└── storage_generated.go # Storage operations (generated)
cmd/server/product_handlers_generated.go):
internal/storage/storage_generated.go):
cmd/server/routes_generated.go):
pkg/client/client_generated.go):
cmd/server/openapi_generated.go):
/swagger/Just the Product struct definitions! That’s about 20 lines of code to get a complete REST API with documentation, validation, and client libraries.
Need users? Orders? Categories?
# Add a new resource type (automatically added to the hub version)
fabrica add resource Order
# Edit the generated apis/<group>/<version>/order_types.go
# Add your OrderSpec and OrderStatus fields
# Regenerate all code
fabrica generate
Each resource gets its own complete set of CRUD endpoints automatically.
Ready to add a new version for evolving your API?
# Step 1: Add a new API version to your project
# This creates the version directory and updates apis.yaml
fabrica add version v2
# Step 2: Add resources to the new version
# For alpha versions, resources are added without --force
fabrica add resource Device --version v2alpha1
# For stable versions, you need --force to acknowledge breaking changes
fabrica add resource Device --version v2 --force
# Step 3: Regenerate - handlers for all versions are created automatically
fabrica generate
Important: You must use fabrica add version <version> to create the version in apis.yaml before you can add resources to it. If you try to add a resource to a non-existent version, you’ll get an error:
Error: version v2 not found in apis.yaml (available: [v1])
Version naming conventions:
v1alpha1, v2alpha1 - Alpha versions (unstable, can change freely)v1beta1, v2beta1 - Beta versions (more stable, breaking changes discouraged)v1, v2 - Stable versions (require --force flag for changes)Fabrica uses hub/spoke versioning where all requests are converted to the hub (storage) version internally, allowing you to evolve your API gracefully.
Want to validate input? Add struct tags:
type ProductSpec struct {
Name string `json:"name" validate:"required,min=3,max=100"`
Description string `json:"description" validate:"max=500"`
Price float64 `json:"price" validate:"required,gt=0"`
InStock bool `json:"inStock"`
}
Validation happens automatically - invalid requests return 400 errors with detailed messages!
Visit these URLs while your server is running:
When you’re ready to explore more of Fabrica’s capabilities:
README.md in your projectfabrica --help or fabrica <command> --helpdocs/ in the Fabrica repositoryexamples/ for working code samplesIn 30 minutes, you’ve:
✅ Installed Fabrica CLI ✅ Created a new project with simple mode ✅ Defined a data structure (7 lines of code) ✅ Generated a complete REST API ✅ Ran and tested your API ✅ Learned how to add more resources
You now have a working REST API!
When you’re ready to go deeper and unlock Fabrica’s full power (labels, conditions, events, reconciliation), continue to the Resource Management Tutorial.
Happy coding! 🚀