micro--go-micro
669481224c
* feat(cli): add CRUD, pub/sub, and API gateway templates for micro new
Add --template flag to 'micro new' with three preset templates:
- crud: CRUD service with Create/Read/Update/Delete/List, in-memory
store with sync.RWMutex, UUID generation, pagination, and doc
comments with @example tags for MCP tool discovery.
- pubsub: Event-driven service with Publish/Stats RPCs and a
Subscribe method that hooks into the broker. Includes event
types with ID, type, source, data, and timestamp.
- api: API gateway service with Health and Endpoint RPCs, an
internal HTTP route table, and a response recorder for
proxying requests through RPC.
All templates include MCP-ready doc comments and work with
--no-mcp. The default template (no flag) is unchanged.
Usage:
micro new myservice --template crud
micro new myservice --template pubsub
micro new myservice --template api
* fix(ai): update Atlas Cloud provider to use actual API formats
Fix the Atlas Cloud image generation to use their real async API:
POST /api/v1/model/generateImage → poll /api/v1/model/prediction/{id}
instead of the OpenAI-compatible endpoint which doesn't exist.
Add Quality and OutputFormat fields to ai.ImageRequest for
provider-specific image parameters.
Update default text model from llama-3.3-70b (doesn't exist) to
deepseek-ai/DeepSeek-V3-0324 (their flagship model). Update
default image model to openai/gpt-image-2/text-to-image.
* feat(website): add AI-generated images to landing page, docs, and blog
Generate 5 images via Atlas Cloud's image API (gpt-image-2) to
elevate the website experience:
- hero.png: microservices network graph for landing page
- architecture.png: registry + broker architecture diagram
- mcp-agent.png: AI agent calling services via MCP
- developer-experience.png: terminal showing micro run/chat
- blog-atlas.png: Atlas Cloud unified API illustration
Add visual sections to the landing page with architecture,
MCP integration, and developer experience showcases. Add
images to docs index, MCP docs, and Atlas Cloud blog post.
All images resized to 1200px wide and optimized for web.
Generated using Atlas Cloud sponsor credits.
* feat(website): redesign landing page and add images to docs
Redesign the landing page from a centered card layout to a
full-width modern site with:
- Top navigation bar
- Hero section with gradient background and CTA buttons
- Full-width image showcase sections
- Two-column layout for architecture, MCP, and DX sections
- Feature grid with 6 capabilities
- Footer with links
- Responsive breakpoints for mobile
Generate 3 more images via Atlas Cloud for docs:
- getting-started.png for the getting started guide
- deployment.png for the deployment guide
- data-model.png for the data model docs
Add images to getting-started.md, model.md, and deployment.md.
---------
Co-authored-by: Claude <noreply@anthropic.com>
285 行
6.5 KiB
Markdown
285 行
6.5 KiB
Markdown
---
|
|
layout: doc
|
|
title: Data Model
|
|
permalink: /docs/model.html
|
|
description: "Structured data model layer with CRUD operations, queries, and pluggable backends"
|
|
---
|
|
|
|
# Data Model
|
|
|
|
<img src="/images/generated/data-model.png" alt="Go Micro data model" style="width: 100%; border-radius: 8px; margin-bottom: 1.5rem;" />
|
|
|
|
The `model` package provides a structured data model layer for Go Micro services. Define Go structs, tag your fields, and get CRUD operations with queries, filtering, ordering, and pagination.
|
|
|
|
## Quick Start
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go-micro.dev/v5"
|
|
"go-micro.dev/v5/model"
|
|
)
|
|
|
|
type Task struct {
|
|
ID string `json:"id" model:"key"`
|
|
Title string `json:"title"`
|
|
Done bool `json:"done"`
|
|
Owner string `json:"owner" model:"index"`
|
|
}
|
|
|
|
func main() {
|
|
service := micro.New("tasks")
|
|
|
|
// Register your type with the service's model backend
|
|
db := service.Model()
|
|
db.Register(&Task{})
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a record
|
|
db.Create(ctx, &Task{ID: "1", Title: "Ship it", Owner: "alice"})
|
|
|
|
// Read by key
|
|
task := &Task{}
|
|
db.Read(ctx, "1", task)
|
|
|
|
// Update
|
|
task.Done = true
|
|
db.Update(ctx, task)
|
|
|
|
// List with filters
|
|
var aliceTasks []*Task
|
|
db.List(ctx, &aliceTasks, model.Where("owner", "alice"))
|
|
|
|
// Delete
|
|
db.Delete(ctx, "1", &Task{})
|
|
}
|
|
```
|
|
|
|
## Defining Models
|
|
|
|
Models are plain Go structs. Use struct tags to control storage behavior:
|
|
|
|
| Tag | Purpose | Example |
|
|
|-----|---------|---------|
|
|
| `model:"key"` | Primary key field | `ID string \`model:"key"\`` |
|
|
| `model:"index"` | Create an index on this field | `Email string \`model:"index"\`` |
|
|
| `json:"name"` | Column name in the database | `Name string \`json:"name"\`` |
|
|
|
|
If no `model:"key"` tag is found, the package defaults to a field with `json:"id"` or a field named `ID`.
|
|
|
|
Table names are auto-derived from the struct name (lowercased + "s"), e.g. `User` → `users`. Override with `model.WithTable("custom_name")`.
|
|
|
|
```go
|
|
type User struct {
|
|
ID string `json:"id" model:"key"`
|
|
Name string `json:"name"`
|
|
Email string `json:"email" model:"index"`
|
|
Age int `json:"age"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
// Register with auto-derived table: "users"
|
|
db.Register(&User{})
|
|
|
|
// Custom table name
|
|
db.Register(&User{}, model.WithTable("app_users"))
|
|
```
|
|
|
|
## CRUD Operations
|
|
|
|
```go
|
|
// Create — inserts a new record (returns ErrDuplicateKey if key exists)
|
|
err := db.Create(ctx, &User{ID: "1", Name: "Alice"})
|
|
|
|
// Read — retrieves by primary key (returns ErrNotFound if missing)
|
|
user := &User{}
|
|
err = db.Read(ctx, "1", user)
|
|
|
|
// Update — modifies an existing record (returns ErrNotFound if missing)
|
|
user.Name = "Alice Smith"
|
|
err = db.Update(ctx, user)
|
|
|
|
// Delete — removes by primary key (returns ErrNotFound if missing)
|
|
err = db.Delete(ctx, "1", &User{})
|
|
```
|
|
|
|
## Queries
|
|
|
|
Use query options to filter, order, and paginate results:
|
|
|
|
### Filters
|
|
|
|
```go
|
|
var results []*User
|
|
|
|
// Equality
|
|
db.List(ctx, &results, model.Where("email", "alice@example.com"))
|
|
|
|
// Operators: =, !=, <, >, <=, >=, LIKE
|
|
db.List(ctx, &results, model.WhereOp("age", ">=", 18))
|
|
db.List(ctx, &results, model.WhereOp("name", "LIKE", "Ali%"))
|
|
|
|
// Multiple filters (AND)
|
|
db.List(ctx, &results,
|
|
model.Where("owner", "alice"),
|
|
model.WhereOp("age", ">", 25),
|
|
)
|
|
```
|
|
|
|
### Ordering
|
|
|
|
```go
|
|
db.List(ctx, &results, model.OrderAsc("name"))
|
|
db.List(ctx, &results, model.OrderDesc("created_at"))
|
|
```
|
|
|
|
### Pagination
|
|
|
|
```go
|
|
db.List(ctx, &results,
|
|
model.Limit(10),
|
|
model.Offset(20),
|
|
)
|
|
```
|
|
|
|
### Counting
|
|
|
|
```go
|
|
total, _ := db.Count(ctx, &User{})
|
|
active, _ := db.Count(ctx, &User{}, model.Where("active", true))
|
|
```
|
|
|
|
## Backends
|
|
|
|
The model layer uses Go Micro's pluggable interface pattern. All backends implement `model.Model`.
|
|
|
|
### Memory (Default)
|
|
|
|
Zero-config, in-memory storage. Data doesn't persist across restarts. Ideal for development and testing.
|
|
|
|
```go
|
|
service := micro.New("myservice")
|
|
db := service.Model() // memory backend by default
|
|
db.Register(&Task{})
|
|
```
|
|
|
|
Or create directly:
|
|
|
|
```go
|
|
import "go-micro.dev/v5/model"
|
|
|
|
db := model.NewModel()
|
|
db.Register(&Task{})
|
|
```
|
|
|
|
### SQLite
|
|
|
|
File-based database. Good for local development or single-node production.
|
|
|
|
```go
|
|
import "go-micro.dev/v5/model/sqlite"
|
|
|
|
db := sqlite.New("app.db")
|
|
service := micro.New("myservice", micro.Model(db))
|
|
```
|
|
|
|
### Postgres
|
|
|
|
Production-grade with connection pooling.
|
|
|
|
```go
|
|
import "go-micro.dev/v5/model/postgres"
|
|
|
|
db := postgres.New("postgres://user:pass@localhost/myapp?sslmode=disable")
|
|
service := micro.New("myservice", micro.Model(db))
|
|
```
|
|
|
|
## Service Integration
|
|
|
|
The `Service` interface provides `Model()` alongside `Client()` and `Server()`:
|
|
|
|
```go
|
|
service := micro.New("users", micro.Address(":9001"))
|
|
|
|
// Access the three core components
|
|
client := service.Client() // Call other services
|
|
server := service.Server() // Handle requests
|
|
db := service.Model() // Data persistence
|
|
|
|
// Register your types
|
|
db.Register(&User{})
|
|
db.Register(&Post{})
|
|
|
|
// Use in your handler
|
|
service.Handle(&UserHandler{db: db})
|
|
service.Run()
|
|
```
|
|
|
|
A handler that uses all three:
|
|
|
|
```go
|
|
type OrderHandler struct {
|
|
db model.Model
|
|
client client.Client
|
|
}
|
|
|
|
// CreateOrder saves an order and notifies the shipping service
|
|
func (h *OrderHandler) CreateOrder(ctx context.Context, req *CreateReq, rsp *CreateRsp) error {
|
|
// Save to database via Model
|
|
order := &Order{ID: req.ID, Item: req.Item, Status: "pending"}
|
|
if err := h.db.Create(ctx, order); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Call another service via Client
|
|
shipClient := proto.NewShippingService("shipping", h.client)
|
|
_, err := shipClient.Ship(ctx, &proto.ShipRequest{OrderID: order.ID})
|
|
|
|
return err
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
The model package returns sentinel errors:
|
|
|
|
```go
|
|
import "go-micro.dev/v5/model"
|
|
|
|
// Check for not found
|
|
err := db.Read(ctx, "missing", &User{})
|
|
if errors.Is(err, model.ErrNotFound) {
|
|
// record doesn't exist
|
|
}
|
|
|
|
// Check for duplicate key
|
|
err = db.Create(ctx, &User{ID: "1", Name: "Alice"})
|
|
err = db.Create(ctx, &User{ID: "1", Name: "Bob"})
|
|
if errors.Is(err, model.ErrDuplicateKey) {
|
|
// key "1" already exists
|
|
}
|
|
```
|
|
|
|
## Swapping Backends
|
|
|
|
Follow the standard Go Micro pattern — use in-memory for development, swap to a real database for production:
|
|
|
|
```go
|
|
func main() {
|
|
var db model.Model
|
|
|
|
if os.Getenv("ENV") == "production" {
|
|
db = postgres.New(os.Getenv("DATABASE_URL"))
|
|
} else {
|
|
db = model.NewModel()
|
|
}
|
|
|
|
service := micro.New("myservice", micro.Model(db))
|
|
// ... same application code regardless of backend
|
|
}
|
|
```
|