I am trying to call a REST API through LUA. However, I am not able to capture full raw response returned by the API. Below is the code sample:
local http_socket = require("socket.http")
local pretty_print = require("pl.pretty")
local header = {
["x-device-type"] = "M",
["authorization"] = "ashdjkashd",
["x-app-secret"] = "asdasda",
["x-user-id"] = "asdasdasd"
}
r, c, h = http_socket.request {
method = "GET", -- Validation API Method
url = "http://google.com", -- Validation API URL
headers = header
}
print(r .. c)
pretty_print.dump(h)
I'm using lua 5.3, and luarocks version=2.4.1.
In variable c i am getting code, and in h there are a few headers. I need to capture full response returned by the API.
As you may know, luasocket's http.request supports two forms of usage. I'm assuming you need the second form to customize the resty request for that particular API.
In this case to capture the response body you'll need to use the sink field with ltn12.sink module. For example
local ltn12 = require 'ltn12'
-- ...
local res = {}
r, c, h, s = http_socket.request
{
method = "GET", -- Validation API Method
url = "http://google.com", -- Validation API URL
headers = header,
sink = ltn12.sink.table(res)
}
res = table.concat(res)
print(res)
The table.concat is needed since the response could be comprised of multiple chunk sizes(appended to res as it's received).
You can also write it out to file by replacing above with ltn12.sink.file, eg. using ltn12.sink.file(io.stdout) will dump the response to standard output.
Related
I am 100% sure that my client-id and client-secret are valid. I used it in my python code and it just worked fine
local http = require("coro-http")
local json = require("json")
local url = "https://id.twitch.tv/oauth2/token"
local client_id = "<>"
local client_secret = "<>"
local headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
local body = "client_id=" .. client_id .. "&client_secret=" .. client_secret .. "&grant_type=client_credentials"
local response, w = http.request("POST", url, headers, body)
print(w)
local data = json.decode(w)
local access_token = data.access_token
local headers = {
["Client-ID"] = client_id,
["Authorization"] = "Bearer " .. access_token
}
local response, b = http.request("GET", "https://api.twitch.tv/helix/channels?broadcaster_id=141981764", headers)
print(b)
Getting token and then do a simple get request
I found this repository which is doing exactly what you're trying to.
From the code you provided and the one from the above repo, I would say #LMD comment is the way to go. You need to urlencode your body string.
Maybe querystring from luvit could be a good starting point.
How to resolved error or possible ways to resolved it?
Guys, i've developed plugin using Lua language which can be integrate or run from Adobe's LightRoom Classic. Currently i need to upload or send a file to server but i can not. Everytime i called the POST API which is multipart/form-data error popup "?:0: attempt to perform arithmetic on field 'fileSize' (a nil value)". Not even API is being called this error pops up before API call. after debug I can assure the possible issue is in creating mimeChunks with file type.
I have developed the code like below, can any one help me out with suggestions so that i can able to resolved issue?
local filePath = assert("C:\Users\Ankit\Desktop\Hangman.PNG")
local fileName = LrPathUtils.leafName(filePath)
local mimeChunks = {}
mimeChunks[#mimeChunks + 1] = {
name = 'api_sig',
value = "test value"
}
mimeChunks[#mimeChunks + 1] = {
name = "file",
filePath = filePath,
fileName = fileName,
contentType = "application/octet-stream"
}
local postUrl = "API endpoint"
local result, hdrs = LrHttp.postMultipart(postUrl, mimeChunks)
if result then
LrDialogs.message("Form Values", result)
else
LrDialogs.message("Form Values", "API issue")
end
Eventually image or file path itself cause the issue, there are no such indications or articles related to this functionality, but yes "add-on backslash" will work out for sure. Kindly review the below code for more detailed bifurcation which pass dynamic selected file or image path.
local function uploadFile(filePath)
local fileName = LrPathUtils.leafName( filePath )
local mimeChunks = {}
mimeChunks[ #mimeChunks + 1 ] = { name = 'api_sig', value = "test value"}
mimeChunks[#mimeChunks + 1] = {
name = "file",
filePath = filePath,
fileName = fileName,
contentType = "image/jpeg" --multipart/form-data --application/octet-stream
}
import "LrTasks".startAsyncTask(
function()
local postUrl = "http://cms.local.com/api/v1/upload"
local result, hdrs = LrHttp.postMultipart(postUrl, mimeChunks)
if result then
LrDialogs.message("Image uploaded.", result)
else
LrDialogs.message("Error", "API issue")
end
end
)
end
Above uploadFile method will automatically call the API and post form-data collection. Below code is for call uploadFile function which select all the images from catalog.
for p, photo in ipairs(LrApplication.activeCatalog()) do
uploadFile(assert(photo:getRawMetadata('path')));
end
Above code will help you out the selection of categlog with Adobe's LightRoom Plugin.
I wrote simple class to compress data. Here it is:
LZWCompressor = {}
function LZWCompressor.new()
local self = {}
self.mDictionary = {}
self.mDictionaryLen = 0
-- ...
self.Encode = function(sInput)
self:InitDictionary(true)
local s = ""
local ch = ""
local len = string.len(sInput)
local result = {}
local dic = self.mDictionary
local temp = 0
for i = 1, len do
ch = string.sub(sInput, i, i)
temp = s..ch
if dic[temp] then
s = temp
else
result[#result + 1] = dic[s]
self.mDictionaryLen = self.mDictionaryLen + 1
dic[temp] = self.mDictionaryLen
s = ch
end
end
result[#result + 1] = dic[s]
return result
end
-- ...
return self
end
And i run it by:
local compressor = LZWCompression.new()
local encodedData = compressor:Encode("I like LZW, but it doesnt want to compress this text.")
print("Input length:",string.len(originalString))
print("Output length:",#encodedData)
local decodedString = compressor:Decode(encodedData)
print(decodedString)
print(originalString == decodedString)
But when i finally run it by lua, it shows that interpreter expected string, not Table. That was strange thing, because I pass argument of type string. To test Lua's logs, i wrote at beggining of function:
print(typeof(sInput))
I got output "Table" and lua's error. So how to fix it? Why lua displays that string (That i have passed) is a table? I use Lua 5.3.
Issue is in definition of method Encode(), and most likely Decode() has same problem.
You create Encode() method using dot syntax: self.Encode = function(sInput),
but then you're calling it with colon syntax: compressor:Encode(data)
When you call Encode() with colon syntax, its first implicit argument will be compressor itself (table from your error), not the data.
To fix it, declare Encode() method with colon syntax: function self:Encode(sInput), or add 'self' as first argument explicitly self.Encode = function(self, sInput)
The code you provided should not run at all.
You define function LZWCompressor.new() but call CLZWCompression.new()
Inside Encode you call self:InitDictionary(true) which has not been defined.
Maybe you did not paste all relevant code here.
The reason for the error you get though is that you call compressor:Encode(sInput) which is equivalent to compressor.Encode(self, sInput). (syntactic sugar) As function parameters are not passed by name but by their position sInput inside Encode is now compressor, not your string.
Your first argument (which happens to be self, a table) is then passed to string.len which expects a string.
So you acutally call string.len(compressor) which of course results in an error.
Please make sure you know how to call and define functions and how to use self properly!
This function is fine, but it doesn't do what I would like it to, but I hav eused it to make sure the use of objects is OK:
let getStreamData_ok (uri:string) =
let request = WebRequest.Create uri
use response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
while not reader.EndOfStream do
ignore <| reader.ReadLine()
I would like to connect to a stream and pull the file down one line at a time, on demand. This function doesn't work, I have tried shifting various lines in and out of the sequence expression without any success:
let getStreamData_OnDemand (uri:string) =
let request = WebRequest.Create uri
use response = request.GetResponse()
seq {
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
while not reader.EndOfStream do
yield reader.ReadLine()
}
Usage code:
let lines = getStreamData_OnDemand("http://stackoverflow.com/")
for line in lines do
ignore line
Thank you
This should work:
let getStreamData_OnDemand (uri:string) = seq {
let request = WebRequest.Create uri
use response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
while not reader.EndOfStream do
yield reader.ReadLine() }
The key difference compared to your second code snippet (the one that uses sequence expressions) is that everything is done inside a sequence expression. Most importantly, the use response = ... line is also enclosed in the sequence expression.
This is essential, because use in this case means that the response will be disposed only after the iteration over the sequence is completed. In your second code snippet, you would dispose response before anything is read from the returned sequence.
In your original snippet, it is disposed after getStreamData_OnDemand returns, but that's before you even started iterating over the sequence - so when you start iterating over the sequence, it is already disposed!
I am developing application in flex 3 which interacts with the Google feeds to produce my results. The URL to which i want to send request is something like this
http://books.google.com/books/feeds/volumes?q=football+-soccer&start-index=11&max-results=10
Now i can send and receive results with q parameter, but in the next two parameters has a '-' (start-index and max-results). I am using HTTPService to send the requeset like this.
SearchService.url = "http://books.google.com/books/feeds/volumes";
SearchService.method = "GET";
SearchService.contentType = "application/x-www-form-urlencoded"
Here SearchService is the HTTPService
var params:Object = new Object();
params.q = searchText;
params.start-index = 11;
params.max-results = 100;
service.SearchService.send(params);
Now my flex IDE throws me a error stating 'Cannot assign a non-reference value'. Only if i send the request with this parameters, i could put pagination in my application. So how can i send HTTPService request with '-' in the URL parameters?
You can do:
var params:Object = new Object();
params["q"] = searchText;
params["start-index"] = 11;
params["max-results"] = 100;
service.SearchService.send(params);
Validated and tested to work properly! :)