diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace
index 92c80ee08a2ec568fb333f86fefff47fd47c597a..24dbe8a68728954d801fc4a7d3dab7e87b4e8678 100644
--- a/ma-impl.sublime-workspace
+++ b/ma-impl.sublime-workspace
@@ -271,6 +271,49 @@
 	},
 	"buffers":
 	[
+		{
+			"file": "vipra-ui/app/routes/articles.js",
+			"settings":
+			{
+				"buffer_size": 213,
+				"line_ending": "Unix"
+			}
+		},
+		{
+			"file": "vipra-ui/app/templates/articles.hbs",
+			"settings":
+			{
+				"buffer_size": 103,
+				"line_ending": "Unix"
+			}
+		},
+		{
+			"file": "vipra-ui/app/models/article.js",
+			"settings":
+			{
+				"buffer_size": 159,
+				"line_ending": "Unix"
+			}
+		},
+		{
+			"file": "vipra-ui/app/adapters/application.js",
+			"settings":
+			{
+				"buffer_size": 137,
+				"line_ending": "Unix"
+			}
+		},
+		{
+			"contents": "import DS from 'ember-data';\n\nexport default DS.RESTSerializer.extend({\n  \n});\n",
+			"file": "vipra-ui/app/serializers/application.js",
+			"file_size": 76,
+			"file_write_time": 130945949499834628,
+			"settings":
+			{
+				"buffer_size": 79,
+				"line_ending": "Unix"
+			}
+		}
 	],
 	"build_system": "",
 	"build_system_choices":
