Roxios Httpservice wrapper and stream data eventsources

Roxios makes http service so much more useful

You can send any type of request method
You can get response even if the request has an error
You can stream data using responsetype stream
You can get arraybuffers using responsetype arraybuffers
You can set timeouts for requests
Auto Jsondecode all requests unless you use the responsetype text if the text cant be parsed as json it will stay as text
You can get status codes
You can get headers

get, head, delete, options, trace request example

local response = roxios.get("https://example.com/") --replace get with your required method
local data = response.data
local headers = response.headers
local status = response.status
local statusText = response.statusText

post, put, patch request example

local response = roxios.post("https://example.com/", {["key"] = "value"}) --replace post with your required method
local data = response.data
local headers = response.headers
local status = response.status
local statusText = response.statusText

Get stream example (make sure your glitch projects are setup and working in the streamingservers table)

local response = roxios.get("https://example.com/", {["responseType"] = "stream"})
dataresponse = ""
response.ondata.Event:Connect(function(data)
	dataresponse = dataresponse  .. data
end)

response.onend.Event:Connect(function()
	print(dataresponse)
end)

response.close:Fire() --closes it

Time out example (timeout is in ms)

local response = roxios.get("https://example.com/", {["timeout"] = 5000})

Headers example

local response = roxios.get("https://example.com/",{["headers"] = {""}})

Get response data even on errors

local s,e = pcall(function()
	local response = roxios.get("https://example.com/")
end)
if not s then
	print(e.response)
end

Module: (copy and paste into a module script)

local streamingservers = { --remix the first one and create more servers if u are using streaming
	"https://f480y3f.glitch.me/"
}

local httpStatusCodes = {
	[100] = "Continue",
	[101] = "Switching Protocols",
	[200] = "OK",
	[201] = "Created",
	[202] = "Accepted",
	[203] = "Non-Authoritative Information",
	[204] = "No Content",
	[205] = "Reset Content",
	[206] = "Partial Content",
	[300] = "Multiple Choices",
	[301] = "Moved Permanently",
	[302] = "Found",
	[303] = "See Other",
	[304] = "Not Modified",
	[305] = "Use Proxy",
	[307] = "Temporary Redirect",
	[400] = "Bad Request",
	[401] = "Unauthorized",
	[402] = "Payment Required",
	[403] = "Forbidden",
	[404] = "Not Found",
	[405] = "Method Not Allowed",
	[406] = "Not Acceptable",
	[407] = "Proxy Authentication Required",
	[408] = "Request Timeout",
	[409] = "Conflict",
	[410] = "Gone",
	[411] = "Length Required",
	[412] = "Precondition Failed",
	[413] = "Payload Too Large",
	[414] = "URI Too Long",
	[415] = "Unsupported Media Type",
	[416] = "Range Not Satisfiable",
	[417] = "Expectation Failed",
	[500] = "Internal Server Error",
	[501] = "Not Implemented",
	[502] = "Bad Gateway",
	[503] = "Service Unavailable",
	[504] = "Gateway Timeout",
	[505] = "HTTP Version Not Supported",
}

httpservice = game:GetService("HttpService")

getmsgfromcode = function(code)
	local f = httpStatusCodes[code]
	if not f then
		f = "Unkown Status code"
	end
	return f
end

create_error = function(d, l)
	local b = "Axios Error: " .. d
	error({["message"] = b, ["response"] = l})
end


roxios = {}

roxios["request"] = function(method, url, data, options)
	local initresponse = {}
	initresponse["Url"] = url
	initresponse["Method"] = method
	if data and #data > 0 then
		initresponse["Body"] = data
	end
	if options and options["url"] then
		initresponse["Url"] = options["url"]
	end
	if options and options["method"] then
		initresponse["Method"] = string.upper(options["method"])
	end
	if options and options["headers"] and #options["headers"] > 0 then
		initresponse["Headers"] = options["headers"]
	end
	local timeout = math.huge
	if options and options["timeout"] and tonumber(options["timeout"]) then
		timeout = tonumber(options["timeout"])
	end
	local responsetype = nil
	if options and options["responseType"] then
		responsetype = options["responseType"]
	end
	
	if responsetype == "stream" then
		local touse = streamingservers[math.random(1, #streamingservers)]
		local streamid = roxios.get(touse .. "/?url=" .. initresponse["Url"] .. "&method=" .. initresponse["Method"]).data
		local ondata = Instance.new("BindableEvent")
		local endstream = Instance.new("BindableEvent")
		local close = Instance.new("BindableEvent")
		
		spawn(function()
			local ended = false
			while task.wait(1) and not ended do
				local newdata = roxios.get(touse .. "/newdata?id=" .. streamid).data
				if newdata == "end" then
					endstream:Fire("Stream ended")
					ended = true
					break
				end
				local s,e = pcall(function()
					for i,v in ipairs(newdata) do
						local buffer = v.data
						local str = ""
						for i,v in ipairs(buffer) do
							str = str .. string.char(v)
						end
						print(str)
						ondata:Fire(str)
					end
				end)
				if not s then
					warn(e)
				end
			end
			close.Event:Connect(function()
				ended = true
				endstream:Fire("Stream closed")
			end)
		end)
		
		return {["ondata"] = ondata, ["onend"] = endstream, ["close"] = close}
	end
	
	local start = os.clock() * 1000
	local basicresponse
	local timedout = false
	
	spawn(function()
		local s,e = pcall(function()
			basicresponse = httpservice:RequestAsync(initresponse)
		end)
		if not s then
			create_error(tostring(e),{})
			return
		end
	end)
	
	while not basicresponse and not timedout do
		task.wait()
		local target = ((os.clock() * 1000) - start)
		if target > timeout then
			timedout = true
		end
	end
	
	if timedout then
		create_error("timeout of "..timeout.."ms exceeded", {})
		return
	end
	
	local response = {}
	
	if responsetype == "arraybuffer" then
		local buffer = {}
		for i = 1, #basicresponse["Body"] do
			local char = basicresponse["Body"]:sub(i, i)
			local value = string.byte(char)
			table.insert(buffer, value)
		end
		response["Body"] = buffer
	end

	local c = basicresponse["StatusCode"]
	local msg = getmsgfromcode(c)
	
	if responsetype ~= "text" then
		pcall(function()
			basicresponse["Body"] = httpservice:JSONDecode(basicresponse["Body"])
		end)
	end
	
	response["status"] = c
	response["data"] = basicresponse["Body"]
	response["headers"] = basicresponse["Headers"]
	response["statusText"] = msg
	
	if c < 400 then
		return response
	else
		create_error("Request failed with status code" .. c, response)
	end
end


roxios["get"] = function(url, options)
	return roxios.request("GET", url, nil, options)
end

roxios["post"] = function(url, data, options)
	return roxios.request("POST", url, data, options)
end

roxios["put"] = function(url, data, options)
	return roxios.request("PUT", url, data, options)
end

roxios["delete"] = function(url, options)
	return roxios.request("DELETE", url, nil, options)
end

roxios["patch"] = function(url, data, options)
	return roxios.request("PATCH", url, data, options)
end

roxios["options"] = function(url, options)
	return roxios.request("OPTIONS", url, nil, options)
end

roxios["head"] = function(url, options)
	return roxios.request("HEAD", url, nil, options)
end

roxios["trace"] = function(url, options)
	return roxios.request("TRACE", url, nil, options)
end


return roxios
4 Likes

Axios for Roblox! How amazing!

1 Like

node-fetch/fetch >>>>>>>>>>>>>>>

1 Like