{"id":13776653,"url":"https://github.com/tokers/lua-resty-requests","last_synced_at":"2025-04-06T02:47:01.978Z","repository":{"id":47814417,"uuid":"119240343","full_name":"tokers/lua-resty-requests","owner":"tokers","description":"Yet Another HTTP library for OpenResty - For human beings!","archived":false,"fork":false,"pushed_at":"2020-05-06T10:28:59.000Z","size":121,"stargazers_count":159,"open_issues_count":11,"forks_count":28,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-02-14T17:32:22.485Z","etag":null,"topics":["lua-resty","openresty"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tokers.png","metadata":{"files":{"readme":"README.markdown","changelog":"CHANGELOG.markdown","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-28T08:16:26.000Z","updated_at":"2023-12-11T06:18:05.000Z","dependencies_parsed_at":"2022-09-12T01:40:18.937Z","dependency_job_id":null,"html_url":"https://github.com/tokers/lua-resty-requests","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-requests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-requests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-requests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-requests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tokers","download_url":"https://codeload.github.com/tokers/lua-resty-requests/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247426984,"owners_count":20937197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua-resty","openresty"],"created_at":"2024-08-03T18:00:31.124Z","updated_at":"2025-04-06T02:47:01.955Z","avatar_url":"https://github.com/tokers.png","language":"Lua","funding_links":[],"categories":["Libraries","Lua"],"sub_categories":[],"readme":"Name\n====\n\nlua-resty-requests - Yet Another HTTP Library for OpenResty.\n\n![Build Status](https://travis-ci.org/tokers/lua-resty-requests.svg?branch=master)\n\n```bash\nresty -e 'print(require \"resty.requests\".get{ url = \"https://github.com\", stream = false }.content)'\n```\n\nTable of Contents\n=================\n\n* [Name](#name)\n* [Status](#status)\n* [Features](#features)\n* [Synopsis](#synopsis)\n* [Installation](#installation)\n* [Methods](#methods)\n    * [request](#request)\n    * [state](#state)\n    * [get](#get)\n    * [head](#head)\n    * [post](#post)\n    * [put](#put)\n    * [delete](#delete)\n    * [options](#options)\n    * [patch](#patch)\n* [Response Object](#response-object)\n* [Session](#session)\n* [TODO](#todo)\n* [Author](#author)\n* [Copyright and License](#copyright-and-license)\n* [See Also](#see-also)\n\nStatus\n======\n\nThis Lua module now can be considered as production ready.\n\nNote since the `v0.7.1` release, this module started using lua-resty-socket,\nfor working in the non-yieldable phases, but still more efforts are needed,\nso **DONOT** use it in the `init` or `init_worker` phases (or other\nnon-yieldable phases).\n\nFeatures\n========\n\n* HTTP/1.0, HTTP/1.1 and HTTP/2 (WIP).\n* SSL/TLS support.\n* Chunked data support.\n* Convenient interfaces to support features like json, authorization and etc.\n* Stream interfaces to read body.\n* HTTP/HTTPS proxy.\n* Latency metrics.\n* Session support.\n\nSynopsis\n========\n\n```lua\nlocal requests = require \"resty.requests\"\n\n-- example url\nlocal url = \"http://example.com/index.html\"\n\nlocal r, err = requests.get(url)\nif not r then\n    ngx.log(ngx.ERR, err)\n    return\nend\n\n-- read all body\nlocal body = r:body()\nngx.print(body)\n\n-- or you can iterate the response body\n-- while true do\n--     local chunk, err = r:iter_content(4096)\n--     if not chunk then\n--         ngx.log(ngx.ERR, err)\n--         return\n--     end\n--\n--     if chunk == \"\" then\n--         break\n--     end\n--\n--     ngx.print(chunk)\n-- end\n\n-- you can also use the non-stream mode\n-- local opts = {\n--     stream = false\n-- }\n--\n-- local r, err = requests.get(url, opts)\n-- if not r then\n--     ngx.log(ngx.ERR, err)\n-- end\n--\n-- ngx.print(r.content)\n\n-- or you can use the shortcut way to make the code cleaner.\nlocal r, err = requests.get { url = url, stream = false }\n```\n\nInstallation\n============\n\n* [LuaRocks](https://luarocks.org):\n\n```bash\n$ luarocks install lua-resty-requests\n```\n\n* [OPM](https://github.com/openresty/opm):\n\n```bash\n$ opm get tokers/lua-resty-requests\n```\n\n* Manually:\n\nJust tweeks the `lua_package_path` or the `LUA_PATH` environment variable, to add the installation path for this Lua module:\n\n```\n/path/to/lua-resty-requests/lib/resty/?.lua;\n```\n\nMethods\n=======\n\n### request\n\n**syntax**: *local r, err = requests.request(method, url, opts?)*  \n**syntax**: *local r, err = requests.request { method = method, url = url, ... }\n\nThis is the pivotal method in `lua-resty-requests`, it will return a [response object](#response-object) `r`. In the case of failure, `nil`, and a Lua string which describles the corresponding error will be given.\n\nThe first parameter `method`, is the HTTP method that you want to use(same as\nHTTP's semantic), which takes a Lua string and the value can be:\n\n* `GET`\n* `HEAD`\n* `POST`\n* `PUT`\n* `DELETE`\n* `OPTIONS`\n* `PATCH`\n\nThe second parameter `url`, just takes the literal meaning(i.e. Uniform Resource Location),\nfor instance, `http://foo.com/blah?a=b`, you can omit the scheme prefix and as the default scheme,\n`http` will be selected.\n\nThe third param, an optional Lua table, which contains a number of  options:\n\n* `headers` holds the custom request headers.\n\n* `allow_redirects` specifies whether redirecting to the target url(specified by `Location` header) or not when the status code is `301`, `302`, `303`, `307` or `308`.\n\n* `redirect_max_times` specifies the redirect limits, default is `10`.\n\n* `body`, the request body, can be:\n    * a Lua string, or\n    * a Lua function, without parameter and returns a piece of data (string) or an empty Lua string to represent EOF, or\n    * a Lua table, each key-value pair will be concatenated with the \"\u0026\", and Content-Type header will `\"application/x-www-form-urlencoded\"`\n\n* `error_filter`, holds a Lua function which takes two parameters, `state` and `err`.\n the parameter `err` describes the error and `state` is always one of these values(represents the current stage):\n    * `requests.CONNECT`\n    * `requests.HANDSHAKE`\n    * `requests.SEND_HEADER`\n    * `requests.SEND_BODY`\n    * `requests.RECV_HEADER`\n    * `requests.RECV_BODY`\n    * `requests.CLOSE`\n\nYou can use the method [requests.state](#state) to get the textual meaning of these values.\n\n\n* `timeouts`, an array-like table, `timeouts[1]`, `timeouts[2]` and `timeouts[3]` represents `connect timeout`, `send timeout` and `read timeout` respectively (in milliseconds).\n\n* `http10` specify whether the `HTTP/1.0` should be used, default verion is `HTTP/1.1`.\n* `http20` specify whether the `HTTP/2` should be used, default verion is `HTTP/1.1`.\n\nNote this is still unstable, caution should be exercised. Also, there are some\nlimitations, see [lua-resty-http2](https://github.com/tokers/lua-resty-http2) for the details.\n\n* `ssl` holds a Lua table, with three fields:\n  * `verify`, controls whether to perform SSL verification\n  * `server_name`, is used to specify the server name for the new TLS extension Server Name Indication (SNI)\n\n* `proxies` specify proxy servers, the form is like\n\n```lua\n{\n    http = { host = \"127.0.0.1\", port = 80 },\n    https = { host = \"192.168.1.3\", port = 443 },\n}\n```\n\nWhen using HTTPS proxy, a preceding CONNECT request will be sent to proxy server.\n\n* `hooks`, also a Lua table, represents the hook system that you can use to\nmanipulate portions of the request process. Available hooks are:\n  * `response`, will be triggered immediately after receiving the response headers\n\nyou can assign Lua functions to hooks, these functions accept the [response object](#response-object) as the unique param.\n\n```lua\nlocal hooks = {\n    response = function(r)\n        ngx.log(ngx.WARN, \"during requests process\")\n    end\n}\n```\n\nConsidering the convenience, there are also some \"short path\" options:\n\n* `auth`, to do the Basic HTTP Authorization, takes a Lua table contains `user` and `pass`, e.g. when `auth` is:\n\n```lua\n{\n    user = \"alex\",\n    pass = \"123456\"\n}\n```\n\nRequest header `Authorization` will be added, and the value is `Basic YWxleDoxMjM0NTY=`.\n\n* `json`, takes a Lua table, it will be serialized by `cjson`, the serialized data will be sent as the request body, and it takes the priority when both `json` and `body` are specified.\n\n* `cookie`, takes a Lua table, the key-value pairs will be organized according to the `Cookie` header's rule, e.g. `cookie` is:\n\n```lua\n{\n    [\"PHPSESSID\"] = \"298zf09hf012fh2\",\n    [\"csrftoken\"] = \"u32t4o3tb3gg43\"\n}\n```\n\nThe `Cookie` header will be `PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43 `.\n\n* `stream`, takes a boolean value, specifies whether reading the body in the stream mode, and it will be true by default. \n\n### state\n\n**syntax**: *local state_name = requests.state(state)*\n\nThe method is used for getting the textual meaning of these values:\n\n * `requests.CONNECT`\n * `requests.HANDSHAKE`\n * `requests.SEND_HEADER`\n * `requests.SEND_BODY`\n * `requests.RECV_HEADER`\n * `requests.RECV_BODY`\n * `requests.CLOSE`\n\na Lua string `\"unknown\"` will be returned if `state` isn't one of the above values.\n\n### get\n\n**syntax**: *local r, err = requests.get(url, opts?)*  \n**syntax**: *local r, err = requests.get { url = url, ... }*\n\nSends a HTTP GET request. This is identical with\n\n```lua\nrequests.request(\"GET\", url, opts)\n```\n\n### head\n**syntax**: *local r, err = requests.head(url, opts?)*   \n**syntax**: *local r, err = requests.head { url = url, ... }*\n\nSends a HTTP HEAD request. This is identical with\n\n```lua\nrequests.request(\"HEAD\", url, opts)\n```\n\n### post\n**syntax**: *local r, err = requests.post(url, opts?)*    \n**syntax**: *local r, err = requests.post { url = url, ... }*\n\nSends a HTTP POST request. This is identical with\n\n```lua\nrequests.request(\"POST\", url, opts)\n```\n\n### put\n**syntax**: *local r, err = requests.put(url, opts?)*    \n**syntax**: *local r, err = requests.put { url = url, ... }*\n\nSends a HTTP PUT request. This is identical with\n\n```lua\nrequests.request(\"PUT\", url, opts)\n```\n\n### delete\n**syntax**: *local r, err = requests.delete(url, opts?)*  \n**syntax**: *local r, err = requests.delete { url = url, ... }*\n\nSends a HTTP DELETE request. This is identical with\n\n```lua\nrequests.request(\"DELETE\", url, opts)\n```\n\n### options\n**syntax**: *local r, err = requests.options(url, opts?)*  \n**syntax**: *local r, err = requests.options { url = url, ... }*\n\nSends a HTTP OPTIONS request. This is identical with\n\n```lua\nrequests.request(\"OPTIONS\", url, opts)\n```\n\n### patch\n**syntax**: *local r, err = requests.patch(url, opts?)*  \n**syntax**: *local r, err = requests.patch { url = url, ... }*\n\nSends a HTTP PATCH request. This is identical with\n\n```lua\nrequests.request(\"PATCH\", url, opts)\n```\n\nResponse Object\n===============\n\nMethods like `requests.get` and others will return a response object `r`, which can be manipulated by the following methods and variables:\n\n* `url`, the url passed from caller\n* `method`, the request method, e.g. `POST`\n* `status_line`, the raw status line(received from the remote)\n* `status_code`, the HTTP status code\n* `http_version`, the HTTP version of response, e.g. `HTTP/1.1`\n* `headers`, a Lua table represents the HTTP response headers(case-insensitive)\n* `close`, holds a Lua function, used to close(keepalive) the underlying TCP connection\n* `drop`, is a Lua function, used for dropping the unread HTTP response body, will be invoked automatically when closing (if any unread data remains)\n* `iter_content`, which is also a Lua function, emits a part of response body(decoded from chunked format) each time called. \n\nThis function accepts an optional param `size` to specify the size of body that the caller wants, when absent, `iter_content` returns `8192` bytes when the response body is plain or returns a piece of chunked data if the resposne body is chunked.\n\nIn case of failure, `nil` and a Lua string described the error will be returned.\n\n* `body`, also holds a Lua function that returns the whole response body.\n\nIn case of failure, `nil` and a Lua string described the error will be returned.\n\n* `json`, holds a Lua function, serializes the body to a Lua table, note the `Content-Type` should be `application/json`. In case of failure, `nil` and an error string will be given.\n\n* `content`, the response body, only valid in the non-stream mode.\n\n* `elapsed`, a hash-like Lua table which represents the cost time (in seconds) for each stage.\n  * `elapsed.connect`, cost time for the TCP 3-Way Handshake;\n  * `elapsed.handshake`, cost time for the SSL/TLS handshake (if any);\n  * `elapsed.send_header`, cost time for sending the HTTP request headers;\n  * `elapsed.send_body`, cost time for sending the HTTP request body (if any);\n  * `elapsed.read_header`, cost time for receiving the HTTP response headers;\n  * `elapsed.ttfb`, the time to first byte.\n\nNote When HTTP/2 protocol is applied, the `elapsed.send_body` (if any) will be same as `elapsed.send_header`.\n\nSession\n=======\n\nA session persists some data across multiple requests, like cookies data, authorization data and etc.\n\nThis mechanism now is still experimental.\n\nA simple example:\n\n```lua\ns = requests.session()\nlocal r, err = s:get(\"https://www.example.com\")\nngx.say(r:body())\n```\n\nA session object has same interfaces with `requests`, i.e. those http methods.\n\nTODO\n====\n\n* other interesting features...\n\n\nAuthor\n======\n\nAlex Zhang (张超) zchao1995@gmail.com, UPYUN Inc.\n\nCopyright and License\n=====================\n\nThe bundle itself is licensed under the 2-clause BSD license.\n\nCopyright (c) 2017-2019, Alex Zhang.\n\nThis module is licensed under the terms of the BSD license.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSee Also\n=========\n\n* upyun-resty: https://github.com/upyun/upyun-resty\n* httpipe: https://github.com/timebug/lua-resty-httpipe\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftokers%2Flua-resty-requests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftokers%2Flua-resty-requests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftokers%2Flua-resty-requests/lists"}