diff --git a/common/cpp/include/json_parser/json_parser.h b/common/cpp/include/json_parser/json_parser.h
index 8ca8ce02b4ff5d60840d61f7fab5669caee43124..7373e91a74bf5043487846b675be1ce29fc62363 100644
--- a/common/cpp/include/json_parser/json_parser.h
+++ b/common/cpp/include/json_parser/json_parser.h
@@ -3,6 +3,8 @@
 
 #include <string>
 #include <memory>
+#include <vector>
+#include <string>
 
 #include "common/error.h"
 
@@ -14,10 +16,16 @@ class JsonParser {
   public:
     JsonParser(const std::string& json, bool read_from_file);
     ~JsonParser();
+    JsonParser(JsonParser&& other);
     Error GetUInt64(const std::string& name, uint64_t* val) const noexcept;
     Error GetString(const std::string& name, std::string* val) const noexcept;
+    Error GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept;
+    Error GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept;
+    JsonParser Embedded(const std::string& name) const noexcept;
   private:
     std::unique_ptr<RapidJson>  rapid_json_;
+    JsonParser(RapidJson* rapid_json_);
+
 };
 
 }
diff --git a/common/cpp/src/json_parser/json_parser.cpp b/common/cpp/src/json_parser/json_parser.cpp
index d9f6f49ec05cd1b166bd5b88be202030be84ebcd..1a848557881de69cf1fbcab77fcc2997e6f28d00 100644
--- a/common/cpp/src/json_parser/json_parser.cpp
+++ b/common/cpp/src/json_parser/json_parser.cpp
@@ -11,6 +11,16 @@ JsonParser::~JsonParser() {
 JsonParser::JsonParser(const std::string& json, bool read_from_file) : rapid_json_{new RapidJson(json, read_from_file)} {
 }
 
+Error JsonParser::GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept {
+    return rapid_json_->GetArrayUInt64(name, val);
+
+}
+
+Error JsonParser::GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept {
+    return rapid_json_->GetArrayString(name, val);
+}
+
+
 Error JsonParser::GetUInt64(const std::string& name, uint64_t* val) const noexcept {
     return rapid_json_->GetUInt64(name, val);
 }
@@ -19,6 +29,18 @@ Error JsonParser::GetString(const std::string& name, std::string* val) const noe
     return rapid_json_->GetString(name, val);
 }
 
+JsonParser JsonParser::Embedded(const std::string& name) const noexcept {
+    RapidJson* rapid_json = new RapidJson(*rapid_json_.get(), name);
+    return JsonParser(rapid_json);
+}
+
+JsonParser::JsonParser(RapidJson* json) : rapid_json_{json} {
+}
+
+JsonParser::JsonParser(JsonParser&& other) {
+    rapid_json_ = std::move(other.rapid_json_);
+}
+
 }
 
 
diff --git a/common/cpp/src/json_parser/rapid_json.cpp b/common/cpp/src/json_parser/rapid_json.cpp
index 6c3a875992065fa594ae9cce578d4b5a2f9ba8a2..e3f1f6ee55a9839476b3fe9eb2eb014fe61b137f 100644
--- a/common/cpp/src/json_parser/rapid_json.cpp
+++ b/common/cpp/src/json_parser/rapid_json.cpp
@@ -1,4 +1,5 @@
 #include "rapid_json.h"
+#include "rapid_json.h"
 
 using namespace rapidjson;
 
