Added handler for correct JSON deserialization, addresses #195 (#287)

* Added handler for correct JSON deserialization (even with multiple body data writes), addresses #195

* Fixed typo

* Added JSON handler example to readme

* Moved Json Handler uri parameter to constructor

* Use request->_tempObject for JSON char data buffer

* Moved onRequest to constructor in JSON async handler
This commit is contained in:
Arsène von Wyss 2018-07-24 20:56:05 +02:00 committed by Me No Dev
parent fc66fae6a9
commit d7399a7664
2 changed files with 99 additions and 4 deletions

View File

@ -30,6 +30,7 @@ To use this library you might need to have the latest git versions of [ESP32](ht
- [GET, POST and FILE parameters](#get-post-and-file-parameters)
- [FILE Upload handling](#file-upload-handling)
- [Body data handling](#body-data-handling)
- [JSON body handling with ArduinoJson](#json-body-handling-with-arduinojson)
- [Responses](#responses)
- [Redirect to another URL](#redirect-to-another-url)
- [Basic response with HTTP Code](#basic-response-with-http-code)
@ -313,6 +314,20 @@ void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_
}
}
```
If needed, the `_tempObject` field on the request can be used to store a pointer to temporary data (e.g. from the body) associated with the request. If assigned, the pointer will automatically be freed along with the request.
### JSON body handling with ArduinoJson
Endpoints which consume JSON can use a special handler to get ready to use JSON data in the request callback:
```cpp
#include "AsyncJson.h"
#include "ArduinoJson.h"
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint", [](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject& jsonObj = json.as<JsonObject>();
// ...
});
server.addHandler(handler);
```
## Responses
### Redirect to another URL

View File

@ -1,9 +1,9 @@
// ESPasyncJson.h
// AsyncJson.h
/*
Async Response to use with arduinoJson and asyncwebserver
Async Response to use with ArduinoJson and AsyncWebServer
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon.
example of callback in use
Example of callback in use
server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
@ -17,11 +17,27 @@
request->send(response);
});
--------------------
Async Request to use with ArduinoJson and AsyncWebServer
Written by Arsène von Wyss (avonwyss)
Example
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint");
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject& jsonObj = json.as<JsonObject>();
// ...
});
server.addHandler(handler);
*/
#ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_
#include <ArduinoJson.h>
const char* JSON_MIMETYPE = "application/json";
/*
* Json Response
* */
@ -57,7 +73,7 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
public:
AsyncJsonResponse(bool isArray=false): _isValid{false} {
_code = 200;
_contentType = "application/json";
_contentType = JSON_MIMETYPE;
if(isArray)
_root = _jsonBuffer.createArray();
else
@ -80,4 +96,68 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
return len;
}
};
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant &json)> ArJsonRequestHandlerFunction;
class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
private:
protected:
const String _uri;
WebRequestMethodComposite _method;
ArJsonRequestHandlerFunction _onRequest;
int _contentLength;
int _maxContentLength;
public:
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
void setMethod(WebRequestMethodComposite method){ _method = method; }
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
virtual bool canHandle(AsyncWebServerRequest *request) override final{
if(!_onRequest)
return false;
if(!(_method & request->method()))
return false;
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
return false;
if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
return false;
request->addInterestingHeader("ANY");
return true;
}
virtual void handleRequest(AsyncWebServerRequest *request) override final {
if(_onRequest) {
if (request->_tempObject != NULL) {
DynamicJsonBuffer jsonBuffer;
JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject));
if (json.success()) {
_onRequest(request, json);
return;
}
}
request->send(_contentLength > _maxContentLength ? 413 : 400);
} else {
request->send(500);
}
}
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
}
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
if (_onRequest) {
_contentLength = total;
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
request->_tempObject = malloc(total);
}
if (request->_tempObject != NULL) {
memcpy((uint8_t*)(request->_tempObject) + index, data, len);
}
}
}
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
};
#endif