Index: binary-improvements2/MapRendering/Web/API/AbsRestApi.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/AbsRestApi.cs	(revision 388)
+++ binary-improvements2/MapRendering/Web/API/AbsRestApi.cs	(revision 388)
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+using System.Net;
+using AllocsFixes.JSON;
+
+namespace AllocsFixes.NetConnections.Servers.Web.API {
+	public abstract class AbsRestApi : AbsWebAPI {
+		public sealed override void HandleRequest (RequestContext _context) {
+			JSONNode jsonBody = null;
+
+			if (_context.Request.HasEntityBody) {
+				string body = new StreamReader (_context.Request.InputStream).ReadToEnd ();
+
+				if (!string.IsNullOrEmpty (body)) {
+					try {
+						jsonBody = Parser.Parse (body);
+					} catch (Exception e) {
+						SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
+						return;
+					}
+				}
+			}
+
+			try {
+				switch (_context.Request.HttpMethod) {
+					case "GET":
+						if (jsonBody != null) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "GET_WITH_BODY");
+							return;
+						}
+
+						HandleRestGet (_context);
+						return;
+					case "POST":
+						if (!string.IsNullOrEmpty (_context.RequestPath)) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "POST_WITH_ID");
+							return;
+						}
+
+						if (jsonBody == null) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
+							return;
+						}
+
+						HandleRestPost (_context, jsonBody);
+						return;
+					case "PUT":
+						if (string.IsNullOrEmpty (_context.RequestPath)) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "PUT_WITHOUT_ID");
+							return;
+						}
+
+						if (jsonBody == null) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
+							return;
+						}
+
+						HandleRestPut (_context, jsonBody);
+						return;
+					case "DELETE":
+						if (string.IsNullOrEmpty (_context.RequestPath)) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "DELETE_WITHOUT_ID");
+							return;
+						}
+
+						if (jsonBody != null) {
+							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
+							return;
+						}
+
+						HandleRestDelete (_context);
+						return;
+					default:
+						SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
+						return;
+				}
+			} catch (Exception e) {
+				SendEnvelopedResult (_context, null, HttpStatusCode.InternalServerError, jsonBody, "ERROR_PROCESSING", _exception: e);
+			}
+		}
+
+		private static readonly JSONArray emptyData = new JSONArray ();
+
+		protected void SendEnvelopedResult (RequestContext _context, JSONNode _resultData, HttpStatusCode _statusCode = HttpStatusCode.OK,
+			JSONNode _jsonInputBody = null, string _errorCode = null, Exception _exception = null) {
+			JSONObject meta = new JSONObject ();
+
+			meta.Add ("serverTime", new JSONString (DateTime.Now.ToString ("o")));
+			if (!string.IsNullOrEmpty (_errorCode)) {
+				meta.Add ("requestMethod", new JSONString (_context.Request.HttpMethod));
+				meta.Add ("requestSubpath", new JSONString (_context.RequestPath));
+				meta.Add ("requestBody", new JSONString (_jsonInputBody?.ToString () ?? "-empty-"));
+				meta.Add ("errorCode", new JSONString (_errorCode));
+				if (_exception != null) {
+					meta.Add ("exceptionMessage", new JSONString (_exception.Message));
+					meta.Add ("exceptionTrace", new JSONString (_exception.StackTrace));
+				}
+			}
+
+			JSONObject envelope = new JSONObject ();
+			envelope.Add ("meta", meta);
+			envelope.Add ("data", _resultData ?? emptyData);
+
+			WebUtils.WriteJson (_context.Response, envelope, _statusCode);
+		}
+
+		protected abstract void HandleRestGet (RequestContext _context);
+
+		protected abstract void HandleRestPost (RequestContext _context, JSONNode _jsonBody);
+
+		protected abstract void HandleRestPut (RequestContext _context, JSONNode _jsonBody);
+
+		protected abstract void HandleRestDelete (RequestContext _context);
+	}
+}
Index: binary-improvements2/MapRendering/Web/API/Markers.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/Markers.cs	(revision 388)
+++ binary-improvements2/MapRendering/Web/API/Markers.cs	(revision 388)
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using AllocsFixes.JSON;
+
+namespace AllocsFixes.NetConnections.Servers.Web.API {
+	class Markers : AbsRestApi {
+		private readonly Dictionary<string, (string, string)> markers = new Dictionary<string, (string, string)> ();
+
+		private static readonly JSONArray emptyResult = new JSONArray ();
+		
+		public Markers () {
+			markers.Add (WebUtils.GenerateGuid (), ("539", "498"));
+			markers.Add (WebUtils.GenerateGuid (), ("-18", "524"));
+			markers.Add (WebUtils.GenerateGuid (), ("29", "-162"));
+			markers.Add (WebUtils.GenerateGuid (), ("458", "-257"));
+		}
+
+		protected override void HandleRestGet (RequestContext _context) {
+			string id = _context.RequestPath;
+			
+			if (string.IsNullOrEmpty (id)) {
+				JSONArray result = new JSONArray ();
+
+				foreach (KeyValuePair<string, (string, string)> kvp in markers) {
+					JSONObject marker = new JSONObject ();
+					marker.Add ("id", new JSONString (kvp.Key));
+					marker.Add ("lat", new JSONString (kvp.Value.Item1));
+					marker.Add ("lng", new JSONString (kvp.Value.Item2));
+					result.Add (marker);
+				}
+				
+				SendEnvelopedResult (_context, result);
+				return;
+			}
+
+			if (!markers.TryGetValue (id, out (string, string) location)) {
+				SendEnvelopedResult (_context, emptyResult, HttpStatusCode.NotFound);
+				return;
+			}
+
+			{
+				JSONArray result = new JSONArray ();
+				JSONObject marker = new JSONObject ();
+				marker.Add ("id", new JSONString (id));
+				marker.Add ("lat", new JSONString (location.Item1));
+				marker.Add ("lng", new JSONString (location.Item2));
+				result.Add (marker);
+				SendEnvelopedResult (_context, result);
+			}
+		}
+
+		protected override void HandleRestPost (RequestContext _context, JSONNode _jsonBody) {
+			if (!(_jsonBody is JSONObject bodyObject)) {
+				
+			}
+
+			throw new NotImplementedException ();
+		}
+
+		protected override void HandleRestPut (RequestContext _context, JSONNode _jsonBody) {
+			throw new NotImplementedException ();
+		}
+
+		protected override void HandleRestDelete (RequestContext _context) {
+			throw new NotImplementedException ();
+		}
+	}
+}
