Date: 2025-11-16 Branch: claude/rest-api-libraries-017raMCMgMaSRSLBcArTrSDA
This document describes the implementation of the REST API library for GoFlow, which provides a signal-based reactive approach to making HTTP requests that integrates seamlessly with GoFlow's widget system.
GoFlow widgets need a way to fetch data from REST APIs that:
- Integrates with the Signals reactive system
- Automatically triggers widget rebuilds when data changes
- Provides clear loading and error states
- Is type-safe and easy to use
- Follows familiar patterns from Flutter and modern web frameworks
pkg/api/
├── client.go # HTTP client with middleware support
├── response.go # Response wrapper with helper methods
├── resource.go # Signal-based Resource[T] and ResourceList[T]
├── fetcher.go # Helper functions for common requests
├── provider.go # Context provider for API client
├── middleware/
│ ├── auth.go # Authentication middleware
│ ├── logging.go # Request/response logging
│ └── retry.go # Retry logic with exponential backoff
└── services/
├── user_service.go # Example user service
└── post_service.go # Example post service
Resources wrap API data in Signals that trigger widget rebuilds:
type ResourceState[T any] struct {
Data *T
Loading bool
Error error
}
type Resource[T any] struct {
state *signals.Signal[ResourceState[T]]
// ... other fields
}This allows widgets to reactively respond to data changes:
func (w *MyWidget) Build(ctx BuildContext) Widget {
state := w.resource.Get() // Creates reactive dependency
if state.Loading { return LoadingWidget() }
if state.Error != nil { return ErrorWidget(state.Error) }
return DataWidget(state.Data)
}Middleware wraps HTTP requests in a composable chain:
type Middleware func(next RequestHandler) RequestHandler
client.Use(middleware.Logging(nil)).
Use(middleware.BearerAuth("token")).
Use(middleware.Retry(config))Each middleware can:
- Modify the request before sending
- Inspect/modify the response
- Handle errors and retries
- Add headers, logging, timing, etc.
Services encapsulate related API endpoints:
type UserService struct {
client *api.Client
}
func (s *UserService) GetUser(ctx context.Context, id int) *api.Resource[User] {
return api.Get[User](ctx, s.client, fmt.Sprintf("/users/%d", id))
}This provides:
- Separation of concerns
- Testability (easy to mock)
- Reusability across widgets
- Type safety with generics
API client is provided through BuildContext:
&api.APIProvider{
Client: apiClient,
Child: &MyApp{},
}
// In descendants:
apiClient := api.GetClient(ctx)The Client struct (client.go:22-28) provides:
- Base URL configuration
- Timeout settings
- Default headers
- Middleware chain
- HTTP verb methods (GET, POST, PUT, PATCH, DELETE)
The Resource[T] type (resource.go:14-22) provides:
- Thread-safe state management
- Reactive signal-based updates
- Cancellation support
- Helper methods for common checks
Three built-in middleware types:
-
Authentication (
middleware/auth.go)- Bearer token
- Basic auth
- API key headers
-
Logging (
middleware/logging.go)- Request/response logging
- Timing information
- Custom logger support
-
Retry (
middleware/retry.go)- Exponential backoff
- Configurable retry conditions
- Max retries setting
fetcher.go provides convenience functions:
Get[T]()- GET request returning Resource[T]Post[T]()- POST request returning Resource[T]FetchList[T]()- Request returning ResourceList[T]
// Create API client
apiClient := api.NewClient(api.ClientConfig{
BaseURL: "https://api.example.com",
}).Use(middleware.Logging(nil))
// Wrap app with provider
app := &api.APIProvider{
Client: apiClient,
Child: &HomePage{},
}type UserProfile struct {
goflow.BaseWidget
userResource *api.Resource[User]
initialized *signals.Signal[bool]
}
func (w *UserProfile) Build(ctx goflow.BuildContext) goflow.Widget {
// Initialize once
if w.initialized == nil {
w.initialized = signals.NewSignal(false)
apiClient := api.GetClient(ctx)
userService := NewUserService(apiClient)
w.userResource = userService.GetUser(context.Background(), 1)
w.initialized.Set(true)
}
// Get reactive state
state := w.userResource.Get()
// Handle states
if state.Loading {
return &widgets.Text{Text: "Loading..."}
}
if state.Error != nil {
return &widgets.Text{Text: fmt.Sprintf("Error: %v", state.Error)}
}
// Display data
return &widgets.Text{Text: state.Data.Name}
}Demonstrates:
- Fetching a list of users
- Displaying loading state
- Error handling
- Rendering list items
Demonstrates:
- User posts by ID
- Expandable comments
- Multiple resources in one widget
- Interactive state with signals
Comprehensive tests in:
client_test.go- HTTP client tests, middleware chainresource_test.go- Resource state management
To run tests:
go test ./pkg/api/... -v✅ Simple API: Familiar GET/POST/PUT/DELETE methods ✅ Reactive: Automatic widget rebuilds ✅ Type Safe: Compile-time type checking ✅ Error Handling: Built-in error state ✅ Loading States: Automatic loading indicators
✅ Testable: Easy to mock services ✅ Extensible: Middleware pattern ✅ Organized: Service layer pattern ✅ Reusable: Share services across widgets ✅ Maintainable: Clear separation of concerns
Potential improvements:
-
Caching Layer
- Response caching
- Cache invalidation
- TTL support
-
Optimistic Updates
- Update UI before server confirms
- Rollback on error
-
Pagination Support
- Built-in pagination helpers
- Infinite scroll support
-
GraphQL Support
- GraphQL client
- Query builder
-
WebSocket Support
- Real-time updates
- SSE (Server-Sent Events)
-
Request Debouncing
- Prevent duplicate requests
- Cancel in-flight requests
-
Upload/Download Progress
- Track progress
- Show progress bars
This implementation advances Phase 4.4 (Q4 2025) of the GoFlow roadmap:
- ✅ HTTP client with middleware
- ✅ JSON serialization helpers
- ✅ REST API builder pattern
- ⏳ WebSocket support (future)
- ⏳ GraphQL client (future)
See pkg/api/README.md for:
- Complete API reference
- Best practices
- Advanced examples
- Migration guide
The REST API library provides a robust, reactive foundation for making HTTP requests in GoFlow applications. It integrates seamlessly with the Signals system and provides patterns familiar to developers from Flutter and modern web frameworks.
The library is production-ready for basic use cases and provides a solid foundation for future enhancements.