@@ -11,6 +12,10 @@ RapidJson::RapidJson(const std::string& json, bool read_from_file): io__{new Sys
 }
 
 Error RapidJson::LazyInitialize()const noexcept {
+    if (embedded_error_) {
+        return TextError(embedded_error_->Explain());
+    }
+
     if (initialized_)
         return nullptr;
 
@@ -27,19 +32,26 @@ Error RapidJson::LazyInitialize()const noexcept {
         return TextError("Cannot parse document");
     }
 
-    return nullptr;
+    object_ = doc_.GetObject();
 
+    return nullptr;
 }
 
 hidra2::Error CheckValueType(const std::string& name, ValueType type, const Value& val) {
     bool res = false;
     switch (type) {
+    case ValueType::kObject:
+        res = val.IsObject();
+        break;
     case ValueType::kString:
         res = val.IsString();
         break;
     case ValueType::kUint64:
         res = val.IsInt64();
         break;
+    case ValueType::kArray:
+        res = val.IsArray();
+        break;
     }
     if (!res) {
         return TextError("wrong type: " + name);
@@ -54,8 +66,8 @@ hidra2::Error RapidJson::GetValue(const std::string& name, ValueType type, Value
         return err;
     }
 
-    auto iterator = doc_.FindMember(name.c_str());
-    if (iterator == doc_.MemberEnd()) {
+    auto iterator = object_.FindMember(name.c_str());
+    if (iterator == object_.MemberEnd()) {
         return  TextError("cannot find: " + name);
     }
 
@@ -63,7 +75,6 @@ hidra2::Error RapidJson::GetValue(const std::string& name, ValueType type, Value
     return CheckValueType(name, type, *val);
 }
 
-
 Error RapidJson::GetUInt64(const std::string& name, uint64_t* val) const noexcept {
     Value json_val;
     if (Error err = GetValue(name, ValueType::kUint64, &json_val)) {
@@ -73,9 +84,6 @@ Error RapidJson::GetUInt64(const std::string& name, uint64_t* val) const noexcep
     return nullptr;
 }
 
-
-
-
 Error RapidJson::GetString(const std::string& name, std::string* val) const noexcept {
     Value json_val;
     if (Error err = GetValue(name, ValueType::kString, &json_val)) {
@@ -86,4 +94,47 @@ Error RapidJson::GetString(const std::string& name, std::string* val) const noex
 }
 
 
+Error RapidJson::GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kArray, &json_val)) {
+        return err;
+    }
+
+    for (auto& v : json_val.GetArray()) {
+        if (!v.IsInt64()) {
+            return TextError("wrong type of array element: " + name);
+        }
+        val->push_back(v.GetInt());
+    }
+    return nullptr;
+
+}
+
+Error RapidJson::GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept {
+    Value json_val;
+    if (Error err = GetValue(name, ValueType::kArray, &json_val)) {
+        return err;
+    }
+
+    for (auto& v : json_val.GetArray()) {
+        if (!v.IsString()) {
+            return TextError("wrong type of array element: " + name);
+        }
+        val->push_back(v.GetString());
+    }
+    return nullptr;
+
+}
+
+
+RapidJson::RapidJson(const RapidJson& parent, const std::string& subname) {
+    auto err = parent.GetValue(subname, ValueType::kObject, &object_);
+    if (err) {
+        embedded_error_ = std::move(err);
+        return;
+    }
+    initialized_ = true;
+}
+
+
 }
\ No newline at end of file
diff --git a/common/cpp/src/json_parser/rapid_json.h b/common/cpp/src/json_parser/rapid_json.h
index 5aad1ff20133f33c2dca3ab057dc9e836c88ecb1..6f55934c2a159eb8746a1132669e6f58c0b31e70 100644
--- a/common/cpp/src/json_parser/rapid_json.h
+++ b/common/cpp/src/json_parser/rapid_json.h
@@ -10,21 +10,29 @@ namespace hidra2 {
 
 enum class ValueType {
     kUint64,
-    kString
+    kString,
+    kObject,
+    kArray
 };
 
 class RapidJson {
   public:
     RapidJson(const std::string& json, bool read_from_file);
+    RapidJson(const RapidJson& parent, const std::string& subname);
     Error GetUInt64(const std::string& name, uint64_t* val) const noexcept;
     Error GetString(const std::string& name, std::string* val) const noexcept;
+    Error GetArrayUInt64(const std::string& name, std::vector<uint64_t>* val) const noexcept;
+    Error GetArrayString(const std::string& name, std::vector<std::string>* val) const noexcept;
     std::unique_ptr<IO> io__;
   private:
     mutable rapidjson::Document doc_;
+    mutable rapidjson::Value object_;
     std::string json_;
     bool read_from_file_;
     mutable bool initialized_ = false;
     Error LazyInitialize() const noexcept;
+    Error embedded_error_ = nullptr;
+
     hidra2::Error GetValue(const std::string& name, ValueType type, rapidjson::Value* val)const noexcept;
 };
 
diff --git a/common/cpp/unittests/json_parser/test_json_parser.cpp b/common/cpp/unittests/json_parser/test_json_parser.cpp
index 4de52be0bf32fe58aca700af5d4d6e4b699f6272..d4545a5a0129152ee7b03099cab941113db5be53 100644
--- a/common/cpp/unittests/json_parser/test_json_parser.cpp
+++ b/common/cpp/unittests/json_parser/test_json_parser.cpp
@@ -18,6 +18,7 @@ using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 using ::testing::HasSubstr;
+using ::testing::ElementsAre;
 
 using hidra2::JsonParser;
 using hidra2::RapidJson;
@@ -27,7 +28,7 @@ using hidra2::IO;
 
 namespace {
 
-TEST(ParseString, CorrectConvertToJson) {
+TEST(ParseString, SimpleConvertToJson) {
     std::string json = R"({"_id":2,"foo":"foo","bar":1})";
 
     JsonParser parser{json, false};
@@ -48,6 +49,67 @@ TEST(ParseString, CorrectConvertToJson) {
 
 }
 
+TEST(ParseString, EmbeddedConvertToJson) {
+    std::string json = R"({"id":{"test":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err1 = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err1, Eq(nullptr));
+    ASSERT_THAT(id, Eq(2));
+}
+
+TEST(ParseString, DoubleEmbeddedConvertToJson) {
+    std::string json = R"({"id":{"test":{"test2":2}}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err1 = parser.Embedded("id").Embedded("test").GetUInt64("test2", &id);
+
+    ASSERT_THAT(err1, Eq(nullptr));
+    ASSERT_THAT(id, Eq(2));
+}
+
+
+TEST(ParseString, ErrorOnWrongEmbeddedKey) {
+    std::string json = R"({"id1":{"test":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
+
+TEST(ParseString, ErrorOnWrongEmbeddedSubKey) {
+    std::string json = R"({"id1":{"test1":2}})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.Embedded("id").GetUInt64("test", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
+
+
+TEST(ParseString, ErrorOnWrongKey) {
+    std::string json = R"({"_id":"2"})";
+
+    JsonParser parser{json, false};
+
+    uint64_t id;
+    auto err = parser.GetUInt64("_id1", &id);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
+}
 
 TEST(ParseString, ErrorOnWrongType) {
     std::string json = R"({"_id":"2"})";
@@ -75,6 +137,46 @@ TEST(ParseString, ErrorOnWrongDocument) {
 
 }
 
+
+TEST(ParseString, IntArrayConvertToJson) {
+    std::string json = R"({"array":[1,2,3]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<uint64_t> vec;
+    auto err = parser.GetArrayUInt64("array", &vec);
+
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(vec, ElementsAre(1, 2, 3));
+}
+
+
+TEST(ParseString, IntArrayErrorConvertToJson) {
+    std::string json = R"({"array":[1,2,"3"]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<uint64_t> vec;
+    auto err = parser.GetArrayUInt64("array", &vec);
+
+    ASSERT_THAT(err, Ne(nullptr));
+    ASSERT_THAT(err->Explain(), HasSubstr("type"));
+}
+
+
+TEST(ParseString, StringArrayConvertToJson) {
+    std::string json = R"({"array":["s1","s2","s3"]})";
+
+    JsonParser parser{json, false};
+
+    std::vector<std::string> vec;
+    auto err = parser.GetArrayString("array", &vec);
+
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(vec, ElementsAre("s1", "s2", "s3"));
+}
+
+
 class ParseFileTests : public Test {
   public:
     RapidJson parser{"filename", true};
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 9cd78d4856eea4c5cfb467e47eeb361c54c19663..0fb7141827c5997da8294a401a2bb2a3721a238e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,8 @@ find_package(Threads)
 add_subdirectory(common/cpp)
 add_subdirectory(system_io)
 
+add_subdirectory(json_parser)
+
 if(BUILD_MONGODB_CLIENTLIB)
     add_subdirectory(mongo_db)
 endif()
diff --git a/tests/json_parser/CMakeLists.txt b/tests/json_parser/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..97a6482ba7df9c128c135a58c05f823d661385ad
--- /dev/null
+++ b/tests/json_parser/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(parse_config_file)
diff --git a/tests/json_parser/parse_config_file/CMakeLists.txt b/tests/json_parser/parse_config_file/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..51aff5e133cfb1f40e45fb3febfba181aa3ff28d
--- /dev/null
+++ b/tests/json_parser/parse_config_file/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(TARGET_NAME parse_config_file)
+set(SOURCE_FILES parse_config_file.cpp)
+
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES})
+target_link_libraries(${TARGET_NAME} test_common hidra2-worker)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+
+################################
+# Testing
+################################
+
+add_integration_test(${TARGET_NAME} parseOK "${CMAKE_CURRENT_SOURCE_DIR}/config.json OK")
+add_integration_test(${TARGET_NAME} parseFails "${CMAKE_CURRENT_SOURCE_DIR}/config_bad.json FAIL")
+
+
diff --git a/tests/json_parser/parse_config_file/config.json b/tests/json_parser/parse_config_file/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..06f8798f2fd07e3558e274f32fef4234e9dd46b3
--- /dev/null
+++ b/tests/json_parser/parse_config_file/config.json
@@ -0,0 +1,14 @@
+{
+  "server":"some_string",
+
+  "port": 10,
+  "//": "This is a way to make comments",
+  "some_array":[1,2,3],
+  "//": "Another comment",
+  "some_string_array":["s1","s2","s3"],
+  "embedded_stuff":
+  {
+    "some_string":"embedded_string",
+    "some_int": 20
+  }
+}
\ No newline at end of file
diff --git a/tests/json_parser/parse_config_file/config_bad.json b/tests/json_parser/parse_config_file/config_bad.json
new file mode 100644
index 0000000000000000000000000000000000000000..b960fb0ce8985f07ccadeb5180aade059fd89cca
--- /dev/null
+++ b/tests/json_parser/parse_config_file/config_bad.json
@@ -0,0 +1,11 @@
+{
+  "server":"some_string",
+  "port": 10,
+  "some_array":1,
+  "some_string_array":["s1","s2","s3"],
+  "embedded_stuff":
+  {
+    "some_string":"embedded_string",
+    "some_int": 20
+  }
+}
\ No newline at end of file
diff --git a/tests/json_parser/parse_config_file/parse_config_file.cpp b/tests/json_parser/parse_config_file/parse_config_file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c185240553dc07c5786fcb8565ce38b3b0dc57f7
--- /dev/null
+++ b/tests/json_parser/parse_config_file/parse_config_file.cpp
@@ -0,0 +1,77 @@
+#include "json_parser/json_parser.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "testing.h"
+
+using hidra2::M_AssertEq;
+
+
+using namespace hidra2;
+
+struct Settings {
+    uint64_t port;
+    std::string server;
+    std::vector<uint64_t> intarray;
+    std::vector<std::string> stringarray;
+    std::string embedded_string;
+    uint64_t some_int;
+};
+
+void AssertSettings(const Settings& settings) {
+    M_AssertEq(10, settings.port);
+
+    M_AssertEq(3, settings.intarray.size());
+    M_AssertEq(1, settings.intarray[0]);
+    M_AssertEq(2, settings.intarray[1]);
+    M_AssertEq(3, settings.intarray[2]);
+
+    M_AssertEq(3, settings.stringarray.size());
+    M_AssertEq("s1", settings.stringarray[0]);
+    M_AssertEq("s2", settings.stringarray[1]);
+    M_AssertEq("s3", settings.stringarray[2]);
+
+    M_AssertEq("some_string", settings.server);
+    M_AssertEq("embedded_string", settings.embedded_string);
+    M_AssertEq(20, settings.some_int);
+}
+
+Settings Parse(const std::string& fname, Error* err) {
+    hidra2::JsonParser parser(fname, true);
+
+    Settings settings;
+
+    (*err = parser.GetUInt64("port", &settings.port)) ||
+    (*err = parser.GetArrayString("some_string_array", &settings.stringarray)) ||
+    (*err = parser.GetArrayUInt64("some_array", &settings.intarray)) ||
+    (*err = parser.Embedded("embedded_stuff").GetString("some_string", &settings.embedded_string)) ||
+    (*err = parser.Embedded("embedded_stuff").GetUInt64("some_int", &settings.some_int)) ||
+    (*err = parser.GetString("server", &settings.server)
+    );
+
+    return settings;
+}
+
+int main(int argc, char* argv[]) {
+    if (argc != 3) {
+        std::cout << "Wrong number of arguments" << std::endl;
+        exit(EXIT_FAILURE);
+    }
+
+    auto fname = std::string{argv[1]};
+    auto res = std::string{argv[2]};
+
+    Error err;
+    auto settings = Parse(fname, &err);
+
+    if (err) {
+        return ! (res == "FAIL");
+    } else {
+        AssertSettings(settings);
+        return ! (res == "OK");
+    }
+}
+
+