using System; using System.IO; using System.Net; using AllocsFixes.JSON; namespace Webserver.WebAPI { public abstract class AbsRestApi : AbsWebAPI { private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize"); 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 { jsonDeserializeSampler.Begin (); jsonBody = Parser.Parse (body); jsonDeserializeSampler.End (); } catch (Exception e) { jsonDeserializeSampler.End (); 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", 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 bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out int _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) { return false; } if (!(fieldNode is JsonValue valueField)) { return false; } try { _value = valueField.AsInt; return true; } catch (Exception) { return false; } } protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out double _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) { return false; } if (!(fieldNode is JsonValue valueField)) { return false; } try { _value = valueField.AsDouble; return true; } catch (Exception) { return false; } } protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out string _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) { return false; } if (!(fieldNode is JsonValue valueField)) { return false; } try { _value = valueField.AsString; return true; } catch (Exception) { return false; } } 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); } }