# Data Transfer Object (DTO)

DTO is any object of the class which extends oatpp::DTO. It is a special object which can be Serialized and Deserialized with the help of oatpp::data::mapping::ObjectMapper.

# Declaration

DTO objects are generated within DTO-code-gen section. DTO code generation section must begin with
#include OATPP_CODEGEN_BEGIN(DTO) and must be closed with #include OATPP_CODEGEN_END(DTO). Do not forget to close code generation section in order to avoid macro conflicts later in the code!

#include "oatpp/core/Types.hpp"
#include "oatpp/core/macro/codegen.hpp"

#include OATPP_CODEGEN_BEGIN(DTO) ///< Begin DTO codegen section

class User : public oatpp::DTO {

  DTO_INIT(User, DTO /* extends */)

  DTO_FIELD(String, name);
  DTO_FIELD(Int32, age);


#include OATPP_CODEGEN_END(DTO) ///< End DTO codegen section

# Field Name Qualifier

DTO_FIELD(String, name, "user-name");

# Default Value

By default all values are set to nullptr. You can override default values by assigning values to DTO fields.

DTO_FIELD(String, name) = "Ivan";

# Additional Field Info

  info->description = "user first name"; //<-- Fields description is integrated with Swagger-UI.
DTO_FIELD(String, name) = "Ivan";

# Declare Field As Object

DTO_FIELD(Object<User>, user);

# Declare Field As List

List of primitives:

DTO_FIELD(List<Int32>, colors);

List of Objects:

DTO_FIELD(List<Object<MyObject>>, colors);

# Declare Field As Map

Map String --> Int32:

DTO_FIELD(Fields<Int32>, colors);

Map String --> Object:

DTO_FIELD(Fields<Object<MyObject>>, colors);

# Core Types

Types defined in oatpp/core/Types.hpp.

# Primitives

Type Underlying Type Default Value
Int8 v_int8 nullptr
UInt8 v_uint8 nullptr
Int16 v_int16 nullptr
UInt16 v_uint16 nullptr
Int32 v_int32 nullptr
UInt32 v_uint32 nullptr
Int64 v_int64 nullptr
UInt64 v_uint64 nullptr
Float32 v_float32 nullptr
Float64 v_float64 nullptr
Boolean bool nullptr
# Examples
oatpp::Int32 a = 32;
v_int32 va = *a;

# Collections

Type Underlying Collection Default Value
Vector<T> std::vector<T> nullptr
List<T> std::list<T> nullptr
UnorderedSet<T> std::unordered_set<T> nullptr
Fields<T> std::list<std::pair<Key, Value>> nullptr
UnorderedFields<T> std::unordered_map<Key, Value> nullptr
# Examples
oatpp::Vector<oatpp::String> porridges = {"Owsianka", "Stirabout", "Zabkása"};
for(auto& porridge : *porridges) {

# Special Types

Type Underlying Type Default Value
String oatpp::base::StrBuffer nullptr
Object<T> class which extends oatpp::DTO nullptr
Enum<T> enum declared via ENUM nullptr
Any any other mapping-enabled type nullptr
# Examples
oatpp::Object<MyDto> dto = MyDto::createShared();
oatpp::Any any = dto;
auto dto = any.retrieve<oatpp::Object<MyDto>>(); // throws `std::runtime_error` if stored type doesn't match.

# Custom Types

To simplify the integration of custom types with oatpp Object-Mapping framework the "Type Interpretation" feature was introduced.
For information about custom object mapping contact us in dev-chat

Let's say you have some struct that is not part of oatpp object-mapping framework.

struct VPoint {
  v_int32 x;
  v_int32 y;
  v_int32 z;

To integrate it with oatpp object-mapping you can do the following:

namespace __class {
  class PointClass;

/* Declare ObjectWrapper for your type */
/* Mapping-Enabled Point */
typedef oatpp::data::mapping::type::Primitive<VPoint, __class::PointClass> Point;

namespace __class {

   * Type info
  class PointClass {

     * Type interpretation
    class Inter : public oatpp::Type::Interpretation<Point, oatpp::UnorderedFields<oatpp::Int32>>  {

      oatpp::UnorderedFields<oatpp::Int32> interpret(const Point& value) const override {
          return {{"x", value->x}, {"y", value->y}, {"z", value->z}};

      Point reproduce(const oatpp::UnorderedFields<oatpp::Int32> map) const override {
        return Point({map["x"], map["y"], map["z"]});



    static const oatpp::ClassId CLASS_ID;

    static oatpp::Type* getType(){
      static Type type(CLASS_ID, nullptr, nullptr, {{"my-types", new Inter()}} /* <-- Add type interpretation */ );
      return &type;


  const oatpp::ClassId PointClass::CLASS_ID("my-types::Point");


Now the "Point" struct can be serialized/deserialized with object mappers.

oatpp::parser::json::mapping::ObjectMapper mapper;

  auto config = mapper.getSerializer()->getConfig();
  config->enabledInterpretations = {"my-types"}; // Enable "my-types" for serializer

  auto config = mapper.getDeserializer()->getConfig();
  config->enabledInterpretations = {"my-types"}; // Enable "my-types" for deserializer

Point point ({1, 2, 3}); // Create mapping-enabled Point

auto json = mapper.writeToString(point); // Serialize Point
auto pointClone = mapper.readFromString<Point>(json); // Deserialize Point

Note: Type interpretations work through all framework components including REST framework, ORM, and Swagger-UI.

# Example

# Serialize / Deserialize

# Define DTO

#include "oatpp/core/Types.hpp"
#include "oatpp/core/macro/codegen.hpp"

#include OATPP_CODEGEN_BEGIN(DTO) ///< Begin DTO codegen section

class User : public oatpp::DTO {

  DTO_INIT(User, DTO /* extends */)

  DTO_FIELD(String, name, "First-Name");
  DTO_FIELD(String, surname, "Family-Name");
  DTO_FIELD(Int32, age);
  DTO_FIELD(Fields<List<Object<User>>>, familyMembers); ///< Map<String, List<User>>
  DTO_FIELD(Fields<String>, additionalNotes); ///< Map<String, String>


#include OATPP_CODEGEN_END(DTO) ///< End DTO codegen section

# Create object and set fields

/* create user */
auto user = User::createShared();
user->name = "Ivan";
user->surname = "Ovsyanochka";
user->age = 24;
user->familyMembers = {}; // Initialize empty map.
user->additionalNotes = {}; // Initialize empty map.

/* create user */
auto brother = User::createShared();
brother->name = "Yuriy";
brother->surname = "Ovsyanochka";
brother->age = 30;

/* create user */
auto sister = User::createShared();
sister->name = "Kate";
sister->surname = "Ovsyanochka";
sister->age = 20;

/* create list of siblings */
oatpp::List<oatpp::Object<User>> siblings = {brother, sister};

user->familyMembers->push_back({"siblings", siblings});
user->additionalNotes->push_back({"Education", "Master of Computer Science"});

# Create JSON object mapper

#include "oatpp/parser/json/mapping/ObjectMapper.hpp"


/* create json ObjectMapper with default configs */
auto jsonObjectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared();

# Serialize user to json

oatpp::String json = jsonObjectMapper->writeToString(user); 
OATPP_LOGD("json", "value='%s'", json->c_str()); ///< print json


  "First-Name": "Ivan",
  "Family-Name": "Ovsyanochka",
  "age": 24,
  "familyMembers": {
    "siblings": [
        "First-Name": "Yuriy",
        "Family-Name": "Ovsyanochka",
        "age": 30,
        "familyMembers": null,
        "additionalNotes": null
        "First-Name": "Kate",
        "Family-Name": "Ovsyanochka",
        "age": 20,
        "familyMembers": null,
        "additionalNotes": null
  "additionalNotes": {
    "Education": "Master of Computer Science"

Please note: example of above output is beautified with oatpp::parser::json::Beautifier.

# Deserizalize from String

auto cloneOfUser = jsonObjectMapper->readFromString<oatpp::Object<User>>(json);

# Use JSON Beautifier

Without the use of beautifier the json serializer output will contain no spaces nor newline character:

{"First-Name":"Ivan","Family-Name":"Ovsyanochka","age":24 ...

In order to beautify json output set useBeautifier = true in serializer config:

/* create serializer and deserializer configurations */
auto serializeConfig = oatpp::parser::json::mapping::Serializer::Config::createShared();
auto deserializeConfig = oatpp::parser::json::mapping::Deserializer::Config::createShared();

/* enable beautifier */
serializeConfig->useBeautifier = true;

/* create json object mapper with serializer config */
auto jsonObjectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared(serializeConfig, deserializeConfig);

More about json object mapper configuration see:

# Examples of code