95 lines
3.3 KiB
D
95 lines
3.3 KiB
D
/**
|
|
* Defines functions to read and write JSON values when handling HTTP requests.
|
|
*/
|
|
module handy_http_data.json;
|
|
|
|
import streams;
|
|
import handy_http_primitives.request;
|
|
import handy_http_primitives.response;
|
|
|
|
/**
|
|
* Reads a JSON value from the body of the given HTTP request, parsing it using
|
|
* the ASDF library according to the template type T.
|
|
*
|
|
* Throws a BAD_REQUEST HttpStatusException if deserialization fails.
|
|
* Params:
|
|
* request = The request to read the JSON from.
|
|
* Returns: The value that was read.
|
|
*/
|
|
T readJsonBodyAs(T)(ref ServerHttpRequest request) {
|
|
import asdf : deserialize, SerdeException;
|
|
try {
|
|
string requestBody = request.readBodyAsString(false);
|
|
return deserialize!T(requestBody);
|
|
} catch (SerdeException e) {
|
|
throw new HttpStatusException(HttpStatus.BAD_REQUEST, e.msg, e);
|
|
}
|
|
}
|
|
|
|
unittest {
|
|
import handy_http_primitives.builder;
|
|
ServerHttpRequest request = ServerHttpRequestBuilder()
|
|
.withBody("{\"key\": \"value\"}")
|
|
.withHeader("Content-Length", "16")
|
|
.build();
|
|
struct TestStruct {
|
|
string key;
|
|
}
|
|
TestStruct testStruct = readJsonBodyAs!TestStruct(request);
|
|
assert(testStruct.key == "value");
|
|
}
|
|
|
|
/**
|
|
* Writes a JSON value to the body of the given HTTP response, serializing it
|
|
* using the ASDF library. Will also set Content-Type and Content-Length
|
|
* headers before writing.
|
|
*
|
|
* Throws an INTERNAL_SERVER_ERROR HttpStatusException if serialization or
|
|
* writing fails.
|
|
* Params:
|
|
* response = The response to write to.
|
|
* bodyContent = The content to write.
|
|
*/
|
|
void writeJsonBody(T)(ref ServerHttpResponse response, in T bodyContent) {
|
|
import std.conv : to;
|
|
import std.traits : isArray;
|
|
import std.json;
|
|
import asdf : serializeToJson, SerdeException;
|
|
try {
|
|
static if (isArray!T && bodyContent.length == 0) {
|
|
string responseBody = "[]";
|
|
} else static if (is(T == JSONValue)) {
|
|
string responseBody = bodyContent.toString();
|
|
} else {
|
|
string responseBody = serializeToJson(bodyContent);
|
|
}
|
|
response.headers.remove("Content-Type");
|
|
response.headers.remove("Content-Length");
|
|
response.headers.add("Content-Type", "application/json");
|
|
response.headers.add("Content-Length", to!string(responseBody.length));
|
|
StreamResult result = response.outputStream.writeToStream(cast(ubyte[]) responseBody);
|
|
if (result.hasError) {
|
|
StreamError err = result.error;
|
|
throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR, cast(string) err.message);
|
|
}
|
|
} catch (SerdeException e) {
|
|
throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.msg, e);
|
|
}
|
|
}
|
|
|
|
unittest {
|
|
import handy_http_primitives.builder;
|
|
ArrayOutputStream!ubyte outputStream = byteArrayOutputStream();
|
|
ServerHttpResponse response = ServerHttpResponseBuilder()
|
|
.withOutputStream(&outputStream)
|
|
.build();
|
|
struct TestStruct {
|
|
string key;
|
|
}
|
|
TestStruct testStruct = TestStruct("value");
|
|
writeJsonBody(response, testStruct);
|
|
assert(response.headers["Content-Type"] == "application/json");
|
|
const writtenBody = cast(string) outputStream.toArrayRaw();
|
|
assert(writtenBody == "{\"key\":\"value\"}");
|
|
}
|