@@ -450,11 +493,23 @@
 	"expanded_folders":
 	[
 		"/home/eike/Repositories/fu/ss15/ma/impl",
-		"/home/eike/Repositories/fu/ss15/ma/impl/vm",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/adapters",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/models",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/serializers",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vm/config"
 	],
 	"file_history":
 	[
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/app.js",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/application.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/index.hbs",
+		"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/router.js",
 		"/home/eike/Repositories/fu/ss15/ma/impl/vm/bootstrap.sh",
 		"/home/eike/Repositories/fu/ss15/ma/doc/thesis/thesis.tex",
 		"/home/eike/Repositories/fu/ss15/ma/impl/Vagrantfile",
@@ -845,8 +900,484 @@
 	"groups":
 	[
 		{
+			"selected": 0,
 			"sheets":
 			[
+				{
+					"buffer": 0,
+					"file": "vipra-ui/app/routes/articles.js",
+					"semi_transient": false,
+					"settings":
+					{
+						"buffer_size": 213,
+						"regions":
+						{
+						},
+						"selection":
+						[
+							[
+								213,
+								213
+							]
+						],
+						"settings":
+						{
+							"BracketHighlighterBusy": false,
+							"bh_regions":
+							[
+								"bh_curly",
+								"bh_curly_center",
+								"bh_curly_open",
+								"bh_curly_close",
+								"bh_curly_content",
+								"bh_c_define",
+								"bh_c_define_center",
+								"bh_c_define_open",
+								"bh_c_define_close",
+								"bh_c_define_content",
+								"bh_double_quote",
+								"bh_double_quote_center",
+								"bh_double_quote_open",
+								"bh_double_quote_close",
+								"bh_double_quote_content",
+								"bh_tag",
+								"bh_tag_center",
+								"bh_tag_open",
+								"bh_tag_close",
+								"bh_tag_content",
+								"bh_default",
+								"bh_default_center",
+								"bh_default_open",
+								"bh_default_close",
+								"bh_default_content",
+								"bh_angle",
+								"bh_angle_center",
+								"bh_angle_open",
+								"bh_angle_close",
+								"bh_angle_content",
+								"bh_unmatched",
+								"bh_unmatched_center",
+								"bh_unmatched_open",
+								"bh_unmatched_close",
+								"bh_unmatched_content",
+								"bh_single_quote",
+								"bh_single_quote_center",
+								"bh_single_quote_open",
+								"bh_single_quote_close",
+								"bh_single_quote_content",
+								"bh_round",
+								"bh_round_center",
+								"bh_round_open",
+								"bh_round_close",
+								"bh_round_content",
+								"bh_regex",
+								"bh_regex_center",
+								"bh_regex_open",
+								"bh_regex_close",
+								"bh_regex_content",
+								"bh_square",
+								"bh_square_center",
+								"bh_square_open",
+								"bh_square_close",
+								"bh_square_content"
+							],
+							"editorconfig": true,
+							"ensure_newline_at_eof_on_save": true,
+							"incomplete_sync": null,
+							"remote_loading": false,
+							"synced": false,
+							"syntax": "Packages/JavaScript/JavaScript.sublime-syntax",
+							"tab_size": 2,
+							"translate_tabs_to_spaces": true,
+							"trim_trailing_white_space_on_save": true
+						},
+						"translation.x": 0.0,
+						"translation.y": 0.0,
+						"zoom_level": 1.0
+					},
+					"stack_index": 0,
+					"type": "text"
+				},
+				{
+					"buffer": 1,
+					"file": "vipra-ui/app/templates/articles.hbs",
+					"semi_transient": false,
+					"settings":
+					{
+						"buffer_size": 103,
+						"regions":
+						{
+						},
+						"selection":
+						[
+							[
+								80,
+								80
+							]
+						],
+						"settings":
+						{
+							"BracketHighlighterBusy": false,
+							"bh_regions":
+							[
+								"bh_curly",
+								"bh_curly_center",
+								"bh_curly_open",
+								"bh_curly_close",
+								"bh_curly_content",
+								"bh_c_define",
+								"bh_c_define_center",
+								"bh_c_define_open",
+								"bh_c_define_close",
+								"bh_c_define_content",
+								"bh_double_quote",
+								"bh_double_quote_center",
+								"bh_double_quote_open",
+								"bh_double_quote_close",
+								"bh_double_quote_content",
+								"bh_tag",
+								"bh_tag_center",
+								"bh_tag_open",
+								"bh_tag_close",
+								"bh_tag_content",
+								"bh_default",
+								"bh_default_center",
+								"bh_default_open",
+								"bh_default_close",
+								"bh_default_content",
+								"bh_angle",
+								"bh_angle_center",
+								"bh_angle_open",
+								"bh_angle_close",
+								"bh_angle_content",
+								"bh_unmatched",
+								"bh_unmatched_center",
+								"bh_unmatched_open",
+								"bh_unmatched_close",
+								"bh_unmatched_content",
+								"bh_single_quote",
+								"bh_single_quote_center",
+								"bh_single_quote_open",
+								"bh_single_quote_close",
+								"bh_single_quote_content",
+								"bh_round",
+								"bh_round_center",
+								"bh_round_open",
+								"bh_round_close",
+								"bh_round_content",
+								"bh_regex",
+								"bh_regex_center",
+								"bh_regex_open",
+								"bh_regex_close",
+								"bh_regex_content",
+								"bh_square",
+								"bh_square_center",
+								"bh_square_open",
+								"bh_square_close",
+								"bh_square_content"
+							],
+							"editorconfig": true,
+							"ensure_newline_at_eof_on_save": false,
+							"incomplete_sync": null,
+							"remote_loading": false,
+							"synced": false,
+							"syntax": "Packages/Handlebars/grammars/Handlebars.tmLanguage",
+							"tab_size": 2,
+							"translate_tabs_to_spaces": true,
+							"trim_trailing_white_space_on_save": true
+						},
+						"translation.x": 0.0,
+						"translation.y": 0.0,
+						"zoom_level": 1.0
+					},
+					"stack_index": 1,
+					"type": "text"
+				},
+				{
+					"buffer": 2,
+					"file": "vipra-ui/app/models/article.js",
+					"semi_transient": false,
+					"settings":
+					{
+						"buffer_size": 159,
+						"regions":
+						{
+						},
+						"selection":
+						[
+							[
+								62,
+								62
+							]
+						],
+						"settings":
+						{
+							"BracketHighlighterBusy": false,
+							"bh_regions":
+							[
+								"bh_curly",
+								"bh_curly_center",
+								"bh_curly_open",
+								"bh_curly_close",
+								"bh_curly_content",
+								"bh_c_define",
+								"bh_c_define_center",
+								"bh_c_define_open",
+								"bh_c_define_close",
+								"bh_c_define_content",
+								"bh_double_quote",
+								"bh_double_quote_center",
+								"bh_double_quote_open",
+								"bh_double_quote_close",
+								"bh_double_quote_content",
+								"bh_tag",
+								"bh_tag_center",
+								"bh_tag_open",
+								"bh_tag_close",
+								"bh_tag_content",
+								"bh_default",
+								"bh_default_center",
+								"bh_default_open",
+								"bh_default_close",
+								"bh_default_content",
+								"bh_angle",
+								"bh_angle_center",
+								"bh_angle_open",
+								"bh_angle_close",
+								"bh_angle_content",
+								"bh_unmatched",
+								"bh_unmatched_center",
+								"bh_unmatched_open",
+								"bh_unmatched_close",
+								"bh_unmatched_content",
+								"bh_single_quote",
+								"bh_single_quote_center",
+								"bh_single_quote_open",
+								"bh_single_quote_close",
+								"bh_single_quote_content",
+								"bh_round",
+								"bh_round_center",
+								"bh_round_open",
+								"bh_round_close",
+								"bh_round_content",
+								"bh_regex",
+								"bh_regex_center",
+								"bh_regex_open",
+								"bh_regex_close",
+								"bh_regex_content",
+								"bh_square",
+								"bh_square_center",
+								"bh_square_open",
+								"bh_square_close",
+								"bh_square_content"
+							],
+							"editorconfig": true,
+							"ensure_newline_at_eof_on_save": true,
+							"incomplete_sync": null,
+							"remote_loading": false,
+							"synced": false,
+							"syntax": "Packages/JavaScript/JavaScript.sublime-syntax",
+							"tab_size": 2,
+							"translate_tabs_to_spaces": true,
+							"trim_trailing_white_space_on_save": true
+						},
+						"translation.x": 0.0,
+						"translation.y": 0.0,
+						"zoom_level": 1.0
+					},
+					"stack_index": 2,
+					"type": "text"
+				},
+				{
+					"buffer": 3,
+					"file": "vipra-ui/app/adapters/application.js",
+					"semi_transient": false,
+					"settings":
+					{
+						"buffer_size": 137,
+						"regions":
+						{
+						},
+						"selection":
+						[
+							[
+								132,
+								132
+							]
+						],
+						"settings":
+						{
+							"BracketHighlighterBusy": false,
+							"bh_regions":
+							[
+								"bh_curly",
+								"bh_curly_center",
+								"bh_curly_open",
+								"bh_curly_close",
+								"bh_curly_content",
+								"bh_c_define",
+								"bh_c_define_center",
+								"bh_c_define_open",
+								"bh_c_define_close",
+								"bh_c_define_content",
+								"bh_double_quote",
+								"bh_double_quote_center",
+								"bh_double_quote_open",
+								"bh_double_quote_close",
+								"bh_double_quote_content",
+								"bh_tag",
+								"bh_tag_center",
+								"bh_tag_open",
+								"bh_tag_close",
+								"bh_tag_content",
+								"bh_default",
+								"bh_default_center",
+								"bh_default_open",
+								"bh_default_close",
+								"bh_default_content",
+								"bh_angle",
+								"bh_angle_center",
+								"bh_angle_open",
+								"bh_angle_close",
+								"bh_angle_content",
+								"bh_unmatched",
+								"bh_unmatched_center",
+								"bh_unmatched_open",
+								"bh_unmatched_close",
+								"bh_unmatched_content",
+								"bh_single_quote",
+								"bh_single_quote_center",
+								"bh_single_quote_open",
+								"bh_single_quote_close",
+								"bh_single_quote_content",
+								"bh_round",
+								"bh_round_center",
+								"bh_round_open",
+								"bh_round_close",
+								"bh_round_content",
+								"bh_regex",
+								"bh_regex_center",
+								"bh_regex_open",
+								"bh_regex_close",
+								"bh_regex_content",
+								"bh_square",
+								"bh_square_center",
+								"bh_square_open",
+								"bh_square_close",
+								"bh_square_content"
+							],
+							"editorconfig": true,
+							"ensure_newline_at_eof_on_save": true,
+							"incomplete_sync": null,
+							"remote_loading": false,
+							"synced": false,
+							"syntax": "Packages/JavaScript/JavaScript.sublime-syntax",
+							"tab_size": 2,
+							"translate_tabs_to_spaces": true,
+							"trim_trailing_white_space_on_save": true
+						},
+						"translation.x": 0.0,
+						"translation.y": 0.0,
+						"zoom_level": 1.0
+					},
+					"stack_index": 4,
+					"type": "text"
+				},
+				{
+					"buffer": 4,
+					"file": "vipra-ui/app/serializers/application.js",
+					"semi_transient": false,
+					"settings":
+					{
+						"buffer_size": 79,
+						"regions":
+						{
+						},
+						"selection":
+						[
+							[
+								74,
+								74
+							]
+						],
+						"settings":
+						{
+							"BracketHighlighterBusy": false,
+							"bh_regions":
+							[
+								"bh_curly",
+								"bh_curly_center",
+								"bh_curly_open",
+								"bh_curly_close",
+								"bh_curly_content",
+								"bh_c_define",
+								"bh_c_define_center",
+								"bh_c_define_open",
+								"bh_c_define_close",
+								"bh_c_define_content",
+								"bh_double_quote",
+								"bh_double_quote_center",
+								"bh_double_quote_open",
+								"bh_double_quote_close",
+								"bh_double_quote_content",
+								"bh_tag",
+								"bh_tag_center",
+								"bh_tag_open",
+								"bh_tag_close",
+								"bh_tag_content",
+								"bh_default",
+								"bh_default_center",
+								"bh_default_open",
+								"bh_default_close",
+								"bh_default_content",
+								"bh_angle",
+								"bh_angle_center",
+								"bh_angle_open",
+								"bh_angle_close",
+								"bh_angle_content",
+								"bh_unmatched",
+								"bh_unmatched_center",
+								"bh_unmatched_open",
+								"bh_unmatched_close",
+								"bh_unmatched_content",
+								"bh_single_quote",
+								"bh_single_quote_center",
+								"bh_single_quote_open",
+								"bh_single_quote_close",
+								"bh_single_quote_content",
+								"bh_round",
+								"bh_round_center",
+								"bh_round_open",
+								"bh_round_close",
+								"bh_round_content",
+								"bh_regex",
+								"bh_regex_center",
+								"bh_regex_open",
+								"bh_regex_close",
+								"bh_regex_content",
+								"bh_square",
+								"bh_square_center",
+								"bh_square_open",
+								"bh_square_close",
+								"bh_square_content"
+							],
+							"editorconfig": true,
+							"ensure_newline_at_eof_on_save": true,
+							"incomplete_sync": null,
+							"remote_loading": false,
+							"synced": false,
+							"syntax": "Packages/JavaScript/JavaScript.sublime-syntax",
+							"tab_size": 2,
+							"translate_tabs_to_spaces": true,
+							"trim_trailing_white_space_on_save": true
+						},
+						"translation.x": 0.0,
+						"translation.y": 0.0,
+						"zoom_level": 1.0
+					},
+					"stack_index": 3,
+					"type": "text"
+				}
 			]
 		}
 	],
@@ -1013,7 +1544,7 @@
 	"show_open_files": true,
 	"show_tabs": true,
 	"side_bar_visible": true,
-	"side_bar_width": 253.0,
+	"side_bar_width": 247.0,
 	"status_bar_visible": true,
 	"template_settings":
 	{
diff --git a/vipra-cmd/cmd/.classpath b/vipra-cmd/cmd/.classpath
index 449f64d01669599457f00e42abb9240824dd40ba..91251671bf896bb25780ea2ddbe38b6248295e34 100644
--- a/vipra-cmd/cmd/.classpath
+++ b/vipra-cmd/cmd/.classpath
@@ -4,14 +4,15 @@
 	<classpathentry kind="src" path="src/main/resources"/>
 	<classpathentry kind="src" path="src/test/java"/>
 	<classpathentry kind="src" path="src/test/resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
 		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="owner.project.facets" value="java"/>
 		</attributes>
 	</classpathentry>
 	<classpathentry kind="output" path="target/classes"/>
diff --git a/vipra-cmd/cmd/.project b/vipra-cmd/cmd/.project
index b570f39e2c8e5435d1e93e9563363317c08d3d52..f6babc09643e3cc5e65f288e4a18ccfdfade64ed 100644
--- a/vipra-cmd/cmd/.project
+++ b/vipra-cmd/cmd/.project
@@ -5,6 +5,11 @@
 	<projects>
 	</projects>
 	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 		<buildCommand>
 			<name>org.eclipse.jdt.core.javabuilder</name>
 			<arguments>
@@ -15,9 +20,24 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
 		<nature>org.eclipse.jdt.core.javanature</nature>
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
 	</natures>
+	<linkedResources>
+		<link>
+			<name>src/main/resources/config.properties</name>
+			<type>1</type>
+			<locationURI>PARENT-2-PROJECT_LOC/vipra-config/config.properties</locationURI>
+		</link>
+	</linkedResources>
 </projectDescription>
diff --git a/vipra-cmd/cmd/.settings/org.eclipse.jdt.core.prefs b/vipra-cmd/cmd/.settings/org.eclipse.jdt.core.prefs
index 714351aec195a9a572640e6844dcafd51565a2a5..13b3428acd87c3f94042e61eed221c15ce682bfa 100644
--- a/vipra-cmd/cmd/.settings/org.eclipse.jdt.core.prefs
+++ b/vipra-cmd/cmd/.settings/org.eclipse.jdt.core.prefs
@@ -1,5 +1,13 @@
 eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
 org.eclipse.jdt.core.compiler.source=1.8
diff --git a/vipra-cmd/cmd/.settings/org.eclipse.wst.common.component b/vipra-cmd/cmd/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000000000000000000000000000000000000..e412462abbe92e089eeb6dac6733233d21e734d0
--- /dev/null
+++ b/vipra-cmd/cmd/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="vipra-cmd">
+        <wb-resource deploy-path="/" source-path="/src/main/java"/>
+        <wb-resource deploy-path="/" source-path="/src/main/resources"/>
+        <wb-resource deploy-path="/" source-path="/src/test/java"/>
+        <wb-resource deploy-path="/" source-path="/src/test/resources"/>
+    </wb-module>
+</project-modules>
diff --git a/vipra-cmd/cmd/.settings/org.eclipse.wst.common.project.facet.core.xml b/vipra-cmd/cmd/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fd0227a68279180b3dd187cfc58335b8a0914833
--- /dev/null
+++ b/vipra-cmd/cmd/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <fixed facet="java"/>
+  <fixed facet="jst.utility"/>
+  <installed facet="jst.utility" version="1.0"/>
+  <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/vipra-cmd/cmd/pom.xml b/vipra-cmd/cmd/pom.xml
index 91e5cbbd8bad479eb8132a455eae553a4db71062..0c6c1fd74bce1761c707fab70bf9862da84047e8 100644
--- a/vipra-cmd/cmd/pom.xml
+++ b/vipra-cmd/cmd/pom.xml
@@ -23,7 +23,18 @@
 			<artifactId>commons-cli</artifactId>
 			<version>1.3.1</version>
 		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.4</version>
+		</dependency>
 
+		<dependency>
+			<groupId>com.googlecode.json-simple</groupId>
+			<artifactId>json-simple</artifactId>
+			<version>1.1.1</version>
+		</dependency>
+		
 		<!-- Logging -->
 		<dependency>
 			<groupId>org.apache.logging.log4j</groupId>
@@ -40,11 +51,12 @@
 			<artifactId>log4j-slf4j-impl</artifactId>
 			<version>${log4jVersion}</version>
 		</dependency>
+
+		<!-- MongoDB Database Adapter -->
 		<dependency>
-			<groupId>org.apache.logging.log4j</groupId>
-			<artifactId>log4j-web</artifactId>
-			<version>${log4jVersion}</version>
-			<scope>runtime</scope>
+			<groupId>org.mongodb</groupId>
+			<artifactId>mongodb-driver</artifactId>
+			<version>3.0.4</version>
 		</dependency>
 
 		<!-- Testing -->
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/CmdOptions.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/CmdOptions.java
index 1cec7022e83b9a92312defff07c7ba36437b20a5..33db5fc837f70e06967a9e5dcf34be5c7bdf5ade 100644
--- a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/CmdOptions.java
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/CmdOptions.java
@@ -1,6 +1,8 @@
 package de.vipra.cmd;
 
 import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
 import org.apache.commons.cli.Options;
 
 public class CmdOptions extends Options {
@@ -11,8 +13,15 @@ public class CmdOptions extends Options {
 	public static final String OPT_IMPORT = "i";
 
 	public CmdOptions() {
-		addOption(OPT_HELP, "help", false, "print this message");
-		addOption(OPT_IMPORT, "import", true, "import articles into the database");
+		addOption(Option.builder(OPT_HELP).longOpt("help").desc("print this message").build());
+
+		OptionGroup opts = new OptionGroup();
+		opts.setRequired(true);
+
+		opts.addOption(Option.builder(OPT_IMPORT).longOpt("import").hasArgs().argName("files/dirs...")
+				.desc("import articles into the database").build());
+
+		addOptionGroup(opts);
 	}
 
 	public void printHelp() {
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Configuration.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Configuration.java
new file mode 100644
index 0000000000000000000000000000000000000000..c30776997c935ebb74d0a18dc0674b6399664249
--- /dev/null
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Configuration.java
@@ -0,0 +1,41 @@
+package de.vipra.cmd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class Configuration extends Properties {
+
+	private static final long serialVersionUID = 1L;
+
+	public static final String DEFAULT_HOST = "localhost";
+	public static final int DEFAULT_PORT = 27017;
+	public static final String DEFAULT_DB = "test";
+
+	public Configuration() {
+		this(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
+	}
+
+	public Configuration(InputStream in) {
+		try {
+			load(in);
+		} catch (IOException e) {}
+	}
+
+	public String getString(String key, String defaultValue) {
+		return getProperty(key, defaultValue);
+	}
+
+	public int getInt(String key, int defaultValue) {
+		try {
+			return Integer.parseInt(getProperty(key, Integer.toString(defaultValue)));
+		} catch (NumberFormatException e) {
+			return defaultValue;
+		}
+	}
+
+	public boolean getBool(String key, boolean defaultValue) {
+		return Boolean.parseBoolean(getProperty(key, Boolean.toString(defaultValue)));
+	}
+
+}
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/ExecutionException.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/ExecutionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..a37b9c3f078430fd143b568e1b42265028ef567a
--- /dev/null
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/ExecutionException.java
@@ -0,0 +1,11 @@
+package de.vipra.cmd;
+
+public class ExecutionException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	public ExecutionException(String msg) {
+		super(msg);
+	}
+
+}
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Main.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Main.java
index b57398208b795e76a5185fbb43664ac09c26f019..34ea6ee604935ad706b0a70ea79aee773f4a4bd7 100644
--- a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Main.java
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/Main.java
@@ -4,15 +4,11 @@ import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.ParseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import de.vipra.cmd.option.ImportOption;
 
 public class Main {
 
-	public static final Logger log = LoggerFactory.getLogger(Main.class);
-
 	public static void main(String[] args) {
 		CommandLineParser parser = new DefaultParser();
 		CmdOptions options = new CmdOptions();
@@ -21,13 +17,15 @@ public class Main {
 			if (cmd.hasOption(CmdOptions.OPT_HELP)) {
 				options.printHelp();
 			} else if (cmd.hasOption(CmdOptions.OPT_IMPORT)) {
-				ImportOption opt = new ImportOption(cmd);
+				String[] paths = cmd.getOptionValues(CmdOptions.OPT_IMPORT);
+				ImportOption opt = new ImportOption(paths);
 				opt.doImport();
+			} else {
+				options.printHelp();
 			}
 		} catch (ParseException e) {
-			log.error("error parsing cmd line: " + e.getMessage());
 			options.printHelp();
-		}
+		} catch (ExecutionException e) {}
 	}
 
 }
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/MongoDB.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/MongoDB.java
new file mode 100644
index 0000000000000000000000000000000000000000..9025c1bdad81f7486996bd5275dd1ad908b2c7a6
--- /dev/null
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/MongoDB.java
@@ -0,0 +1,45 @@
+package de.vipra.cmd;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoDatabase;
+
+public class MongoDB {
+
+	private static MongoDB mongo;
+
+	private final MongoClient client;
+	private final MongoDatabase db;
+
+	private MongoDB(Configuration config) {
+		String host = config.getString("db.host", Configuration.DEFAULT_HOST);
+		Integer port = config.getInt("db.port", Configuration.DEFAULT_PORT);
+		String databaseName = config.getString("db.name", Configuration.DEFAULT_DB);
+
+		client = new MongoClient(host, port);
+		db = client.getDatabase(databaseName);
+	}
+
+	public MongoClient getClient() {
+		return client;
+	}
+
+	public MongoDatabase getDatabase() {
+		return db;
+	}
+
+	public static MongoDB getInstance() {
+		if (mongo == null) {
+			Configuration config = new Configuration();
+			mongo = new MongoDB(config);
+		}
+		return mongo;
+	}
+
+	public static MongoDB getInstance(Configuration config) {
+		if (mongo == null) {
+			mongo = new MongoDB(config);
+		}
+		return mongo;
+	}
+
+}
diff --git a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/option/ImportOption.java b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
index 9aae0effee0d7abf7ba13f04bdac08675d13c4bf..25b02a08acb073f9cb1d6b81eabcbc5213a6c5b3 100644
--- a/vipra-cmd/cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
+++ b/vipra-cmd/cmd/src/main/java/de/vipra/cmd/option/ImportOption.java
@@ -1,15 +1,84 @@
 package de.vipra.cmd.option;
 
-import org.apache.commons.cli.CommandLine;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import de.vipra.cmd.ExecutionException;
+import de.vipra.cmd.MongoDB;
 
 public class ImportOption {
 
-	public ImportOption(CommandLine cmd) {
-		
+	private ArrayList<File> files = new ArrayList<>();
+	private JSONParser parser = new JSONParser();
+	private MongoDB mongo = MongoDB.getInstance();
+
+	public ImportOption(String[] paths) throws ExecutionException {
+		addPaths(paths);
+	}
+
+	private void addPaths(String[] paths) throws ExecutionException {
+		for (int i = 0; i < paths.length; i++) {
+			addPath(new File(paths[i]));
+		}
+	}
+
+	private void addPaths(File[] paths) throws ExecutionException {
+		for (int i = 0; i < paths.length; i++) {
+			addPath(paths[i]);
+		}
+	}
+
+	private void addPath(File file) throws ExecutionException {
+		if (!file.exists()) {
+			throw new ExecutionException("file/dir does not exist");
+		}
+
+		if (file.isFile()) {
+			files.add(file);
+		} else if (file.isDirectory()) {
+			File[] files = file.listFiles(new FilenameFilter() {
+
+				@Override
+				public boolean accept(File dir, String name) {
+					return dir.isFile();
+				}
+
+			});
+
+			addPaths(files);
+		}
+	}
+
+	private void importFile(File file) throws IOException, ParseException {
+		Object data = parser.parse(new FileReader(file));
+		try {
+			JSONArray array = (JSONArray) data;
+			for (Object object : array) {
+				importArticle((JSONObject) object);
+			}
+		} catch (Exception e) {
+			importArticle((JSONObject) data);
+		}
 	}
-	
+
+	private void importArticle(JSONObject obj) {
+
+	}
+
 	public void doImport() {
-		
+		for (File file : files) {
+			try {
+				importFile(file);
+			} catch (Exception e) {}
+		}
 	}
-	
+
 }
diff --git a/vipra-cmd/cmd/src/main/resources/log4j2.xml b/vipra-cmd/cmd/src/main/resources/log4j2.xml
index 8abf1b196fcbb49c3df9551ecb1937bd6491200b..960dbed52c70828a3ffc4a1904819c4d0e4cec3b 100644
--- a/vipra-cmd/cmd/src/main/resources/log4j2.xml
+++ b/vipra-cmd/cmd/src/main/resources/log4j2.xml
@@ -2,11 +2,11 @@
 <Configuration>
 	<Appenders>
 		<Console name="Console" target="SYSTEM_OUT">
-			<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" />
+			<PatternLayout pattern="%level - %msg%n" />
 		</Console>
 	</Appenders>
 	<Loggers>
-		<Root level="all">
+		<Root level="error">
 			<AppenderRef ref="Console" />
 		</Root>
 	</Loggers>
diff --git a/vipra-cmd/cmd/src/main/resources/log4j2dev.xml b/vipra-cmd/cmd/src/main/resources/log4j2dev.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8abf1b196fcbb49c3df9551ecb1937bd6491200b
--- /dev/null
+++ b/vipra-cmd/cmd/src/main/resources/log4j2dev.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+	<Appenders>
+		<Console name="Console" target="SYSTEM_OUT">
+			<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" />
+		</Console>
+	</Appenders>
+	<Loggers>
+		<Root level="all">
+			<AppenderRef ref="Console" />
+		</Root>
+	</Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/vipra-config/config.properties b/vipra-config/config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..07030840d45dd8fed8c2c2d5bff5fe0a54939a4f
--- /dev/null
+++ b/vipra-config/config.properties
@@ -0,0 +1,3 @@
+db.host=localhost
+db.port=27017
+db.name=test
\ No newline at end of file
diff --git a/vipra-rest/.project b/vipra-rest/.project
index 079d790dd5dd058d558fbd31b199f0b017ce4e76..e9151f1e0a91e271e7af97b5faf74f81d3f160bf 100644
--- a/vipra-rest/.project
+++ b/vipra-rest/.project
@@ -3,6 +3,7 @@
 	<name>vipra-rest</name>
 	<comment></comment>
 	<projects>
+		<project>vipra-cmd</project>
 	</projects>
 	<buildSpec>
 		<buildCommand>
@@ -39,4 +40,11 @@
 		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
 		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
 	</natures>
+	<linkedResources>
+		<link>
+			<name>src/main/resources/config.properties</name>
+			<type>1</type>
+			<locationURI>PARENT-1-PROJECT_LOC/vipra-config/config.properties</locationURI>
+		</link>
+	</linkedResources>
 </projectDescription>
diff --git a/vipra-rest/.settings/org.eclipse.jdt.core.prefs b/vipra-rest/.settings/org.eclipse.jdt.core.prefs
index 6e80039d3b822e65e46fbf18906ef652814e9505..c07c252bc5d05edd0375e06b1d52f0a921ae65a0 100644
--- a/vipra-rest/.settings/org.eclipse.jdt.core.prefs
+++ b/vipra-rest/.settings/org.eclipse.jdt.core.prefs
@@ -1,8 +1,298 @@
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
 org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/vipra-rest/.settings/org.eclipse.jdt.ui.prefs b/vipra-rest/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..a7f8de8ef5b0d043d6e4ba0446e4ea440514af27
--- /dev/null
+++ b/vipra-rest/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+formatter_profile=_Vipra
+formatter_settings_version=12
diff --git a/vipra-rest/.settings/org.eclipse.wst.common.component b/vipra-rest/.settings/org.eclipse.wst.common.component
index 07bb526364819fa2125c5a4a6f2b1a060f873764..bfc7ecd2c55b87f9f307cc7ca345597974f27cb9 100644
--- a/vipra-rest/.settings/org.eclipse.wst.common.component
+++ b/vipra-rest/.settings/org.eclipse.wst.common.component
@@ -5,6 +5,6 @@
         <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
         <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
         <property name="java-output-path" value="/vipra-rest/target/classes"/>
-        <property name="context-root" value="rest"/>
+        <property name="context-root" value="vipra-rest"/>
     </wb-module>
 </project-modules>
diff --git a/vipra-rest/.settings/org.eclipse.wst.ws.service.policy.prefs b/vipra-rest/.settings/org.eclipse.wst.ws.service.policy.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..9cfcabe16f73da1c14f4a8fa1ee90cd74497f281
--- /dev/null
+++ b/vipra-rest/.settings/org.eclipse.wst.ws.service.policy.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.wst.ws.service.policy.projectEnabled=false
diff --git a/vipra-rest/pom.xml b/vipra-rest/pom.xml
index 2d7195d19997c01f4e948292baf363f8e31b6e41..804ffc3676547e48a94e764de5269de75487a2eb 100644
--- a/vipra-rest/pom.xml
+++ b/vipra-rest/pom.xml
@@ -29,7 +29,8 @@
 		</dependency>
 		<dependency>
 			<groupId>org.glassfish.jersey.media</groupId>
-			<artifactId>jersey-media-moxy</artifactId>
+			<!--<artifactId>jersey-media-moxy</artifactId>-->
+			<artifactId>jersey-media-json-jackson</artifactId>
 			<version>${jerseyVersion}</version>
 		</dependency>
 		<dependency>
@@ -49,7 +50,7 @@
 			<artifactId>javax.servlet-api</artifactId>
 			<version>${servletVersion}</version>
 		</dependency>
-
+		
 		<!-- Logging -->
 		<dependency>
 			<groupId>org.apache.logging.log4j</groupId>
@@ -87,14 +88,4 @@
 			<version>4.12</version>
 		</dependency>
 	</dependencies>
-
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.eclipse.jetty</groupId>
-				<artifactId>jetty-maven-plugin</artifactId>
-				<version>${jettyVersion}</version>
-			</plugin>
-		</plugins>
-	</build>
 </project>
diff --git a/vipra-rest/src/main/java/de/vipra/rest/APIMediaType.java b/vipra-rest/src/main/java/de/vipra/rest/APIMediaType.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9e4cdb9f094ccc41fd9ea9dd7bc8006a2cb5d4a
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/APIMediaType.java
@@ -0,0 +1,9 @@
+package de.vipra.rest;
+
+import javax.ws.rs.core.MediaType;
+
+public class APIMediaType extends MediaType {
+
+	public static final String APPLICATION_JSONAPI = "application/vnd.api+json";
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/Application.java b/vipra-rest/src/main/java/de/vipra/rest/Application.java
index 22d390d4e5a544fbf68f440a1bdda710f90927d4..7e667e104990fdac4a6ace7172911f04ac82ce1f 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/Application.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/Application.java
@@ -1,16 +1,16 @@
 package de.vipra.rest;
 
+import org.glassfish.jersey.jackson.JacksonFeature;
 import org.glassfish.jersey.server.ResourceConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-public class Application extends ResourceConfig {
+import de.vipra.rest.provider.ObjectMapperProvider;
 
-	public static final Logger log = LoggerFactory.getLogger(Application.class);
+public class Application extends ResourceConfig {
 
 	public Application() {
-		packages("de.cochu.backend.rest");
-		log.info("Application started");
+		packages("de.vipra.rest.resource");
+		register(ObjectMapperProvider.class);
+		register(JacksonFeature.class);
 	}
 
 }
diff --git a/vipra-rest/src/main/java/de/vipra/rest/Configuration.java b/vipra-rest/src/main/java/de/vipra/rest/Configuration.java
new file mode 100644
index 0000000000000000000000000000000000000000..30b9795d6f94592766796724333814ee5d5c6eca
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/Configuration.java
@@ -0,0 +1,50 @@
+package de.vipra.rest;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Configuration extends Properties {
+
+	public static final Logger log = LoggerFactory.getLogger(Configuration.class);
+
+	private static final long serialVersionUID = 1L;
+
+	public static final String DEFAULT_HOST = "localhost";
+	public static final int DEFAULT_PORT = 27017;
+	public static final String DEFAULT_DB = "test";
+
+	public Configuration() {
+		this(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
+	}
+
+	public Configuration(InputStream in) {
+		if (in == null) {
+			log.error("configuration file stream not found");
+		} else {
+			try {
+				load(in);
+			} catch (IOException e) {}
+		}
+	}
+
+	public String getString(String key, String defaultValue) {
+		return getProperty(key, defaultValue);
+	}
+
+	public int getInt(String key, int defaultValue) {
+		try {
+			return Integer.parseInt(getProperty(key, Integer.toString(defaultValue)));
+		} catch (NumberFormatException e) {
+			return defaultValue;
+		}
+	}
+
+	public boolean getBool(String key, boolean defaultValue) {
+		return Boolean.parseBoolean(getProperty(key, Boolean.toString(defaultValue)));
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java b/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java
new file mode 100644
index 0000000000000000000000000000000000000000..e219cf3934944a5f00d75bf3e2f923ec992159ad
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/MongoDB.java
@@ -0,0 +1,45 @@
+package de.vipra.rest;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoDatabase;
+
+public class MongoDB {
+
+	private static MongoDB mongo;
+
+	private final MongoClient client;
+	private final MongoDatabase db;
+
+	private MongoDB(Configuration config) {
+		String host = config.getString("db.host", Configuration.DEFAULT_HOST);
+		Integer port = config.getInt("db.port", Configuration.DEFAULT_PORT);
+		String databaseName = config.getString("db.name", Configuration.DEFAULT_DB);
+
+		client = new MongoClient(host, port);
+		db = client.getDatabase(databaseName);
+	}
+
+	public MongoClient getClient() {
+		return client;
+	}
+
+	public MongoDatabase getDatabase() {
+		return db;
+	}
+
+	public static MongoDB getInstance() {
+		if (mongo == null) {
+			Configuration config = new Configuration();
+			mongo = new MongoDB(config);
+		}
+		return mongo;
+	}
+
+	public static MongoDB getInstance(Configuration config) {
+		if (mongo == null) {
+			mongo = new MongoDB(config);
+		}
+		return mongo;
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/MongoDBContextListener.java b/vipra-rest/src/main/java/de/vipra/rest/MongoDBContextListener.java
deleted file mode 100644
index ef62a6ea958b03ff544ce3f14f7c9a9e6106fa20..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/MongoDBContextListener.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package de.vipra.rest;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.mongodb.MongoClient;
-import com.mongodb.client.MongoDatabase;
-
-@WebListener
-public class MongoDBContextListener implements ServletContextListener {
-
-	public static final Logger log = LoggerFactory.getLogger(MongoDBContextListener.class);
-
-	@Override
-	public void contextDestroyed(ServletContextEvent sce) {
-		MongoClient mongo = (MongoClient) sce.getServletContext().getAttribute("MONGODB_CLIENT");
-		mongo.close();
-
-		log.debug("mongodb connection closed successfully");
-	}
-
-	@Override
-	public void contextInitialized(ServletContextEvent sce) {
-		ServletContext ctx = sce.getServletContext();
-
-		String host = ctx.getInitParameter("MONGODB_HOST");
-		Integer port = Integer.parseInt(ctx.getInitParameter("MONGODB_PORT"));
-		String databaseName = ctx.getInitParameter("MONGODB_DATABASE");
-
-		MongoClient mongo = new MongoClient(host, port);
-		MongoDatabase db = mongo.getDatabase(databaseName);
-
-		ctx.setAttribute("MONGODB_CLIENT", mongo);
-		ctx.setAttribute("MONGODB_DATABASE", db);
-
-		log.debug("mongodb connection created successfully");
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/dao/Article.java b/vipra-rest/src/main/java/de/vipra/rest/dao/Article.java
deleted file mode 100644
index cfd7cdb315edf07acbd249f57616174281aa09b9..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/dao/Article.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package de.vipra.rest.dao;
-
-import java.util.ArrayList;
-import java.util.Date;
-
-import javax.xml.bind.annotation.XmlRootElement;
-
-import org.bson.Document;
-import org.bson.types.ObjectId;
-
-@XmlRootElement
-public class Article extends Dao {
-
-	private String title;
-	private String text;
-	private String url;
-	private Date date;
-
-	public Article() {
-		super();
-	}
-
-	public Article(Document document) {
-		super(document);
-	}
-
-	public String getTitle() {
-		return title;
-	}
-
-	public void setTitle(String title) {
-		this.title = title;
-	}
-
-	public String getText() {
-		return text;
-	}
-
-	public void setText(String text) {
-		this.text = text;
-	}
-
-	public String getUrl() {
-		return url;
-	}
-
-	public void setUrl(String url) {
-		this.url = url;
-	}
-
-	public Date getDate() {
-		return date;
-	}
-
-	public void setDate(Date date) {
-		this.date = date;
-	}
-
-	@Override
-	public Document toDocument() {
-		Document doc = new Document("title", title).append("text", text).append("url", url).append("date", date);
-		if (id != null) {
-			doc.append("_id", new ObjectId(id));
-		}
-		return doc;
-	}
-
-	@Override
-	public void fromDocument(Document document) {
-		id = document.getObjectId("_id").toString();
-		title = document.getString("title");
-		text = document.getString("text");
-		url = document.getString("url");
-		date = document.getDate("date");
-	}
-
-	public static ArrayList<Article> fromDocuments(final ArrayList<Document> docs) {
-		ArrayList<Article> articles = new ArrayList<Article>(docs.size());
-		for (Document doc : docs) {
-			articles.add(new Article(doc));
-		}
-		return articles;
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/dao/Dao.java b/vipra-rest/src/main/java/de/vipra/rest/dao/Dao.java
deleted file mode 100644
index 5bc9b739e5f34b1e5c6ce610312fc9dd8e7c8549..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/dao/Dao.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package de.vipra.rest.dao;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import javax.xml.bind.annotation.XmlRootElement;
-
-import org.bson.Document;
-
-@XmlRootElement
-public abstract class Dao {
-
-	protected String id;
-
-	public Dao() {
-	}
-
-	public Dao(Document document) {
-		fromDocument(document);
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public URI getURI(URI base) throws URISyntaxException, MalformedURLException {
-		return new URI(base.toString() + "/" + id);
-	}
-
-	public abstract Document toDocument();
-
-	public abstract void fromDocument(Document document);
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/APIError.java b/vipra-rest/src/main/java/de/vipra/rest/model/APIError.java
new file mode 100644
index 0000000000000000000000000000000000000000..241a0a322e01ea3b4728b26b029064ec926477d2
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/APIError.java
@@ -0,0 +1,64 @@
+package de.vipra.rest.model;
+
+import java.util.UUID;
+
+import javax.ws.rs.core.Response.Status;
+
+public class APIError {
+
+	private final String id = UUID.randomUUID().toString();
+	private String status;
+	private String code;
+	private String title;
+	private String detail;
+
+	public APIError() {}
+
+	public APIError(String status, String code, String title, String detail) {
+		this.status = status;
+		this.code = code;
+		this.title = title;
+		this.detail = detail;
+	}
+
+	public APIError(Status status, String title, String detail) {
+		this(Integer.toString(status.getStatusCode()), status.getReasonPhrase(), title, detail);
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getDetail() {
+		return detail;
+	}
+
+	public void setDetail(String detail) {
+		this.detail = detail;
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/APIVersion.java b/vipra-rest/src/main/java/de/vipra/rest/model/APIVersion.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e2495d8cf03cfd740304353c0fbed586f2fb439
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/APIVersion.java
@@ -0,0 +1,18 @@
+package de.vipra.rest.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class APIVersion {
+
+	private String version = "1.0";
+
+	public String getVersion() {
+		return version;
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Articles.java b/vipra-rest/src/main/java/de/vipra/rest/model/Articles.java
new file mode 100644
index 0000000000000000000000000000000000000000..6142e729a9b760415fa5f840ba0e0b312bd72584
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Articles.java
@@ -0,0 +1,139 @@
+package de.vipra.rest.model;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bson.Document;
+import org.bson.types.ObjectId;
+
+public class Articles implements Model, Links {
+
+	private String type = Articles.class.getSimpleName().toLowerCase();
+	private String id;
+	private String title;
+	private String text;
+	private String url;
+	private Date date;
+	private Map<String, Link> links;
+
+	public Articles() {}
+
+	public Articles(Document document) {
+		fromDocument(document);
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public String getUrl() {
+		return url;
+	}
+
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
+	public Date getDate() {
+		return date;
+	}
+
+	public void setDate(Date date) {
+		this.date = date;
+	}
+
+	@Override
+	public Document toDocument() {
+		Document doc = new Document("title", title).append("text", text).append("url", url).append("date", date);
+		if (id != null) {
+			doc.append("_id", new ObjectId(id));
+		}
+		return doc;
+	}
+
+	@Override
+	public void fromDocument(Document document) {
+		id = document.getObjectId("_id").toString();
+		title = document.getString("title");
+		text = document.getString("text");
+		url = document.getString("url");
+		date = document.getDate("date");
+	}
+
+	public static ArrayList<Articles> fromDocuments(final ArrayList<Document> docs) {
+		ArrayList<Articles> articles = new ArrayList<Articles>();
+		for (Document doc : docs) {
+			articles.add(new Articles(doc));
+		}
+		return articles;
+	}
+
+	@Override
+	public URI getURI(URI base) {
+		return Articles.getURI(base, id);
+	}
+
+	@Override
+	public Map<String, Link> getLinks() {
+		return links;
+	}
+
+	@Override
+	public void setLinks(Map<String, Link> links) {
+		this.links = links;
+	}
+
+	@Override
+	public void addLink(String name, Link link) {
+		if (links == null) {
+			links = new HashMap<>();
+		}
+		links.put(name, link);
+	}
+
+	@Override
+	public void setSelf(URI base) {
+		addLink("self", new Link(getURI(base, id).toString()));
+	}
+
+	public static URI getURI(URI base, String id) {
+		try {
+			return new URI(base.toString() + "/" + id);
+		} catch (URISyntaxException e) {
+			return null;
+		}
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Link.java b/vipra-rest/src/main/java/de/vipra/rest/model/Link.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3233dacdd49bb6980ae727d58ee9e39cfddc4fe
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Link.java
@@ -0,0 +1,30 @@
+package de.vipra.rest.model;
+
+public class Link {
+
+	private String href;
+	private Object meta;
+
+	public Link() {}
+
+	public Link(String href) {
+		setHref(href);
+	}
+
+	public String getHref() {
+		return href;
+	}
+
+	public void setHref(String href) {
+		this.href = href;
+	}
+
+	public Object getMeta() {
+		return meta;
+	}
+
+	public void setMeta(Object meta) {
+		this.meta = meta;
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Links.java b/vipra-rest/src/main/java/de/vipra/rest/model/Links.java
new file mode 100644
index 0000000000000000000000000000000000000000..939277d28519a3ab2cfc06326aa2faea8f8de8fa
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Links.java
@@ -0,0 +1,16 @@
+package de.vipra.rest.model;
+
+import java.net.URI;
+import java.util.Map;
+
+public interface Links {
+
+	Map<String, Link> getLinks();
+
+	void setLinks(Map<String, Link> links);
+
+	void addLink(String name, Link link);
+
+	void setSelf(URI base);
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Meta.java b/vipra-rest/src/main/java/de/vipra/rest/model/Meta.java
new file mode 100644
index 0000000000000000000000000000000000000000..3570a5ea4d0955cf902c7862b911fe7afea5ed10
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Meta.java
@@ -0,0 +1,13 @@
+package de.vipra.rest.model;
+
+import java.util.Map;
+
+public interface Meta {
+
+	Map<String, Object> getMeta();
+
+	void setMeta(Map<String, Object> meta);
+
+	void addMeta(String name, Object meta);
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Model.java b/vipra-rest/src/main/java/de/vipra/rest/model/Model.java
new file mode 100644
index 0000000000000000000000000000000000000000..0de5473c28cb06cfd238823ad1ae45a2129944b5
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Model.java
@@ -0,0 +1,16 @@
+package de.vipra.rest.model;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.bson.Document;
+
+public interface Model {
+
+	Document toDocument();
+
+	void fromDocument(Document document);
+
+	URI getURI(URI base) throws URISyntaxException;
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java b/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..e58bcef4097ba99ed60235e8239af99b4261cba0
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java
@@ -0,0 +1,82 @@
+package de.vipra.rest.model;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ResponseWrapper<T> implements Links {
+
+	private Map<String, Link> links;
+	private T data;
+	private List<APIError> errors;
+	private APIVersion jsonapi = new APIVersion();
+
+	public ResponseWrapper() {}
+
+	public ResponseWrapper(T data) {
+		setData(data);
+	}
+
+	public ResponseWrapper(APIError error) {
+		addError(error);
+	}
+
+	public T getData() {
+		return data;
+	}
+
+	public void setData(T data) {
+		this.data = data;
+		this.errors = null;
+	}
+
+	public List<APIError> getErrors() {
+		return errors;
+	}
+
+	public void setErrors(List<APIError> errors) {
+		this.errors = errors;
+		this.data = null;
+	}
+
+	public APIVersion getJsonapi() {
+		return jsonapi;
+	}
+
+	public void setJsonapi(APIVersion jsonapi) {
+		this.jsonapi = jsonapi;
+	}
+
+	public void addError(APIError error) {
+		if (error == null) {
+			errors = new ArrayList<>();
+		}
+		errors.add(error);
+	}
+
+	@Override
+	public Map<String, Link> getLinks() {
+		return links;
+	}
+
+	@Override
+	public void setLinks(Map<String, Link> links) {
+		this.links = links;
+	}
+
+	@Override
+	public void setSelf(URI base) {
+		addLink("self", new Link(base.toString()));
+	}
+
+	@Override
+	public void addLink(String name, Link link) {
+		if (links == null) {
+			links = new HashMap<>();
+		}
+		links.put(name, link);
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/APIRequestFilter.java b/vipra-rest/src/main/java/de/vipra/rest/provider/APIRequestFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..85bdd37b2bf94d1ef072247dc43f13743913fffe
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/provider/APIRequestFilter.java
@@ -0,0 +1,45 @@
+package de.vipra.rest.provider;
+
+import java.io.IOException;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import de.vipra.rest.APIMediaType;
+
+/**
+ * Request filter based on JSON API v1.0 server responsibilities
+ * 
+ * @see <a href="http://jsonapi.org/format/1.0/">http://jsonapi.org/format/1.0/
+ *      </a>
+ */
+@Provider
+public class APIRequestFilter implements ClientRequestFilter {
+
+	@Override
+	public void filter(ClientRequestContext requestContext) throws IOException {
+		if (requestContext.getHeaderString("Content-Type").contains(";")) {
+			requestContext.abortWith(Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).build());
+		} else {
+			String[] acceptHeader = requestContext.getHeaderString("Accept").split(",");
+			boolean abort = false;
+			for (int i = 0; i < acceptHeader.length; i++) {
+				String accept = acceptHeader[i].trim();
+				if (accept.startsWith(APIMediaType.APPLICATION_JSONAPI)) {
+					if (accept.contains(";")) {
+						abort = true;
+					} else {
+						abort = false;
+						break;
+					}
+				}
+			}
+			if (abort) {
+				requestContext.abortWith(Response.status(Response.Status.NOT_ACCEPTABLE).build());
+			}
+		}
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/CORSFilter.java b/vipra-rest/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java
similarity index 87%
rename from vipra-rest/src/main/java/de/vipra/rest/CORSFilter.java
rename to vipra-rest/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java
index 2f5e5f3a355e9bf7ebd3ab7be5d66fc2fd5176d0..2cd438181c439626d45d3db53e68e2a1d5d18273 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/CORSFilter.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java
@@ -1,4 +1,4 @@
-package de.vipra.rest;
+package de.vipra.rest.provider;
 
 import java.io.IOException;
 
@@ -8,7 +8,7 @@ import javax.ws.rs.container.ContainerResponseFilter;
 import javax.ws.rs.ext.Provider;
 
 @Provider
-public class CORSFilter implements ContainerResponseFilter {
+public class CORSResponseFilter implements ContainerResponseFilter {
 
 	@Override
 	public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..624b6065be81d4e631967d2df95cded40d41c82d
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java
@@ -0,0 +1,42 @@
+package de.vipra.rest.provider;
+
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Provider;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+import de.vipra.rest.model.Articles;
+import de.vipra.rest.model.Link;
+import de.vipra.rest.serializer.ArticlesSerializer;
+import de.vipra.rest.serializer.LinkSerializer;
+
+@Provider
+public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
+
+	final ObjectMapper defaultObjectMapper;
+
+	public ObjectMapperProvider() {
+		defaultObjectMapper = createDefaultMapper();
+	}
+
+	@Override
+	public ObjectMapper getContext(Class<?> type) {
+		return defaultObjectMapper;
+	}
+
+	public static ObjectMapper createDefaultMapper() {
+		SimpleModule module = new SimpleModule();
+		module.addSerializer(Articles.class, new ArticlesSerializer());
+		module.addSerializer(Link.class, new LinkSerializer());
+
+		final ObjectMapper mapper = new ObjectMapper();
+		mapper.enable(SerializationFeature.INDENT_OUTPUT);
+		mapper.setSerializationInclusion(Include.NON_NULL);
+		mapper.registerModule(module);
+		return mapper;
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
deleted file mode 100644
index 4efab4113d4140c61f0bb853583eb6706538eda0..0000000000000000000000000000000000000000
--- a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package de.vipra.rest.resource;
-
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.util.List;
-
-import javax.servlet.ServletContext;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.mongodb.client.MongoDatabase;
-
-import javax.ws.rs.core.GenericEntity;
-
-import de.vipra.rest.Messages;
-import de.vipra.rest.dao.Article;
-import de.vipra.rest.service.ArticleService;
-
-@Path("articles")
-public class ArticleResource {
-
-	public static final Logger log = LoggerFactory.getLogger(ArticleResource.class);
-
-	@Context
-	UriInfo uri;
-
-	final ArticleService service;
-
-	public ArticleResource(@Context ServletContext context) {
-		MongoDatabase db = (MongoDatabase) context.getAttribute("MONGODB_DATABASE");
-		service = new ArticleService(db);
-	}
-
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getArticles(@QueryParam("skip") @DefaultValue("0") int skip,
-			@QueryParam("limit") @DefaultValue("0") int limit,
-			@QueryParam("sortby") @DefaultValue("date") String sortBy,
-			@QueryParam("order") @DefaultValue("desc") String order) {
-		List<Article> articles = service.getArticles(skip, limit, sortBy, order);
-		return Response.ok(new GenericEntity<List<Article>>(articles) {
-		}).build();
-	}
-
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Path("{id}")
-	public Response getArticle(@PathParam("id") String id) {
-		if (id == null || id.trim().length() == 0) {
-			return Response.status(Response.Status.BAD_REQUEST)
-					.entity(String.format(Messages.BAD_REQUEST, "id cannot be empty")).build();
-		}
-		Article article = service.getArticle(id);
-		if (article != null) {
-			return Response.ok(article).build();
-		} else {
-			return Response.status(Response.Status.NOT_FOUND).type(MediaType.TEXT_PLAIN)
-					.entity(String.format(Messages.NOT_FOUND, "article", id)).build();
-		}
-	}
-
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response createArticle(Article article) throws MalformedURLException, URISyntaxException {
-		article = service.createArticle(article);
-		return Response.created(article.getURI(uri.getAbsolutePath())).entity(article).build();
-	}
-
-	@DELETE
-	@Path("{id}")
-	public Response deleteArticle(@PathParam("id") String id) {
-		long deleted = service.deleteArticle(id);
-		switch (Math.toIntExact(deleted)) {
-		case 0:
-			return Response.status(Response.Status.NOT_FOUND).entity(String.format(Messages.NOT_FOUND, "article", id))
-					.build();
-		case 1:
-			return Response.noContent().build();
-		default:
-			log.error(String.format("deleted count while deleting article with id %1 was %2", id, deleted));
-			return Response.serverError().build();
-		}
-	}
-
-	@PUT
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	@Path("{id}")
-	public Response updateArticle(@PathParam("id") String id, Article article) {
-		long updated = service.updateArticle(article);
-		switch (Math.toIntExact(updated)) {
-		case 0:
-			return Response.status(Response.Status.NOT_FOUND).type(MediaType.TEXT_PLAIN)
-					.entity(String.format(Messages.NOT_FOUND, "article", id)).build();
-		case 1:
-			return Response.ok().entity(article).build();
-		default:
-			log.error(String.format("updated count while updating article with id %1 was %2", id, updated));
-			return Response.serverError().build();
-		}
-	}
-
-}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticlesResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticlesResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a25706ef800d0ac1b2ad5d4683252adf4959a19
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticlesResource.java
@@ -0,0 +1,126 @@
+package de.vipra.rest.resource;
+
+import java.util.ArrayList;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import de.vipra.rest.APIMediaType;
+import de.vipra.rest.Configuration;
+import de.vipra.rest.Messages;
+import de.vipra.rest.MongoDB;
+import de.vipra.rest.model.APIError;
+import de.vipra.rest.model.Articles;
+import de.vipra.rest.model.ResponseWrapper;
+import de.vipra.rest.service.ArticlesService;
+
+@Path("articles")
+public class ArticlesResource {
+
+	@Context
+	UriInfo uri;
+
+	final ArticlesService service;
+
+	public ArticlesResource(@Context ServletContext servletContext) {
+		Configuration config = new Configuration(servletContext.getResourceAsStream("config.properties"));
+		MongoDB mongo = MongoDB.getInstance(config);
+		service = new ArticlesService(mongo.getDatabase());
+	}
+
+	@GET
+	@Produces(APIMediaType.APPLICATION_JSONAPI)
+	public Response getArticles(@QueryParam("skip") @DefaultValue("0") int skip,
+			@QueryParam("limit") @DefaultValue("0") int limit,
+			@QueryParam("sort") @DefaultValue("date") String sortBy) {
+		ArrayList<Articles> articles = service.getArticles(uri.getAbsolutePath(), skip, limit, sortBy);
+		ResponseWrapper<ArrayList<Articles>> res = new ResponseWrapper<>(articles);
+		res.setSelf(uri.getAbsolutePath());
+		return Response.ok().entity(res).build();
+	}
+
+	@GET
+	@Produces(APIMediaType.APPLICATION_JSONAPI)
+	@Consumes(APIMediaType.APPLICATION_JSONAPI)
+	@Path("{id}")
+	public Response getArticle(@PathParam("id") String id) {
+		ResponseWrapper<Articles> res = new ResponseWrapper<>();
+		res.setSelf(Articles.getURI(uri.getAbsolutePath(), id));
+		if (id == null || id.trim().length() == 0) {
+			res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty",
+					String.format(Messages.BAD_REQUEST, "id cannot be empty")));
+			return Response.status(Response.Status.BAD_REQUEST).entity(res).build();
+		}
+		Articles article = service.getArticle(uri.getAbsolutePath(), id);
+		if (article != null) {
+			res.setData(article);
+			return Response.ok().entity(res).build();
+		} else {
+			res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found",
+					String.format(Messages.NOT_FOUND, "article", id)));
+			return Response.status(Response.Status.NOT_FOUND).entity(res).build();
+		}
+	}
+
+	@POST
+	@Consumes(APIMediaType.APPLICATION_JSONAPI)
+	@Produces(APIMediaType.APPLICATION_JSONAPI)
+	public Response createArticle(Articles article) {
+		article = service.createArticle(uri.getAbsolutePath(), article);
+		ResponseWrapper<Articles> res = new ResponseWrapper<>(article);
+		res.setSelf(article.getURI(uri.getAbsolutePath()));
+		return Response.created(article.getURI(uri.getAbsolutePath())).entity(res).build();
+	}
+
+	@DELETE
+	@Path("{id}")
+	public Response deleteArticle(@PathParam("id") String id) {
+		long deleted = service.deleteArticle(id);
+		switch (Math.toIntExact(deleted)) {
+		case 0:
+			ResponseWrapper<Articles> res = new ResponseWrapper<>();
+			res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found",
+					String.format(Messages.NOT_FOUND, "article", id)));
+			res.setSelf(Articles.getURI(uri.getAbsolutePath(), id));
+			return Response.status(Response.Status.NOT_FOUND).entity(res).build();
+		case 1:
+			return Response.noContent().build();
+		default:
+			return Response.serverError().build();
+		}
+	}
+
+	@PUT
+	@Consumes(APIMediaType.APPLICATION_JSONAPI)
+	@Produces(APIMediaType.APPLICATION_JSONAPI)
+	@Path("{id}")
+	public Response updateArticle(@PathParam("id") String id, Articles article) {
+		long updated = service.updateArticle(uri.getAbsolutePath(), article);
+		ResponseWrapper<Articles> res = new ResponseWrapper<>();
+		res.setSelf(article.getURI(uri.getAbsolutePath()));
+		switch (Math.toIntExact(updated)) {
+		case 0:
+			res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found",
+					String.format(Messages.NOT_FOUND, "article", id)));
+			return Response.status(Response.Status.NOT_FOUND).entity(res).build();
+		case 1:
+			res.setData(article);
+			return Response.ok().entity(res).build();
+		default:
+			return Response.serverError().build();
+		}
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java b/vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java
new file mode 100644
index 0000000000000000000000000000000000000000..14037482fbb3d0ee7eadaa0222b5b4f7f4ad9007
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java
@@ -0,0 +1,34 @@
+package de.vipra.rest.resource;
+
+import static com.mongodb.client.model.Sorts.*;
+
+import java.util.ArrayList;
+
+import org.bson.conversions.Bson;
+import org.bson.types.ObjectId;
+
+public class Helper {
+
+	public static Bson getSorts(String sortBy) {
+		String[] sortKeys = sortBy.split(",");
+		ArrayList<Bson> sorts = new ArrayList<>(sortKeys.length);
+		for (String sort : sortKeys) {
+			if (sort.startsWith("-")) {
+				sorts.add(descending(sort.substring(1)));
+			} else if (sort.startsWith("+")) {
+				sort = sort.substring(1);
+			}
+			sorts.add(ascending(sort));
+		}
+		return orderBy(sorts);
+	}
+
+	public static ObjectId objectId(String id) {
+		try {
+			return new ObjectId(id);
+		} catch (IllegalArgumentException e) {
+			return null;
+		}
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticlesSerializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticlesSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7e2c9f72e48f2ae0128c66af5da59d4312bca35
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticlesSerializer.java
@@ -0,0 +1,35 @@
+package de.vipra.rest.serializer;
+
+import de.vipra.rest.model.Articles;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public class ArticlesSerializer extends JsonSerializer<Articles> {
+
+	@Override
+	public void serialize(Articles value, JsonGenerator gen, SerializerProvider serializers)
+			throws IOException, JsonProcessingException {
+		gen.writeStartObject();
+		gen.writeStringField("id", value.getId());
+		gen.writeStringField("type", value.getType());
+		gen.writeObjectFieldStart("attributes");
+		if (value.getTitle() != null)
+			gen.writeStringField("title", value.getTitle());
+		if (value.getText() != null)
+			gen.writeStringField("text", value.getText());
+		if (value.getUrl() != null)
+			gen.writeStringField("url", value.getUrl());
+		if (value.getDate() != null)
+			gen.writeStringField("date", value.getDate().toString());
+		gen.writeEndObject();
+		if (value.getLinks() != null)
+			gen.writeObjectField("links", value.getLinks());
+		gen.writeEndObject();
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/LinkSerializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/LinkSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..f726f6743459f1c67a500a8342968c91f375e20a
--- /dev/null
+++ b/vipra-rest/src/main/java/de/vipra/rest/serializer/LinkSerializer.java
@@ -0,0 +1,27 @@
+package de.vipra.rest.serializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import de.vipra.rest.model.Link;
+
+public class LinkSerializer extends JsonSerializer<Link> {
+
+	@Override
+	public void serialize(Link value, JsonGenerator gen, SerializerProvider serializers)
+			throws IOException, JsonProcessingException {
+		if (value.getMeta() != null) {
+			gen.writeStartObject();
+			gen.writeStringField("href", value.getHref());
+			gen.writeObjectField("meta", value.getMeta());
+			gen.writeEndObject();
+		} else {
+			gen.writeString(value.getHref());
+		}
+	}
+
+}
diff --git a/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java b/vipra-rest/src/main/java/de/vipra/rest/service/ArticlesService.java
similarity index 51%
rename from vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java
rename to vipra-rest/src/main/java/de/vipra/rest/service/ArticlesService.java
index 0bbb199b4ebbadf6d521db645f7f6fba1b87481f..deb4bbd6c6f704ba6e1f6adaacbc3839ff38284e 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/service/ArticlesService.java
@@ -1,13 +1,9 @@
 package de.vipra.rest.service;
 
-import static com.mongodb.client.model.Sorts.ascending;
-import static com.mongodb.client.model.Sorts.descending;
-
+import java.net.URI;
 import java.util.ArrayList;
-import java.util.List;
 
 import org.bson.Document;
-import org.bson.types.ObjectId;
 
 import com.mongodb.client.MongoCollection;
 import com.mongodb.client.MongoDatabase;
@@ -15,50 +11,56 @@ import com.mongodb.client.model.Filters;
 import com.mongodb.client.result.DeleteResult;
 import com.mongodb.client.result.UpdateResult;
 
-import de.vipra.rest.dao.Article;
+import de.vipra.rest.model.Articles;
+
+import static de.vipra.rest.resource.Helper.*;
 
-public class ArticleService {
+public class ArticlesService {
 
 	final MongoCollection<Document> articles;
 
-	public ArticleService(MongoDatabase db) {
+	public ArticlesService(MongoDatabase db) {
 		articles = db.getCollection("articles");
 	}
 
-	public Article getArticle(String id) {
-		ObjectId objectId = new ObjectId(id);
-		ArrayList<Document> result = articles.find(Filters.eq("_id", objectId)).into(new ArrayList<Document>());
+	public Articles getArticle(URI base, String id) {
+		ArrayList<Document> result = articles.find(Filters.eq("_id", objectId(id))).into(new ArrayList<Document>());
 		if (result.size() == 1) {
-			return new Article(result.get(0));
+			Articles article = new Articles(result.get(0));
+			article.setSelf(base);
+			return article;
 		} else {
 			return null;
 		}
 	}
 
-	public List<Article> getArticles(int skip, int limit, String sortBy, String order) {
-		ArrayList<Document> docs = articles.find().skip(skip).limit(limit)
-				.sort(order.equals("desc") ? descending(sortBy) : ascending(sortBy)).into(new ArrayList<Document>());
-		ArrayList<Article> result = Article.fromDocuments(docs);
-		for (Article article : result) {
+	public ArrayList<Articles> getArticles(URI base, int skip, int limit, String sortBy) {
+
+		ArrayList<Document> docs = articles.find().skip(skip).limit(limit).sort(getSorts(sortBy))
+				.into(new ArrayList<Document>());
+		ArrayList<Articles> result = Articles.fromDocuments(docs);
+		for (Articles article : result) {
 			article.setText(null);
+			article.setSelf(base);
 		}
 		return result;
 	}
 
-	public Article createArticle(Article article) {
+	public Articles createArticle(URI base, Articles article) {
 		Document doc = new Document(article.toDocument());
 		articles.insertOne(doc);
-		return new Article(doc);
+		article = new Articles(doc);
+		article.setSelf(base);
+		return article;
 	}
 
 	public long deleteArticle(String id) {
-		ObjectId objectId = new ObjectId(id);
-		DeleteResult result = articles.deleteOne(Filters.eq("_id", objectId));
+		DeleteResult result = articles.deleteOne(Filters.eq("_id", objectId(id)));
 		return result.getDeletedCount();
 	}
 
-	public long updateArticle(Article article) {
-		Document docOld = new Document("_id", new ObjectId(article.getId()));
+	public long updateArticle(URI base, Articles article) {
+		Document docOld = new Document("_id", objectId(article.getId()));
 		Document docNew = article.toDocument();
 		UpdateResult result = articles.replaceOne(docOld, docNew);
 		return result.getModifiedCount();
diff --git a/vipra-rest/src/main/webapp/WEB-INF/web.xml b/vipra-rest/src/main/webapp/WEB-INF/web.xml
index 6dfda370c3a3a56b4957fe68b5ceab175159f489..dc73bea3b07729290fc992520ea78d71bcc9bd74 100644
--- a/vipra-rest/src/main/webapp/WEB-INF/web.xml
+++ b/vipra-rest/src/main/webapp/WEB-INF/web.xml
@@ -3,18 +3,6 @@
 	xmlns:web="http://xmlns.jcp.org/xml/ns/javaee"
 	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 	version="3.1">
-	<context-param>
-		<param-name>MONGODB_HOST</param-name>
-		<param-value>localhost</param-value>
-	</context-param>
-	<context-param>
-		<param-name>MONGODB_PORT</param-name>
-		<param-value>27017</param-value>
-	</context-param>
-	<context-param>
-		<param-name>MONGODB_DATABASE</param-name>
-		<param-value>test</param-value>
-	</context-param>
 	<servlet>
 		<servlet-name>jersey</servlet-name>
 		<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
@@ -27,7 +15,4 @@
 		<servlet-name>jersey</servlet-name>
 		<url-pattern>/rest/*</url-pattern>
 	</servlet-mapping>
-	<listener>
-		<listener-class>de.vipra.rest.MongoDBContextListener</listener-class>
-	</listener>
 </web-app>
\ No newline at end of file
diff --git a/vipra-rest/src/test/java/de/vipra/rest/resource/ArticleResourceTest.java b/vipra-rest/src/test/java/de/vipra/rest/resource/ArticleResourceTest.java
index 7ef0949f4b49cbaa15e53a9b0c6cb74711b9f2a5..c9b2d40c9acd82c7f5f4a568903143c3c2e8047b 100644
--- a/vipra-rest/src/test/java/de/vipra/rest/resource/ArticleResourceTest.java
+++ b/vipra-rest/src/test/java/de/vipra/rest/resource/ArticleResourceTest.java
@@ -9,13 +9,13 @@ import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.Test;
 
-import de.vipra.rest.resource.ArticleResource;
+import de.vipra.rest.resource.ArticlesResource;
 
 public class ArticleResourceTest extends JerseyTest {
 
 	@Override
 	protected Application configure() {
-		return new ResourceConfig(ArticleResource.class);
+		return new ResourceConfig(ArticlesResource.class);
 	}
 
 	@Test