Published:

Jarle Aase

Version 0.90 of restc-cpp with important new features

bookmark 2 min read

Why so long?

I have been using restc-cpp in a numer of projects over the last year, and I have added new features as the need has arrived. However, until today, this work as happened mostly in branches. The reason for holding back changes from the master branch is stability. I have been reluctant to pay Apple the yearly 100 US$ ransom for using their development tools (I have no paying customers at the moment that require any work on Apples platforms, so the 100 US$ ransom is solely for the pleasure of providing apple fan girls with free open source tools. Without the compiler working on the macbook (yes, I have a dedicated Macbook Pro where I run a Jenkins slave to build and test the Mac version of restc-cpp (and other open source projects) - since Apple, as the only platform in 2021, don't support virtual machines for building and testing software. They still live in the 1980's) - I cannot test the code for Mac.

The slow move of my projects towards irrelevance however made me pay the rensom a few days ago, and today I merged the latest work into the staging branch and started to look at the compatibility with the different platforms I test on.

I also wanted to add the latest Ubuntu LTS - but until they figure out how to make their 21.04 release work in Docker, they can go gmock themselves.

What's new?

std::optional support

I refactored the serializer/deserializer for C++17 to simplify the code and to make it feasible to add some neat new features. The most significant is full support for std::optional<>.

In the past, you could tell the serializer to skip empty fields. For example, an empty list or a integer with value == 0 or an bool with value == false would all be interpreted as empty and skipped. However, in some cases you actually want to send a 0 integer or false value to an API. Also, data objects would not be removed in the original implementation, even if all their data members was empty. For example, if the data structure below was serialized, the json would look like {"flags":{}}. That's valid json, but potentially not valid data for an API.

struct flags {
  bool enabled{false};
};

struct data {
  flags my_flags;
};

I ran into this problem when I implemented parts of the kubernetes REST API using restc-cpp. The kubernetes API server is implemented using golang, and it turns out that it often cannot deal with empty data objects. Either you must fill inn the data members with some valid values, or you must not send the date member at all. In some cases where they implement unions as:

struct example {
  OptionOne optionOne;
  OptionTwo optionTwo;

}

you are supposed to only fill in one of the option, and the API server will reject the request if you provide both options or no options. In restc-cpp, this is now solved by using std::optional<>.

The example above will work in this situation if we say:

struct example {
  std::optional<OptionOne> optionOne;
  std::optional<OptionTwo> optionTwo;

}

... and only set a value in one of the options.

If we redo the first example as:

struct flags {
  std::optional<bool> enabled{false};
};

struct data {
  flags my_flags;
};


The data serialized from d will look like: {"flags":{"enabled":false}}

This is something I have missed for a very long time, and I hope it will prove as useful to you as it did to me.

In addition to std::optional, the C++17 version of the serializer and deserializer will give more helpful error-messages.

CMAKE subproject

I'm using the setup below to integrate restc-cpp with my CMAKE project.

set(EXTERNAL_PROJECTS_PREFIX ${CMAKE_BINARY_DIR}/external-projects)
set(EXTERNAL_PROJECTS_INSTALL_PREFIX ${EXTERNAL_PROJECTS_PREFIX}/installed)

include(GNUInstallDirs)

# MUST be called before any add_executable() # https://stackoverflow.com/a/40554704/8766845
link_directories(${EXTERNAL_PROJECTS_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
include_directories($<BUILD_INTERFACE:${EXTERNAL_PROJECTS_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}>)

include(ExternalProject)

ExternalProject_Add(externalRestcCpp
    PREFIX "${EXTERNAL_PROJECTS_PREFIX}"
    GIT_REPOSITORY "https://github.com/jgaa/restc-cpp.git"
    CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX=${EXTERNAL_PROJECTS_INSTALL_PREFIX}
        -DRESTC_CPP_WITH_UNIT_TESTS=OFF
        -DRESTC_CPP_WITH_FUNCTIONALT_TESTS=OFF
        -DRESTC_CPP_WITH_EXAMPLES=OFF
        -DRESTC_CPP_USE_CPP17=ON
        -DRESTC_CPP_LOG_WITH_BOOST_LOG=OFF
        -DBOOST_ROOT=${BOOST_ROOT}
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DRESTC_BOOST_VERSION=${USE_BOOST_VERSION}
        -DBOOST_ERROR_CODE_HEADER_ONLY=1
    )

On github