Fabrica Blog

Simple guides introducing Fabrica with hands-on examples.

View the Project on GitHub OpenCHAMI/fabrica

Getting Started with Fabrica

This guide will walk you through creating your first REST API with Fabrica in about 15 minutes.

Prerequisites

Installation

Install the Fabrica CLI:

go install github.com/openchami/fabrica/cmd/fabrica@latest

Verify installation:

fabrica --version
# Output: fabrica version v0.4.5

Create Your First API

Step 1: Initialize Project

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

Step 2: Add Your First Resource

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
}

Step 3: Customize Your Resource

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"`
}

Step 4: Generate Code

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:

Step 5: Update Dependencies

After code generation, update your Go module dependencies:

go mod tidy

This resolves all the new imports that were added by the code generator.

Step 6: Run Your API

go run ./cmd/server/

Your API is now running at http://localhost:8080!

Using Your API

Create a Book

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,
  }
}

List Books

curl http://localhost:8080/books

Get a Specific Book

curl http://localhost:8080/books/boo-abc123def456

Update a Book

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"
    }
  }'

Delete a Book

curl -X DELETE http://localhost:8080/books/boo-abc123def456

Using the Generated Client

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.

Understanding the Resource Model

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:

Validation

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:

Storage Options

File-Based Storage (Default)

Perfect for development:

backend, err := storage.NewFileBackend("./data")

Data stored in ./data/ directory as JSON files.

Database Storage (Production)

Use Ent for production:

fabrica init myapp --storage=ent --db=postgres

See Storage Guide for details.

Next Steps

Now that you have a working API:

  1. Add More Resources - fabrica add resource Author
  2. Add Custom Middleware - Implement authentication/authorization in internal/middleware/
  3. Add Validation - See Validation Guide
  4. Use the Client - Generated Go client in pkg/client/
  5. Add Events - See Events Guide
  6. Deploy - Build with go build cmd/server/main.go

Common Tasks

Add Another Resource

fabrica add resource Author
# Edit apis/example.fabrica.dev/v1/author_types.go
fabrica generate

Regenerate After Changes

# After editing resource definitions
fabrica generate

Build for Production

go build -o bookstore-api cmd/server/main.go
./bookstore-api

Run Tests

go test ./...

Troubleshooting

Error: “go: updates to go.mod needed”

Fix: Run go mod tidy after fabrica generate to resolve all new imports created by the code generator.

Error: “no resources found”

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"`
}

Error: “failed to read embedded template”

Fix: Update fabrica: go install github.com/openchami/fabrica/cmd/fabrica@latest

Further Reading

Get Help