REST API Framework Overview
Forge includes a REST API framework inspired by Django REST Framework (DRF): a viewset serves the CRUD routes of one model, a serializer shapes its JSON, and a router mounts viewsets on the application's router.
Architectural Principles
- ViewSets:
api.BaseViewSetserves list, create, retrieve, update, partial update and destroy for one model from a manager such as the generated<Model>Objects. - Serializers: a factory returning an
api.Serializer. OptionalFields(),Exclude(),ReadonlyFields()andWriteOnlyFields()methods shape responses and requests. Model validation (validatetags andClean()) runs on create and update. - Pagination: List responses are paginated by page number (
page,page_size). - Filtering and ordering:
?field=value, lookups such as?price__gte=10, and?ordering=-priceon list requests. - Rate Throttling: per-user and per-IP rate throttles (
api/throttling) answer429when a client exceeds its rate. - OpenAPI skeleton:
api/docsserves an OpenAPI 3.0 document with theinfoblock only; paths and schemas are not generated yet.
Complete Example
forge generate writes the Product model's ProductObjects manager; forge add api writes a registration function like this one.
package catalog
import (
"github.com/forgego/forge/api"
"github.com/forgego/forge/api/throttling"
"github.com/forgego/forge/server"
)
// 1. Define a serializer. Fields limits the keys in every response.
type ProductSerializer struct {
*api.BaseSerializer
}
func NewProductSerializer() api.Serializer {
return &ProductSerializer{BaseSerializer: api.NewBaseSerializer(nil)}
}
func (s *ProductSerializer) Fields() []string {
return []string{"id", "sku", "name", "price", "in_stock"}
}
// 2. Build the viewset and register it on the application's router.
func RegisterProductAPI(router *server.Router) {
viewset := api.NewBaseViewSet(NewProductSerializer, ProductObjects, &Product{})
viewset.ExcludeResponseFields = api.NonSerializableFields(&Product{})
viewset.ReadOnlyRequestFields = api.NonEditableFields(&Product{})
viewset.RejectUnknownRequestFields = true
viewset.Throttles = []throttling.Throttle{throttling.NewUserRateThrottle("100/min")}
apiRouter := api.NewRouter("/api/v1")
apiRouter.Register("products", viewset)
apiRouter.RegisterRoutes(router)
}
Register binds the standard REST routes under the router prefix:
GET /api/v1/products/— List with pagination, filters, and orderingPOST /api/v1/products/— Create a record with input validationGET /api/v1/products/{id}— Retrieve a single recordPUT /api/v1/products/{id}— Full updatePATCH /api/v1/products/{id}— Partial updateDELETE /api/v1/products/{id}— Delete a record
Register and RegisterRoutes panic when the viewset's data access cannot serve these routes; see ViewSet Data Access.
Next Steps
- ModelSerializers: Field whitelisting and validation.
- ViewSets: Custom actions and scoping the queryset.
- Pagination: Page-number pagination and page size settings.
- OpenAPI: What the OpenAPI document contains today.