using System; using System.Collections.Generic; using System.IO; using System.Net; using Utf8Json; 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) { IDictionary inputJson = null; byte[] jsonInputData = null; if (_context.Request.HasEntityBody) { Stream requestInputStream = _context.Request.InputStream; jsonInputData = new byte[_context.Request.ContentLength64]; requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64); try { jsonDeserializeSampler.Begin (); inputJson = JsonSerializer.Deserialize> (jsonInputData); // Log.Out ("JSON body:"); // foreach ((string key, object value) in inputJson) { // Log.Out ($" - {key} = {value} ({value.GetType ()})"); // } jsonDeserializeSampler.End (); } catch (Exception e) { jsonDeserializeSampler.End (); SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e); return; } } try { switch (_context.Request.HttpMethod) { case "GET": if (inputJson != null) { SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY"); return; } HandleRestGet (_context); return; case "POST": if (!string.IsNullOrEmpty (_context.RequestPath)) { SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID"); return; } if (inputJson == null) { SendErrorResult (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY"); return; } HandleRestPost (_context, inputJson, jsonInputData); return; case "PUT": if (string.IsNullOrEmpty (_context.RequestPath)) { SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID"); return; } if (inputJson == null) { SendErrorResult (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY"); return; } HandleRestPut (_context, inputJson, jsonInputData); return; case "DELETE": if (string.IsNullOrEmpty (_context.RequestPath)) { SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID"); return; } if (inputJson != null) { SendErrorResult (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY"); return; } HandleRestDelete (_context); return; default: SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD"); return; } } catch (Exception e) { SendErrorResult (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e); } } protected void SendErrorResult (RequestContext _context, HttpStatusCode _statusCode, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) { PrepareEnvelopedResult (out JsonWriter writer); writer.WriteRaw (JsonEmptyData); SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception); } static AbsRestApi () { JsonWriter writer = new JsonWriter (); writer.WriteBeginArray (); writer.WriteEndArray (); JsonEmptyData = writer.ToUtf8ByteArray (); } protected static readonly byte[] JsonEmptyData; protected void PrepareEnvelopedResult (out JsonWriter _writer) { WebUtils.PrepareEnvelopedResult (out _writer); } protected void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) { WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception); } protected bool TryGetJsonField (IDictionary _jsonObject, string _fieldName, out int _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) { return false; } if (fieldNode is not double value) { return false; } try { _value = (int)value; return true; } catch (Exception) { return false; } } protected bool TryGetJsonField (IDictionary _jsonObject, string _fieldName, out double _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) { return false; } if (fieldNode is not double value) { return false; } try { _value = value; return true; } catch (Exception) { return false; } } protected bool TryGetJsonField (IDictionary _jsonObject, string _fieldName, out string _value) { _value = default; if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) { return false; } if (fieldNode is not string value) { return false; } try { _value = value; return true; } catch (Exception) { return false; } } protected virtual void HandleRestGet (RequestContext _context) { SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported"); } protected virtual void HandleRestPost (RequestContext _context, IDictionary _jsonInput, byte[] _jsonInputData) { SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported"); } protected virtual void HandleRestPut (RequestContext _context, IDictionary _jsonInput, byte[] _jsonInputData) { SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported"); } protected virtual void HandleRestDelete (RequestContext _context) { SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported"); } } }