Access REST API via lua script - api

Is there way to access rest api with pure lua script
GET / POST both way need to access and display response
i already tried
local api = nil
local function iniit()
if api == nil then
-- body
api = require("http://api.com")
.create()
.on_get(function ()
return {name = "Apple",
id = 12345}
end)
end
end

In linux , mac we can easily install luarocks , and then we can install curl package. It's easiest way to unix like os.
-- HTTP Get
local curl = require('curl')
curl.easy{
url = 'api.xyz.net?a=data',
httpheader = {
"X-Test-Header1: Header-Data1",
"X-Test-Header2: Header-Data2",
},
writefunction = io.stderr -- use io.stderr:write()
}
:perform()
:close()
In windows i faced several problems. Cant install luarocks correctly. then luarock install command not work correctl, etc..
In first dwnload lua from official site, and then create structure like (below web site)
http://fuchen.github.io/dev/2013/08/24/install-luarocks-on-windows/
then i download lua luadist
http://luadist.org/
then i got same structure luadist extracted folder and lua folder.
merged luadist folder and lua folder
Finaly we can use http.soket
local http=require("socket.http");
local request_body = [[login=user&password=123]]
local response_body = {}
local res, code, response_headers = http.request{
url = "api.xyz.net?a=data",
method = "GET",
headers =
{
["Content-Type"] = "application/x-www-form-urlencoded";
["Content-Length"] = #request_body;
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(response_body),
}
print(res)
print(code)
if type(response_headers) == "table" then
for k, v in pairs(response_headers) do
print(k, v)
end
end
print("Response body:")
if type(response_body) == "table" then
print(table.concat(response_body))
else
print("Not a table:", type(response_body))
end
IF YOU DO THESE STEPS CORRECTLY , THIS WILL BE WORK 1000% SURE

Related

Sonatype Nexus search api does not return all the artifacts

We use sonatype nexus OSS 3.14.0-04 to store all our artifacts and we use Jenkins as our CI/CD took. I introduced snapshot support recently. From Jenkins I use the below groovy script to fetch all artifact versions and populate an Active choice drop-down:
#!/usr/bin/env groovy
import groovy.json.JsonSlurper
def source = "release"
def url = "http://<<nexus-host>>/service/rest/v1/search?repository=maven-releases&maven.groupId=com.xyz&maven.artifactId=woof&maven.extension=war"
Set<String> versions = new HashSet<>();
def continuationToken = null
def count = 0
def url1 = url
while (true) {
def xml = url1.toURL().text
JsonSlurper parser = new groovy.json.JsonSlurper()
Map parsedJson = parser.parseText(xml)
def rawVer = parsedJson.items.version
continuationToken = parsedJson.continuationToken
if (continuationToken != null) {
url1 = url + "&continuationToken=" + continuationToken
}
if (source.equalsIgnoreCase('snapshot')) {
Set<String> modVersion = new HashSet<>()
for (def item : rawVer) {
modVersion.add(item.split("-").getAt(0) + "-SNAPSHOT")
}
versions.addAll(modVersion)
} else {
versions.addAll(rawVer)
}
if (continuationToken == null || count > 5) {
break;
}
}
return versions.sort().reverse()
The nexus api search endpoint uses a pagination strategy to return the result. If the global result contains several pages, the current result will contain a continuationToken you can use in your next query to fetch the next result page.
If your search returns more results than the page size, you will need to make several calls to the search url to get all the results in your Jenkins script (i.e. until continuationToken is null).
Ref: Nexus Search API endpoint doc (also referenced in your swagger-ui api view in your nexus admin)

scrapy-splash response.body contains no html

Im trying to use crawlera alongside splash local instance, this is my lua script
function main(splash)
function use_crawlera(splash)
local user = splash.args.crawlera_user
local host = 'proxy.crawlera.com'
local port = 8010
local session_header = 'X-Crawlera-Session'
local session_id = 'create'
splash:on_request(function(request)
request:set_header('X-Crawlera-Cookies', 'disable')
request:set_header(session_header, session_id)
request:set_proxy { host, port, username = user, password = '' }
end)
splash:on_response_headers(function(response)
if type(response.headers[session_header]) ~= nil then
session_id = response.headers[session_header]
end
end)
end
function main(splash)
use_crawlera(splash)
splash:go(splash.args.url)
splash:wait(30)
return splash:html()
end
end
and this is my start_request
yield SplashRequest(index_url,
self.parse_kawanlama_index,
endpoint='execute',
args={
'lua_source': lua_script,
'wait' : 5,
'html' : 1,
'url': index_url,
'timeout': 10,
'crawlera_user':self.crawlera_apikey
},
# tell Splash to cache the lua script, to avoid sending it for every request
cache_args=['lua_source'],
)
but it doesnt seems to work because response.body that i got in self.parse(response) is contains no html.

Unable to branch my tests using a variable in Postman

I have a collection with two folders, one for POSTs and one for GETs
At the collection level, I have set variables
And the following collection-level scripts to be run after every request:
requestLast = pm.variables.get("requestLast");
requestCurrent = pm.variables.get("requestCurrent");
statusGet = pm.variables.get("statusGet");
requestLast = requestCurrent;
requestCurrent = pm.request.name;
I want to always be keeping track of the previously run request, so I can return to it when necessary.
In the 'positivePosts' folder I have the following test script:
if(statusGet === 0) {
postman.setNextRequest("resultsPositive");
}
else {
statusGet = 0;
}
pm.variables.set("requestLast", requestLast);
pm.variables.set("requestCurrent", requestCurrent);
pm.variables.set("statusGet", statusGet);
The individual POST requests have no test scripts.
The results folder does not have any tests, but the resultsPositive GET has this test script:
var jsonData = JSON.parse(responseBody);
schema = pm.variables.get("schemaPositive");
tests["Valid Schema"] = tv4.validate(jsonData, schema);
tests["Status code is 200"] = responseCode.code === 200;
statusGet = 1;
postman.setNextRequest(requestLast);
pm.variables.set("requestLast", requestLast);
pm.variables.set("requestCurrent", requestCurrent);
pm.variables.set("statusGet", statusGet);
There are no pre-request scripts anywhere in the collection.
When running the collection, I would expect this order:
postRich
resultsPositive
postAllProperties
resultsPositive
postMinimum
resultsPositive
However, what I actually see is:
postRich
postAllProperties
postPositive
I also don't understand why postPositive is not run after postRich.

Kong plugin do not run access block

I'm developing a plugin to Kong API Gateway. I created a service pointing it to another service in the local network and basically every request to my service is redirected to the other one, so far so good.
What the plugin has to do is grab the field Authorization Bearer in the header, and pass to the upstream service as part of the URI. E.g.
Request is received on:
localhost/service
In its header, it have a Authorization Bearer that contains a JWT
The plugin has to receive it, take the JWT and parse it to URI to the upstream service:
productionServer/service/9a8udoadzlkndid813gru1gr <-JWT took from header
My attempt till now:
local singletons = require "kong.singletons"
local BasePlugin = require "kong.plugins.base_plugin"
local responses = require "kong.tools.responses"
local constants = require "kong.constants"
local multipart = require "multipart"
local cjson = require "cjson"
local url = require "socket.url"
local access = require "kong.plugins.ctk.access"
local CtkHandler = BasePlugin:extend()
CtkHandler.PRIORITY = 3505
CtkHandler.VERSION = "0.1.0"
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- JUST EXTENDED THE BASE PLUGIN ---")
function CtkHandler:new()
CtkHandler.super.new(self, "ctk")
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- INSTACIATED ITSELF ---")
end
function CtkHandler:access(conf)
CtkHandler.super.access(self)
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- STARTED THE ACCESS PART ---")
do_authentication()
access.execute(conf)
end
file:close()
return CtkHandler
The idea, is that after every request, the access block at the end be executed, then, he will redirect to my access file
local singletons = require "kong.singletons"
local BasePlugin = require "kong.plugins.base_plugin"
local responses = require "kong.tools.responses"
local constants = require "kong.constants"
local multipart = require "multipart"
local cjson = require "cjson"
local url = require "socket.url"
local basic_serializer = require "kong.plugins.log-serializers.basic"
local string_format = string.format
local ngx_set_header = ngx.req.set_header
local get_method = ngx.req.get_method
local req_set_uri_args = ngx.req.set_uri_args
local req_get_uri_args = ngx.req.get_uri_args
local req_set_header = ngx.req.set_header
local req_get_headers = ngx.req.get_headers
local req_clear_header = ngx.req.clear_header
local req_set_method = ngx.req.set_method
local ngx_decode_args = ngx.decode_args
local ngx_re_gmatch = ngx.re.gmatch
local string_format = string.format
local cjson_encode = cjson.encode
local ipairs = ipairs
local request = ngx.request
local function retrieve_token(request, conf)
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- RUNNING RETRIEVE TOKEN ---")
local uri_parameters = request.get_uri_args()
for _, v in ipairs(conf.uri_param_names) do
if uri_parameters[v] then
return uri_parameters[v]
end
end
local ngx_var = ngx.var
for _, v in ipairs(conf.cookie_names) do
local jwt_cookie = ngx_var["cookie_" .. v]
if jwt_cookie and jwt_cookie ~= "" then
return jwt_cookie
end
end
local authorization_header = request.get_headers()["authorization"]
if authorization_header then
local iterator, iter_err = ngx_re_gmatch(authorization_header, "\\s*[Bb]earer\\s+(.+)")
if not iterator then
return nil, iter_err
end
local m, err = iterator()
if err then
return nil, err
end
if m and #m > 0 then
return m[1]
end
end
end
local function do_authentication(conf)
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- RUNNING DO_AUTHENTICATION ---")
local token, err = retrieve_token(ngx.req, conf)
if err then
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
end
local ttype = type(token)
if ttype ~= "string" then
if ttype == "nil" then
return false, {status = 401}
elseif ttype == "table" then
return false, {status = 401, message = "Multiple tokens provided"}
else
return false, {status = 401, message = "Unrecognizable token"}
end
append_uri(token)
return true
end
end
local function append_uri(token)
file = io.open("/usr/local/kong/logs/ctk.lua", "a+")
io.input(file)
file:write("--- FUNCTION APPEND_URL ---")
local uri = ngx.get_uri_args
ngx.req.set_uri(ngx.unescape_uri("/" .. token))
end
In the Kong server, after installing the plugin above, I receive:
--- JUST EXTENDED THE BASE PLUGIN ------ INSTACIATED ITSELF ---
Which is the control inserted inside the code to trace it.
Any ideas?
Actually using io.write isn't recommended, so what i had to do was change it to:
ngx.log(ngx.WARN, "SOME MESSAGE")
After that, the block code access ran just fine.
There's a Kong plugin that can perform the OAuth 2.0 token validation, see: kong-oidc. You may want to deploy that.

Advice needed on setting up an (Objective C?) Mac-based web service

I have developed numerous iOS apps over the years so know Objective C reasonably well.
I'd like to build my first web service to offload some of the most processor intensive functions.
I'm leaning towards using my Mac as the server, which comes with Apache. I have configured this and it appears to be working as it should (I can type the Mac's IP address and receive a confirmation).
Now I'm trying to decide on how to build the server-side web service, which is totally new to me. I'd like to leverage my Objective C knowledge if possible. I think I'm looking for an Objective C-compatible web service engine and some examples how to connect it to browsers and mobile interfaces. I was leaning towards using Amazon's SimpleDB as the database.
BTW: I see Apple have Lion Server, but I cannot work out if this is an option.
Any thoughts/recommendations are appreciated.?
There are examples of simple web servers out there written in ObjC such as this and this.
That said, there are probably "better" ways of doing this if you don't mind using other technologies. This is a matter of preference; but I've use Python, MySQL, and the excellent web.py framework for these sorts of backends.
For example, here's an example web service (some redundancies omitted...) using the combination of technologies described. I just run this on my server, and it takes care of url redirection and serves JSON from the db.
import web
import json
import MySQLdb
urls = (
"/equip/gruppo", "gruppo", # GET = get all gruppos, # POST = save gruppo
"/equip/frame", "frame"
)
class StatusCode:
(Success,SuccessNoRows,FailConnect,FailQuery,FailMissingParam,FailOther) = range(6);
# top-level class that handles db interaction
class APIObject:
def __init__(self):
self.object_dict = {} # top-level dictionary to be turned into JSON
self.rows = []
self.cursor = ""
self.conn = ""
def dbConnect(self):
try:
self.conn = MySQLdb.connect( host = 'localhost', user = 'my_api_user', passwd = 'api_user_pw', db = 'my_db')
self.cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)
except:
self.object_dict['api_status'] = StatusCode.FailConnect
return False
else:
return True
def queryExecute(self,query):
try:
self.cursor.execute(query)
self.rows = self.cursor.fetchall()
except:
self.object_dict['api_status'] = StatusCode.FailQuery
return False
else:
return True
class gruppo(APIObject):
def GET(self):
web.header('Content-Type', 'application/json')
if self.dbConnect() == False:
return json.dumps(self.object_dict,sort_keys=True, indent=4)
else:
if self.queryExecute("SELECT * FROM gruppos") == False:
return json.dumps(self.object_dict,sort_keys=True, indent=4)
else:
self.object_dict['api_status'] = StatusCode.SuccessNoRows if self.rows.count == 0 else StatusCode.Success
data_list = []
for row in self.rows:
# create a dictionary with the required elements
d = {}
d['id'] = row['id']
d['maker'] = row['maker_name']
d['type'] = row['type_name']
# append to the object list
data_list.append(d)
self.object_dict['data'] = data_list
# return to the client
return json.dumps(self.object_dict,sort_keys=True, indent=4)