Routing
Gleece is designed to minimize HTTP routing boilerplate code, allowing developers to focus on business logic.
A route is essentially a function within a controller that is annotated with the @Route
annotation.
Creating a Controller
First, create a controller struct that extends the GleeceController from Gleece's runtime. Annotate the controller with the base routing path, which will serve as the prefix for all routes in that controller.
You can also set the security schema and scopes for the entire controller (these can be overridden per route later).
import "github.com/gopher-fleece/runtime"
// @Route(/base-path)
// @Security(securitySchemaName, { scopes: ["read"] })
type ExampleController struct {
runtime.GleeceController // Embedding the GleeceController to inherit its methods
}
Creating a Route
Create a function in the controller to handle the logic and annotate it with the @Method
and @Route
annotations:
// @Method(GET)
// @Route(/simple-get)
func (ec *ExampleController) SimpleGet() (string, error) {
return "works", nil
}
To access data from the HTTP request, add parameters to the function along with corresponding annotations indicating their source:
// @Method(GET)
// @Route(/simple-get)
// @Query(name, { validate: "required" })
// @Response(200)
func (ec *ExampleController) SimpleGet(name string) (string, error) {
return "Hello " + name, nil
}
Parameters can be sourced from:
@Query
- Query parameters in the URL@Path
- URL path parameters@Header
- HTTP headers@Body
- Request body@FromField
- Request urlencoded form fields
Multiple instances of @Query
, @Path
, @FromField
, and @Header
annotations are allowed in a single route.
However, only one @Body
annotation is allowed per route.
For REST parameters a non-pointer arguments are always considered mandatory, regardless of the validate
content. Path parameters are always mandatory as per the OpenAPI specification (a missing path results in a 404
error).
Parameter Types
All HTTP request parameters can be only primitives, primitives aliases/enums or pointers to primitives types.
Except for @Body
that supports only non-primitive types.
Body Processing Constraints
The @Body
and @FromField
annotations should not be used together in the same route as they represent different approaches to processing the request body payload:
@FromField
- Processes individual fields fromapplication/x-www-form-urlencoded
request payload@Body
- Processes completeapplication/json
request payload
Response Types
Route handlers in Gleece follow a consistent return pattern. While the return type is optional, when specified, it should be a tuple in the form of (<response type>, error)
:
- The first value represents the response payload that will be serialized to JSON
- The second value indicates any error that occurred during processing
The response payload can be anything that supported by Gleece's modeling. see the Modeling page for more details.
Complete Example
Here's a comprehensive example of a controller with annotated routes:
package controllers
import (
"github.com/google/uuid"
"github.com/gopher-fleece/runtime"
)
// @Description Example object
type Example struct {
// @Description Some text
Text string `json:"text" validate:"required"`
// @Description Some number
Number int `json:"number" validate:"gte=1"`
}
// @Tag(Example)
// @Route(/base-path)
// @Security(securitySchemaName, { scopes: ["read"] })
// @Description The Example API
type ExampleController struct {
runtime.GleeceController
}
// @Description Create an example
// @Method(POST)
// @Route(/logic/{example_name}/{example_id})
// @Query(email, { validate: "required,email" }) The exampler email
// @Path(id, { name: "example_id", validate:"gt=1" }) The example ID
// @Path(name, { name: "example_name" }) The example's name
// @Body(example) The example object
// @Header(origin, { name: "x-origin" }) The request origin
// @Header(trace) The trace ID
// @Response(200) The new ID of the example
// @ErrorResponse(500) Error when processing fails
// @Security(securitySchemaName, { scopes: ["read", "write"] })
func (ec *ExampleController) ExampleLogic(
id int,
email string,
name string,
origin string,
trace *string,
example Example) (string, error) {
newId := uuid.New()
return example.Text + " " + newId.String(), nil
}
For detailed information about all available annotations and their options, please refer to the Annotations page.