Skip to content
Download

Model Binding

Model binding lets controller actions receive a request body as a strongly typed C++ value.

Instead of reading and deserializing the request body manually, you can declare a parameter on the action and let Mach bind the body for you.

Consider a model used when creating a user:

struct CreateUserRequest {
std::string name;
int age;
};
MACH_DEFINE_JSON(CreateUserRequest, name, age)

The model can be accepted directly by a controller action:

mach::Reply<std::string> createUser(CreateUserRequest user) {
return ok(user.name);
}

For a request body such as:

{
"name": "Alice",
"age": 24
}

Mach deserializes the body into a CreateUserRequest and passes it to createUser() by value.

The action can then work with the strongly typed object without manually parsing the request body.

For user-defined types, use MACH_DEFINE_JSON to define how the type maps to JSON:

struct CreateUserRequest {
std::string name;
int age;
};
MACH_DEFINE_JSON(CreateUserRequest, name, age)

List the fields that should participate in serialization and deserialization after the model type.

MACH_DEFINE_JSON integrates Mach models with its JSON serialization support and is based on nlohmann/json’s non-intrusive JSON mapping.

Primitive types do not require MACH_DEFINE_JSON.

Body-bound actions are mapped like any other controller action:

class UsersController final : public mach::ControllerBase {
public:
inline static constexpr std::string_view route = "/users";
mach::Reply<std::string> createUser(CreateUserRequest user) {
return ok(user.name);
}
static void configure(mach::ControllerBuilder<UsersController>& builder) {
builder.mapPost("/", &UsersController::createUser);
}
};

When a matching request reaches the action, Mach uses the request body to construct the action parameter before invoking it.

An action can also bind a request body directly to a primitive type without defining a JSON model.

For example:

mach::Reply<int> doubleValue(int value) {
return ok(value * 2);
}

Mach binds the request body to the action parameter using its expected type.

Automatic model binding currently applies to request bodies.

Other request data is accessed through the Request API. For example, a route parameter can be retrieved with:

const int id = request().routeParam<int>("id");

Next, you’ll learn how controller actions create and return HTTP responses.