diff --git a/README.md b/README.md index 8a4142d..7ec5424 100644 --- a/README.md +++ b/README.md @@ -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(); + // ... +}); +server.addHandler(handler); +``` ## Responses ### Redirect to another URL diff --git a/src/AsyncJson.h b/src/AsyncJson.h index ec9a63e..062cbbc 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -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(); + // ... + }); + server.addHandler(handler); + */ #ifndef ASYNC_JSON_H_ #define ASYNC_JSON_H_ #include +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 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