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

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