With our types and data store in place,
we will now want to expose these in the API.
Add a Resource definition to the schema
Update our generator definition
Add the template for API resources
Wire resources into the router
Schema Additions
We first add a schema for a resource
and a CUE ‘function’
for converting models to resources.
gen/server.cue
// Resources are pretty simple#Resources: [string]: #Resource#Resource: { Model: #Model Name: Model.Name Routes: #Routes}// We map from Datamodle to Resource#DatamodelToResources: { Datamodel: #Datamodel Resources: #Resources & {for n, M in Datamodel.Models {// sub-value with same name as label as the model"\(n)": {// Same model and name Model: M Name: M.Name// The default CRUD routes Routes: [{ Name: "\(M.Name)Create" Path: "" Method: "POST" }, { Name: "\(M.Name)Read" Path: "" Params: ["\(strings.ToLower(M.Index))"] Method: "GET" }, { Name: "\(M.Name)Update" Path: "" Method: "PATCH" }, { Name: "\(M.Name)Delete" Path: "" Params: ["\(strings.ToLower(M.Index))"] Method: "DELETE" }, ...] // left open so you can add custom routes } } }}
Generator Changes
Add the following changes in their appropriate places into the existing generator definition.
gen/server.cue
Generator: gen.Generator & {// We make resources from the data model// and there is no new inputs for the user In: { Resources: (schema.DatamodelToResources & {"Datamodel": Datamodel}).Resources }// Add a new line in _All All: [ for _, F in ResourceFiles {F}, ]// Define the resource Files ResourceFiles: [...gen.File] & [ for _, R in In.Resources { In: { RESOURCE: R } TemplatePath: "resource.go" Filepath: "\(Outdir)/resources/\(In.RESOURCE.Name).go" }, ]}
Resource Template
The following creates CRUD handlers.
Note how we can reuse our route handler partial template
because we added these in the schema and mapping.
Create a new template called resource.go
templates/resource.go
package resources
import (
"fmt""net/http""github.com/labstack/echo/v4")
// {{ .RESOURCE.Name }}Routes sets up the routes in a router Group
func {{ .RESOURCE.Name }}Routes(G *echo.Group) {
fmt.Println("adding {{.RESOURCE.Name}} routes")
g := G.Group("/{{ kebab .RESOURCE.Name }}")
// wire up CRUD routes
{{ range$R := .RESOURCE.Routes }}
g.{{ $R.Method }}( "{{ range $PATH := $R.Params }}/:{{$PATH}}{{ end }}", {{ $R.Name }}Handler)
{{- end }}
}
{{ range$R := .RESOURCE.Routes }}
{{ template "handler.go"$R }}
{{ end }}