nodemcu / nodemcu-firmware

Lua based interactive firmware for ESP8266, ESP8285 and ESP32

Home Page:https://nodemcu.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ESP32 http module miss PUT

LianYangCn opened this issue · comments

http module miss PUT

why miss PUT?

Justification

We need PUT to upload objects to the Object Storage Service

Workarounds

POST works, but it will take more time to convert the object to the "POST" format

I guess you could ask the same thing about delete: why no http.delete()? @tomsci obviously saw no need for that when he contributed the module.

As PUT is almost identical to POST apart from the method designator in the header it should be little effort to port https://github.com/nodemcu/nodemcu-firmware/blob/dev-esp32/components/modules/http.c#L745 I assume. Also, note that there's a constant HTTP_METHOD_PUT in the ESP-IDF that we have not mapped yet at https://github.com/nodemcu/nodemcu-firmware/blob/dev-esp32/components/modules/http.c#L786.

It's possible to specify a custom request method to http.createConnection() without there needing to be an explicit http.put() function. http.post() is just a convenience function to save you having to use the more complex createConnection() API. I didn't add convenience functions for anything except get and post, since those are by far the most commonly used ones.

However, as noted we haven't defined a http.PUT constant. We should definitely fix that, it was an oversight on my part not to have added it.

If you really want a convenience put method, you could write something like the following, no need to add any native code. Although we should fix the lack of http.PUT - the or 2 below accounts for this such that when we do add it, it'll be used, and until then it uses the underlying esp_http_client_method_t value directly (which is ok so long as we don't upgrade to a new SDK version that renumbers esp_http_client_method_t without first adding http.PUT).

Note this is completely untested and only handles the synchronous case, and ignores what data the server may return (if any) - see the http docs (in particular connection:on()) for how to make things callback-based.

function http_put(url, options, body)
    local PUT = http.PUT or 2 -- handle http.PUT potentially not being defined yet
    options = options or {}
    options.async = false
    local conn = http.createConnection(url, PUT, options)
    conn:setpostdata(body) -- is this still the correct format for a PUT request?
    conn:setmethod(PUT) -- because setpostdata resets this
    conn:setheader("Connection", "close") -- we aren't reusing conn
    local response_headers = nil
    conn:on("headers", function(_, h) response_headers = h end)
    local status_code = conn:request()
    return status_code, response_headers
end

It's possible to specify a custom request method to http.createConnection()

Absolutely, I didn't mention it because I was too lazy to provide an example. Thanks a lot! Besides, I made a mental note that if we start changing/amending the module I'd prefer to

  • rename :setpostdata(body) to setbody(body) as POST isn't the only method that can have or does require a body
  • stop setting the HTTP method in setpostdata/setbody as a consequence

Agreed, both of those sound like a good idea 👍 I only named it setpostdata because that's what the ESP SDK calls it (and I clearly wasn't thinking much about put!)

It's possible to specify a custom request method to http.createConnection() without there needing to be an explicit http.put() function. http.post() is just a convenience function to save you having to use the more complex createConnection() API. I didn't add convenience functions for anything except get and post, since those are by far the most commonly used ones.

However, as noted we haven't defined a http.PUT constant. We should definitely fix that, it was an oversight on my part not to have added it.

If you really want a convenience put method, you could write something like the following, no need to add any native code. Although we should fix the lack of http.PUT - the or 2 below accounts for this such that when we do add it, it'll be used, and until then it uses the underlying esp_http_client_method_t value directly (which is ok so long as we don't upgrade to a new SDK version that renumbers esp_http_client_method_t without first adding http.PUT).

Note this is completely untested and only handles the synchronous case, and ignores what data the server may return (if any) - see the http docs (in particular connection:on()) for how to make things callback-based.

function http_put(url, options, body)
    local PUT = http.PUT or 2 -- handle http.PUT potentially not being defined yet
    options = options or {}
    options.async = false
    local conn = http.createConnection(url, PUT, options)
    conn:setpostdata(body) -- is this still the correct format for a PUT request?
    conn:setmethod(PUT) -- because setpostdata resets this
    conn:setheader("Connection", "close") -- we aren't reusing conn
    local response_headers = nil
    conn:on("headers", function(_, h) response_headers = h end)
    local status_code = conn:request()
    return status_code, response_headers
end

Great!
It's simple and works.