I was looking for http
library in lua and landed in luasocket.http page. It isn’t well documented, sent few GET, POST, PUT
requests and figured few bits. This blog post aims in bridging the gap(code examples).
In this example, I will use httpbin as target site. The complete code is available as gist.
The following code should be executed like a standalone lua file(lua lua_httpbin.lua
) and while executing the code in interpreter please make local variables http, ltn12, base_url
as global variables.
local http = require("socket.http")
local ltn12 = require("ltn12")
local base_url = "https://httpbin.org/"
--Helper for priniting nested table
function deep_print(tbl)
for i, v in pairs(tbl) do
if type(v) == "table" then
deep_print(v)
else
print(i, v)
end
end
end
function http_request( args )
--http.request(url [, body])
--http.request{
-- url = string,
-- [sink = LTN12 sink,]
-- [method = string,]
-- [headers = header-table,]
-- [source = LTN12 source],
-- [step = LTN12 pump step,]
-- [proxy = string,]
-- [redirect = boolean,]
-- [create = function]
--}
--
--
local resp, r = {}, {}
if args.endpoint then
local params = ""
if args.method == nil or args.method == "GET" then
-- prepare query parameters like http://xyz.com?q=23&a=2
if args.params then
for i, v in pairs(args.params) do
params = params .. i .. "=" .. v .. "&"
end
end
end
params = string.sub(params, 1, -2)
local url = ""
if params then url = base_url .. args.endpoint .. "?" .. params else url = base_url .. args.endpoint end
client, code, headers, status = http.request{url=url, sink=ltn12.sink.table(resp),
method=args.method or "GET", headers=args.headers, source=args.source,
step=args.step, proxy=args.proxy, redirect=args.redirect, create=args.create }
r['code'], r['headers'], r['status'], r['response'] = code, headers, status, resp
else
error("endpoint is missing")
end
return r
end
http_request
takes table as an argument which is almost similar to http.request
function with an extra parameter params
which will be helpful for passing parameters to GET
request.
http_request{endpoint=endpoint, params={age=23, name="kracekumar"}}
rather than http_request{endpoint=endpoint .. "?age=23&name=kracekumar"}
.
Remaining piece of code
function main()
-- Normal GET request
endpoint = "/user-agent"
print(endpoint)
deep_print(http_request{endpoint=endpoint})
-- GET request with parameters
endpoint = "/get"
print(endpoint)
deep_print(http_request{endpoint=endpoint, params={age=23, name ="kracekumar"}})
-- POST request with form
endpoint = "/post"
print(endpoint)
local req_body = "a=2"
local headers = {
["Content-Type"] = "application/x-www-form-urlencoded";
["Content-Length"] = #req_body;
}
deep_print(http_request{endpoint=endpoint, method="POST", source=ltn12.source.string(req_body), headers=headers})
-- PATCH Method
endpoint = "/patch"
print(endpoint)
deep_print(http_request{endpoint=endpoint, method="PATCH"})
-- PUT Method
endpoint = "/put"
print(endpoint)
deep_print(http_request{endpoint=endpoint, method="PUT", source =ltn12.source.string("a=23")})
-- Delete method
endpoint = "/delete"
print(endpoint)
deep_print(http_request{endpoint=endpoint, method="DELETE", source=ltn12.source.string("a=23")})
end
main()
output
# First lua is directory name
➜ lua lua lua_httpbin.lua
/user-agent
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:32:14 GMT
content-length 37
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"user-agent": "LuaSocket 2.0.2"
}
/get
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:32:15 GMT
content-length 258
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"headers": {
"Host": "httpbin.org",
"Connection": "close",
"User-Agent": "LuaSocket 2.0.2"
},
"url": "http://httpbin.org/get?age=23&name=kracekumar",
"args": {
"age": "23",
"name": "kracekumar"
},
"origin": "106.51.166.47"
}
/post
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:41:54 GMT
content-length 350
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"json": null,
"origin": "106.51.166.47",
"form": {
"a": "2"
},
"url": "http://httpbin.org/post",
"args": {},
"headers": {
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "LuaSocket 2.0.2",
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": "3"
},
"files": {},
"data": ""
}
/patch
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:32:17 GMT
content-length 251
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"files": {},
"headers": {
"Host": "httpbin.org",
"Connection": "close",
"User-Agent": "LuaSocket 2.0.2"
},
"args": {},
"json": null,
"form": {},
"origin": "106.51.166.47",
"url": "http://httpbin.org/patch",
"data": ""
}
/put
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:32:18 GMT
content-length 276
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"json": null,
"origin": "106.51.166.47",
"form": {},
"url": "http://httpbin.org/put",
"args": {},
"headers": {
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "LuaSocket 2.0.2",
"Content-Length": "0"
},
"files": {},
"data": ""
}
/delete
status HTTP/1.1 200 OK
code 200
connection Close
content-type application/json
date Fri, 19 Jul 2013 07:32:19 GMT
content-length 223
access-control-allow-origin *
server gunicorn/0.17.4
1 {
"args": {},
"json": null,
"headers": {
"Connection": "close",
"User-Agent": "LuaSocket 2.0.2",
"Host": "httpbin.org"
},
"origin": "106.51.166.47",
"data": "",
"url": "http://httpbin.org/delete"
}
My 2p
- When sending
GET
request don’t send paramters in request body. - When sending
POST
request set custom header for form.
My experience of luasocket.http
produces solid reason to create a new library with helper functions like requests.
See also
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.