The HTTPD library is optional. In order to use this library, you must require it in one of your source files (preferably main.lua) prior to use. It only needs to be required once in a single file. It is recommended you do this at the top of your main.lua file, outside of any functions or other code, and you may do this by using this code:
@code() require 'httpd/httpd'; @endcodeCreates a new HTTPD server object. If 'config' is not given, defaults are assumed. By passing in a config, you may control the IP to listen to, port to listen on, and which directories to look in for supporting objects (controllers, views, assets, etc.).
As soon as the object is created, it will begin to listen for any web traffic, however, you must also be sure to pass event data back to your HTTPD instance. See Httpd:handleEvent() for more information.
@code() require 'httpd/httpd'; httpd = Httpd(); @endcode @code() httpd = Httpd({ ip = '0.0.0.0', -- The IP to bind to; use 0.0.0.0 to accept any connection; default 127.0.0.1 port = 80, -- The port to bind to; default 8080 controllerDir = './Controllers/', -- Folder to look for controller objects; default /Controllers/ viewDir = './Views/', -- Folder to look for view files & templates; default /Views/ staticDir = './Static/', -- Folder to look for static files (images, css, javascript, etc.); default /Static/ )}; @endcodePasses an event off to be handled by the Httpd. Returns
If you do not use this function to pass off event data to a created Httpd, then it will not be able to function properly as all incoming socket data is handled this way. This will cause your web server to be unresponsive, so remember to call it!.
@code() function macro.event(e, ...) if( not httpd:handleEvent(e, ...) ) then -- Wasn't handled by the HTTPD, so we might need to handle it some other way end end @endcodeWhen initiated, the Httpd expects to be able to load a routes.lua file which is located in the same directory as your calling script(probably main.lua). This routes file should contain calls to the Route object; this object is instantiated for you automatically when you load the HTTPD library. In this file, you will tell the Route object to mount various Controllers to URIs via the Route:controller() function.
This function maps the first URI segment of a URL to a specific controller, which must be the exact name of the controller class. For example:
@code() Route:controller('/', 'HomeController'); -- This is a special URI; this is your base page, as if you accessed http://127.0.0.1:8080 (assuming default config) Route:controller('home', 'HomeController'); -- Just like above, but the home controller is now accessible via / OR /home Route:controller('test', 'TestController'); -- Just some other controller for an example @endcodeControllers are where the processing for your routes happens; they handle the request the user provided and
will be responsible for returning the result. Methods for each accepted URI should be prefixed with either
A Request object will be passed to the routed method; this can be used to handle any GET/POST parameters.
A Controller should also return the rendered result. You may directly return the HTML as a Response but it is recommended to render a view with View:make().
@code() HomeController = class.new(); -- This handles any request to get the page at http://127.0.0.1:8080 function HomeController:getIndex(request) local dashboardData = getDashboardData(); -- Pretend getDashboardData() grabs some data we want to display return View:make('home', dashboardData); -- Render the page and return it to the user end -- If we instead tried to POST data to http://127.0.0.1:8080, it gets routed here instead function HomeController:postIndex(request) local searchString = request:input('search'); local searchResults = getSearchResults(searchString); -- Pretend this does some actual searching return View:make('search', searchResults); end @endcodeReturns an input from either POST-ed variables or GET variables with a field that matches the
'inputName'. For example, http://127.0.0.1:8080?searchString=blah is a GET request that will have
a Request with 'searchString' = "blah." The type returned will be either a
If you are expecting to receive a file, use Request:file() instead.
@code() -- For accepting a request over GET method function SearchController:getSearch(request) local searchString = request:input('searchString'); end -- For accepting a request over POST method function SearchController:postSearch(request) local searchString = request:input('searchString'); end @endcodeLike Request:input(), except it will return a file. The file will
be returned as a
Like Request:input(), except geared towards "old" input after a validation failure. This is useful for re-populating a form in your View after submission.
If the given field has no input, then it will return 'default' (which defaults to '') instead.
@code() <input type="text" name="searchString" value="{{ request:oldInput('searchString') }}" placeholder="Search for..." />@endcodeReturns all inputs (GET and POST) as a
Returns the value of a set cookie specified by 'name'.
@code() function UserControlPanelController:getIndex(request) local loginCookie = request:getCookie('login'); -- We might store our login as a cookie and need to validate it here end @endcodeReturns the URI segment at a given index, or the specified default if it does not exist.
A URI segment refers to strings, separated by a '/', in the URI section of a URL. For example, http://127.0.0.1:8080/home/index/segment3/segment4/segmentn?notasegment=1 represents a full URL where the segment at index 1 (which typically represents the controller) is 'home', index 2 (which typically represents the method/action) is 'index', index 3 is 'segment3', and so on.
@code() -- http://127.0.0.1:8080/home/index/whatever would be routed here function HomeController:getIndex(request) local something = request:uriSegment(3); -- 'something' should now be assigned 'whatever' end @endcodeReturns all validation errors, as a string, separated by
The HTTPD library makes use ov Views to separate logic (which should go into controllers) from page displays. Views use a Blade-like templating engine. Your Views will be HTML snippets (with some extra syntax and control structures), that end with the ".view.lua" extension.
A template is a special View that other views may choose to extend upon using the @extend directive. A very simplistic template might look something like this:
@code() <!DOCTYPE html> <html lang="en"> <head> </head> <body> @@section('content') </body> </html>@endcodeOnce you have a template (which is optional, but highly recommended), any other View can extend it by injecting content into its sections.
@code() @extends('template') @beginsection('content') Hello World! @endsection@endcodeFully takes care of rendering a view for you and returns the result as a
You should specify the view to render ('viewName') without the "view.lua" extension. You may optionally pass additional variables that will be available to the view as a table of key/value pairs.
@code() function TestController:getIndex(request) local data = { name = Bob, age = 8, }; return View:make('test', data); end @endcode @code() <html> <body> <h1>Test</h1> Hello, my name is {{ name }} and I am {{ age }} years old. </body> </html>@endcode"Extend" a view by using it as a template. Any sections in this view will be inserted into the proper place in the template.
See Templates for more information.
Creates a placeholder (in a template) that can be overriden by another view.
See Templates and @beginsection for more info.
Creates a section that can be placed into the template; if it has a @section() with a matching name, this section will override its content.
The section will continue until it reaches a paired @endsection directive.
@code() @beginsection('mySection') Everything in here will go into the 'mySection' section. @endsection @endcodeThe @include directive can be used to include sub-views into the calling view. This can be useful for partial segments that you might want to reuse on multiple pages (such as some sort of user panel, a form, etc.), or just to further separate code and make things easier for you to work with.
Like with any view, you do not need to include the ".view.lua" suffix.
@code() @extends('template') @beginsection('content') <div class="panel"> @include('panel') </div> @endsection@endcodeThe @foreach directive allows you to iterate over a table of items. Essentially, it's a for-loop
You should pass this directive 3 items in a special format: tableName as indexName,valueName. 'tableName' is of course the table to iterate over while 'indexName' and 'valueName' are the name of the variables to use for the key/value of each iteration.
@code() <table> <tr> <td>Key</td><td>Value</td> </tr> <tr> @foreach(dataTable as index,value) { <td>{{ index }}</td><td>{{ value }}</td> } </tr> </table>@endcodeLike @foreach except it iterates from 'startCount' to 'endCount'. For example, for(count = 1, 10) would iterate 10 times, with 'count' incrementing from 1 to 10.
@code() @for(count = 1, totalCount) { {{ count }}<br /> }@endcodeA standard if statement, to conditionally show content. Optionally you may also have an else statement.
@code() @if(someVariable) { <p>The statement was true</p> } else { <p>The statement was false</p> } @if( 10 > 5 ) { <p>Pretty sure 10 is greater than 5</p> }@endcodeDouble curly braces can be used to output some dynamic content into the view. It will also automatically escape HTML entities. Any Lua code or variables can be placed in the braces.
The {{! statement !}} variation can be used to not escape HTML entities. Use this if you are trying to output a string that might contain data you want to actually be rendered as HTML.
The {{# statement #}} variation can be used to run a statement without displaying any of its output.
@code() <p>Display a string: {{ someString }}</p> <p>{{ if(true) then return 'This statement is true!'; else return 'This statement is false!' end }}</p> <p>Display raw string: {{! "Contains <b>HTML</b>" !}} <br /> Would actually display the text "Contains HTML"; HTML would be bold.</p> <p>Run w/ no display: {{# count = count + 1 #}}</p>@endcodeControllers are expected to return a Response object; View:make() renders the view and returns it as a Response for you. In this context, a Response is simply an object that pairs an HTTP status code to an HTML string which should be sent to the requesting client.
You may opt to create a Response rather than rely on View:make() if you want more control over the status code or just to return a simple HTML message. For example, you might want to show a custom error message.
@code() -- Route for http://127.0.0.1:8080/store/item/xxxx where xxxx is the name of an item to get info on function StoreController:getItem(request) local itemname = request:uriSegment(3, nil); -- If an itemname wasn't specified or if we couldn't find it in the itemtable, show an error if( not itemname or not itemtable[itemname] ) then return Response(404, "<h1>Not Found</h1><p>Sorry, we couldn't find the item for you :(</p>"); end local data = { item = itemtable[itemname], }; return View:make('item_details.view.lua', data); end @endcodePage last updated at 2018-10-08 19:30:49