source: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs@ 416

Last change on this file since 416 was 410, checked in by alloc, 21 months ago

Base API class improvements

File size: 6.3 KB
RevLine 
[391]1using System;
[402]2using System.Collections.Generic;
[391]3using System.IO;
4using System.Net;
[402]5using Utf8Json;
[391]6
7namespace Webserver.WebAPI {
8 public abstract class AbsRestApi : AbsWebAPI {
[394]9 private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize");
10
[410]11 protected AbsRestApi (string _name = null) : this(null, _name) {
12 }
13
14 protected AbsRestApi (Web _parentWeb, string _name = null) : base(_parentWeb, _name) {
15 }
16
[391]17 public sealed override void HandleRequest (RequestContext _context) {
[402]18 IDictionary<string, object> inputJson = null;
19 byte[] jsonInputData = null;
20
[391]21 if (_context.Request.HasEntityBody) {
[402]22 Stream requestInputStream = _context.Request.InputStream;
23
24 jsonInputData = new byte[_context.Request.ContentLength64];
25 requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
26
27 try {
28 jsonDeserializeSampler.Begin ();
29 inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
30
31 // Log.Out ("JSON body:");
32 // foreach ((string key, object value) in inputJson) {
33 // Log.Out ($" - {key} = {value} ({value.GetType ()})");
34 // }
35
36 jsonDeserializeSampler.End ();
37 } catch (Exception e) {
38 jsonDeserializeSampler.End ();
[391]39
[402]40 SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
41 return;
[391]42 }
43 }
44
45 try {
46 switch (_context.Request.HttpMethod) {
47 case "GET":
[402]48 if (inputJson != null) {
49 SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
[391]50 return;
51 }
52
53 HandleRestGet (_context);
54 return;
55 case "POST":
56 if (!string.IsNullOrEmpty (_context.RequestPath)) {
[402]57 SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
[391]58 return;
59 }
60
[402]61 if (inputJson == null) {
62 SendErrorResult (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
[391]63 return;
64 }
65
[402]66 HandleRestPost (_context, inputJson, jsonInputData);
[391]67 return;
68 case "PUT":
69 if (string.IsNullOrEmpty (_context.RequestPath)) {
[402]70 SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
[391]71 return;
72 }
73
[402]74 if (inputJson == null) {
75 SendErrorResult (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
[391]76 return;
77 }
78
[402]79 HandleRestPut (_context, inputJson, jsonInputData);
[391]80 return;
81 case "DELETE":
82 if (string.IsNullOrEmpty (_context.RequestPath)) {
[402]83 SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
[391]84 return;
85 }
86
[402]87 if (inputJson != null) {
88 SendErrorResult (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
[391]89 return;
90 }
91
92 HandleRestDelete (_context);
93 return;
94 default:
[402]95 SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
[391]96 return;
97 }
98 } catch (Exception e) {
[402]99 SendErrorResult (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e);
[391]100 }
101 }
102
[402]103 static AbsRestApi () {
104 JsonWriter writer = new JsonWriter ();
105 writer.WriteBeginArray ();
106 writer.WriteEndArray ();
107 JsonEmptyData = writer.ToUtf8ByteArray ();
108 }
[391]109
[404]110 protected virtual void HandleRestGet (RequestContext _context) {
111 SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
112 }
113
114 protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
115 SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
116 }
117
118 protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
119 SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
120 }
121
122 protected virtual void HandleRestDelete (RequestContext _context) {
123 SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
124 }
125
126
127#region Helpers
128
[402]129 protected static readonly byte[] JsonEmptyData;
130
[404]131 protected static void PrepareEnvelopedResult (out JsonWriter _writer) {
[402]132 WebUtils.PrepareEnvelopedResult (out _writer);
133 }
[391]134
[404]135 protected static void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
[402]136 byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
137
138 WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception);
[391]139 }
140
[404]141 protected static void SendErrorResult (RequestContext _context, HttpStatusCode _statusCode, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
142 PrepareEnvelopedResult (out JsonWriter writer);
143 writer.WriteRaw (JsonEmptyData);
144 SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception);
145 }
146
147 protected static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out int _value) {
[391]148 _value = default;
149
[402]150 if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
[391]151 return false;
152 }
153
[402]154 if (fieldNode is not double value) {
[391]155 return false;
156 }
157
158 try {
[402]159 _value = (int)value;
[391]160 return true;
161 } catch (Exception) {
162 return false;
163 }
164 }
165
[404]166 protected static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out double _value) {
[391]167 _value = default;
168
[402]169 if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
[391]170 return false;
171 }
172
[402]173 if (fieldNode is not double value) {
[391]174 return false;
175 }
176
177 try {
[402]178 _value = value;
[391]179 return true;
180 } catch (Exception) {
181 return false;
182 }
183 }
184
[404]185 protected static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out string _value) {
[391]186 _value = default;
187
[402]188 if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
[391]189 return false;
190 }
191
[402]192 if (fieldNode is not string value) {
[391]193 return false;
194 }
195
196 try {
[402]197 _value = value;
[391]198 return true;
199 } catch (Exception) {
200 return false;
201 }
202 }
[404]203
[391]204
[404]205#endregion
[391]206 }
207}
Note: See TracBrowser for help on using the repository browser.