Skip to content

Commit

Permalink
feat(router): add a router plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Tieske committed Dec 30, 2023
1 parent 1ac5fdb commit b3e1402
Show file tree
Hide file tree
Showing 6 changed files with 416 additions and 7 deletions.
70 changes: 70 additions & 0 deletions example/app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,73 @@ local Pegasus = require 'pegasus'
local Compress = require 'pegasus.plugins.compress'
local Downloads = require 'pegasus.plugins.downloads'
local Files = require 'pegasus.plugins.files'
local Router = require 'pegasus.plugins.router'
local json = require 'pegasus.json'
-- local TLS = require 'pegasus.plugins.tls'


-- example data for the "router" plugin
local routes do
local testData = {
Jane = { firstName = "Jane", lastName = "Doe", age = 25 },
John = { firstName = "John", lastName = "Doe", age = 30 },
}

routes = {
-- router-level preFunction runs before the method prefunction and callback
preFunction = function(req, resp)
local stop = false
local headers = req:headers()
local accept = (headers.accept or "*/*"):lower()
if not accept:find("application/json", 1, true) and
not accept:find("application/*", 1, true) and
not accept:find("*/*", 1, true) then

resp:writeDefaultErrorMessage(406, "This API only produces 'application/json'")
stop = true
end
return stop
end,

["/people"] = {
GET = function(req, resp)
resp:statusCode(200)
resp:addHeader("Content-Type", "application/json")
resp:write(json.encode(testData))
end,
},

["/people/{name}"] = {
-- path-level preFunction runs before the actual method callback
preFunction = function(req, resp)
local stop = false
local name = req.pathParameters.name
if not testData[name] then
local err = ("'%s' is an unknown person"):format(name)
resp:writeDefaultErrorMessage(404, err)
stop = true
end
return stop
end,

-- callback per method
GET = function(req, resp)
resp:statusCode(200)
resp:addHeader("Content-Type", "application/json")
resp:write(json.encode(testData[req.pathParameters.name]))
end,

-- postFunction runs after the actual method callback
postFunction = function(req, resp)
local stop = false
print("served " .. req.pathParameters.name .. "'s data")
return stop
end,
}
}
end


local server = Pegasus:new({
port = '9090',
plugins = {
Expand All @@ -39,6 +104,11 @@ local server = Pegasus:new({
location = '/example/root/',
},

Router:new {
prefix = "/api/1v0/",
routes = routes,
},

Compress:new(),
}
})
Expand Down
91 changes: 86 additions & 5 deletions example/copas.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ local Handler = require 'pegasus.handler'
local copas = require('copas')
local socket = require('socket')
local Downloads = require 'pegasus.plugins.downloads'
local Files = require 'pegasus.plugins.files'
local Router = require 'pegasus.plugins.router'
local Compress = require 'pegasus.plugins.compress'
local json = require 'pegasus.json'


--- Creates a new server within the Copas scheduler.
-- @tparam table opts options table.
Expand All @@ -25,7 +30,6 @@ local Downloads = require 'pegasus.plugins.downloads'
-- @return the server-socket on success, or nil+err on failure
local function newPegasusServer(opts)
opts = opts or {}
assert(opts.location or opts.callback, "either 'location' or 'callback' must be provided")
assert(opts.port, "option 'port' must be provided")

local server_sock, err = socket.bind(opts.interface or '*', opts.port)
Expand All @@ -36,6 +40,10 @@ local function newPegasusServer(opts)
local server_ip, server_port = server_sock:getsockname()
if not server_ip then
return nil, "failed to get server socket name; "..tostring(server_port)
else
if server_ip == "0.0.0.0" then
server_ip = "localhost"
end
end

local hdlr = Handler:new(opts.callback, opts.location, opts.plugins)
Expand All @@ -49,6 +57,68 @@ local function newPegasusServer(opts)
end


-- example data for the "router" plugin
local routes do
local testData = {
Jane = { firstName = "Jane", lastName = "Doe", age = 25 },
John = { firstName = "John", lastName = "Doe", age = 30 },
}

routes = {
-- router-level preFunction runs before the method prefunction and callback
preFunction = function(req, resp)
local stop = false
local headers = req:headers()
local accept = (headers.accept or "*/*"):lower()
if not accept:find("application/json", 1, true) and
not accept:find("application/*", 1, true) and
not accept:find("*/*", 1, true) then

resp:writeDefaultErrorMessage(406, "This API only produces 'application/json'")
stop = true
end
return stop
end,

["/people"] = {
GET = function(req, resp)
resp:statusCode(200)
resp:addHeader("Content-Type", "application/json")
resp:write(json.encode(testData))
end,
},

["/people/{name}"] = {
-- path-level preFunction runs before the actual method callback
preFunction = function(req, resp)
local stop = false
local name = req.pathParameters.name
if not testData[name] then
local err = ("'%s' is an unknown person"):format(name)
resp:writeDefaultErrorMessage(404, err)
stop = true
end
return stop
end,

-- callback per method
GET = function(req, resp)
resp:statusCode(200)
resp:addHeader("Content-Type", "application/json")
resp:write(json.encode(testData[req.pathParameters.name]))
end,

-- postFunction runs after the actual method callback
postFunction = function(req, resp)
local stop = false
print("served " .. req.pathParameters.name .. "'s data")
return stop
end,
}
}
end



-- Create http server
assert(newPegasusServer{
Expand Down Expand Up @@ -80,14 +150,25 @@ assert(newPegasusServer{
},
sni = nil,
},
location = '/example/root/',
callback = nil,

plugins = {
Downloads:new {
prefix = "downloads",
location = '/example/root/',
prefix = 'downloads',
stripPrefix = true,
},
},

Files:new {
location = '/example/root/',
},

Router:new {
prefix = "/api/1v0/",
routes = routes,
},

Compress:new(),
}
})

-- Start
Expand Down
12 changes: 11 additions & 1 deletion example/root/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,15 @@
Age: <input type="text" name="age">
<input type="submit" value="send">
</form>
<p>Try the following API calls for the Router plugin:
<ul>
<li><a href="/api/1v0/people"><code>/api/1v0/people</code></a></li>
<li><a href="/api/1v0/people/John"><code>/api/1v0/people/John</code></a></li>
<li><a href="/api/1v0/people/Mary"><code>/api/1v0/people/Mary</code></a> (fails with 404, change to "Jane" to make it work)</li>
<li><code>curl -v -X POST http://localhost:9090/api/1v0/people/John</code> (a POST request, failing with 405)</li>
<li><code>curl -v -X GET -H "Accept: application/xml" http://localhost:9090/api/1v0/people/John</code> (failing with 406)</li>
</ul>
To see the router features in effect
</p>
</body>
</html>
</html>
1 change: 1 addition & 0 deletions rockspecs/pegasus-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ build = {
['pegasus.plugins.compress'] = 'src/pegasus/plugins/compress.lua',
['pegasus.plugins.downloads'] = 'src/pegasus/plugins/downloads.lua',
['pegasus.plugins.files'] = 'src/pegasus/plugins/files.lua',
['pegasus.plugins.router'] = 'src/pegasus/plugins/router.lua',
['pegasus.plugins.tls'] = 'src/pegasus/plugins/tls.lua',
}
}
Loading

0 comments on commit b3e1402

Please sign in to comment.