Webscript Documentation
Getting Started
Webscript's Lua environment includes library functions for accessing commonly needed facilities like HTTP routines and persistent storage. In addition, it presents a convenient convention for returning script results to an HTTP request.
Scripts are written in Lua version 5.1.5. If you are new to Lua, we recommend first reading our Lua tutorial: Lua in Relatively Few Words
Script Structure
Webscripts are a sequence of executable Lua statements, implicitly wrapped in a function, and ending with a return statement. There is no "main” function—execution begins with the first statement and proceeds on.
Values Passed to the Script
Webscript passes a global table to your script called request
. This parameter contains the originating HTTP request with the following fields:
form
– A table consisting of form data posted to your script. This field is only present if the request has aContent-Type
ofmultipart/form-data
orapplication/x-www-form-urlencode
and the body is successfully parsed as form-encoded.query
– A table consisting of query string parameters from the request's URL. For example, the query string?color=red&number;=3
will result in aquery
table of{color="red", number="3"}
.querystring
– The raw query string from the URL. Using the previous example, thequerystring
value would be"color=red&number;=3"
.files
– A table consisting of files included in a form post. For each included file, the key is the name of the form's input field, and the value is a table consisting oftype
(the content-type of the uploaded file),filename
(original file name), andcontent
(the raw contents of the file).body
– The content of the request, after it's been decoded as needed (e.g. decompressed as specified by aContent-Encoding
header).method
– The HTTP request method. (E.g.,GET
,POST
, ...)remote_addr
– The request's origin IP address.scheme
– The URL scheme. (E.g.,http
orhttps
.)port
– The URL's port. (E.g.,80
or443
.)path
– The URL's path. (E.g., for the URLhttp://example.webscript.io/foo/bar
, the path is/foo/bar
.)headers
– A table of the HTTP request headers. Keys are "train-cased," likeContent-Type
.
Note: To support Internet Explorer's cross-domain requests using XDomainRequest
, if a request has no Content-Type
header, an attempt is still made to parse it as application/x-www-form-urlencode
.
Return Values
Webscript interprets the return value of a script as a response to the HTTP request. A script may return zero or more return values, which are interpreted as follows:
- Return a string to set the body of the response. Note that Lua strings can contain arbitrary binary data.
- Return an integer to set the status code.
- Return a table to send JSON or set the response headers:
- If no string is returned, the first table returned is sent as JSON, with a
Content-Type
header ofapplication/json
. - Any other table is interpreted as HTTP response headers.
- If no string is returned, the first table returned is sent as JSON, with a
The default status code is 200
, and the default Content-Type
is text/plain
.
A few examples:
return "Success!"
return 200
return 403, "Not allowed."
return "<h1>Hello, World!</h1>", {["Content-Type"]="text/html"}
return {color="red", number=3}
return {color="red", number=3}, {["Cache-Control"]="no-cache"}
Persistent Storage
Webscript provides persistent storage—storage that exists between script invocations. The persistent storage is accessed via the storage
table.
Storage is scoped to a single subdomain (e.g., example.webscript.io
) but is shared amongst all scripts under that subdomain.
A simple storage example that remembers the last user to call the script:
storage.lastuser = request.form.username
That value could be accessed on subsequent calls to any script under the same subdomain as storage.lastuser
. All values in persistent storage are strings. Implicit casts are performed on assignment.
Accessing a non-existent storage key returns nil
, and assigning nil
to a key deletes that key.
Making Outbound HTTP Requests
Scripts can easily make outgoing HTTP requests by calling the built-in http.request
function. This function takes one parameter, a table with the following fields:
url
– The target URL, including scheme, e.g.http://example.com
method
(optional, default is "GET") – The HTTP verb, e.g.GET
orPOST
data
(optional) – Either a string (the raw bytes of the request body) or a table (converted to form POST parameters)params
(optional) – A table that's converted into query string parameters. E.g.{color="red"}
becomes?color=red
auth
(optional) – Two possibilities:auth={'username', 'password'}
means to use HTTP basic authenticationauth={oauth={consumertoken='...', consumersecret='...', accesstoken='...', tokensecret='...'}}
means to sign the request with OAuth. Onlyconsumertoken
andconsumersecret
are required (e.g. for obtaining a request token)
headers
(optional) – A table of the request header key/value pairs
A call to http.request
returns a table with the following fields:
content
– The raw bytes of the HTTP response body, after being decoded if necessary according to the response'sContent-Encoding
header.statuscode
– The numeric status code of the HTTP responseheaders – A table of the response's headers
The function http.qsencode
can be used to convert a table of key/value pairs into a query string. This function is rarely needed because the params
field can be used to the same effect when making an HTTP request.
The function http.qsparse
can be used to convert a query string into a table of key/value pairs. This function is rarely needed because request.query
already contains the parsed query string for an incoming request.
Sending Email
Scripts can send email using the email.send
function. This function takes one parameter, a table with the following fields:
server
– The SMTP server's full domainusername
– The SMTP usernamepassword
– The SMTP passwordfrom
– The sender's email addressto
– The recipient's email address. Multiple recipients can be specified with a table, e.g.{'[email protected]', '[email protected]'}
.subject
– The subject of the emailtext
(optional) – The email body in text format. At least one oftext
andhtml
must be specified.html
(optional) – The email body in HTML format. At least one oftext
andhtml
must be specified.attachments
(optional) – Any file attachments to be included with the email. See below for details about this parameter.replyto
(optional) – The reply-to address. Note that not all email providers will respect this field.secure
(optional, defaults to true) – Whether or not to use TLS to connect to the SMTP server
The attachments
field, if present, should be an array-style table, where each member is itself a table with the following fields:
filename
– The name of the attachment.content
– The contents of the attachment (a Lua string).type
(optional) – The content type for the attachment (e.g.image/jpeg
). The default isapplication/octet-stream
.
Example: attachments = { { filename = 'hello.txt', content = 'Hello, World!', type = 'text/plain' }, ... }
Generating and Parsing JSON
Webscript includes two JSON functions:
json.parse(str)
– Convert a JSON-encoded string into a Lua table.json.stringify(T)
– Convert a Lua table into a JSON-encoded string.
Cryptographic Functions
Webscript includes the following basic cryptography functions:
crypto.bcrypt.hash(str)
orcrypto.bcrypt.hash { password=str, rounds=n }
– Hash a password using the bcrypt algorithm. The default number of rounds is 12.crypto.md5(str).digest()
orcrypto.md5(str).hexdigest()
– Hash a string using the MD5 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.crypto.sha1(str).digest()
orcrypto.md5(str).hexdigest()
– Hash a string using the SHA1 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.crypto.sha256(str).digest()
orcrypto.md5(str).hexdigest()
– Hash a string using the SHA256 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.crypto.hmac(key, str, hasher).digest()
orcrypto.hmac(key, str, hasher).hexdigest()
– Create an HMAC signature using the specified hasher (crypto.md5
,crypto.sha1
, orcrypto.sha256
) and return the raw or hexadecimal-encoded HMAC.
Base64 Encoding
Webscript supports base64 encoding with the following functions:
base64.encode(str)
– Produce the base64 encoding of the stringstr
. Note that Lua strings can contain arbitrary binary data.base64.decode(str)
– Produce the string represented by the base64-encoded stringstr
.
Leases
Webscript provides leases to enable scripts to ensure exclusive access to resources. The following functions are defined:
lease.acquire(str)
– Acquire the lease namedstr
. This call blocks until the lease becomes available and is acquired.lease.release(str)
– Release the lease namedstr
.
Leases are scoped to a subdomain. All acquired leases are released when a script terminates.
Logging
Webscript maintains per-script logs. Scripts can write to the log using the log function:
log(str)
Alerts
Scripts can send alerts to their owner by email or by SMS. Email alerts are sent from subdomain@script-alerts.webscript.io (using the subdomain of the script that sent the alert) and go to the email address of the Webscript user account. SMS messages are sent from the number +1 (425) 296-8394 and go to the phone number a user has verified on the settings page.
Note that alerts are only available for paid accounts and are limited to 1,000 email alerts and 100 SMS alerts per calendar month.
Alerts can be sent with the following functions:
alert.sms(str)
alert.email(str)
alert.email(table)
– takes thesubject
,text
,html
, andattachments
parameters as in email.send.
Including Modules From GitHub
To make a public GitHub repository available to webscripts, the repository owner must add https://www.webscript.io/github-hook
as a post-receive webhook for the repository. (See https://help.github.com/articles/post-receive-hooks for GitHub webhook details.)
To import code from GitHub, use the require function:
<variable> = require('<github user>/<repository>/<filename.lua>')
For examples of how modules should work, see https://github.com/webscriptio/lib for the modules maintained by the Webscript team. These modules can be required without a full path. (E.g. local twilio = require 'twilio'
.)
API Beta
Webscript supports a simple HTTP-based API for reading and writing scripts. The API is currently in beta with the version number 0.1 and is subject to change.
Authentication
All access to the Webscript API uses HTTPS with basic authentication. The username should be the email address with which the user logs in to Webscript. The password should be the user's API key, which can be seen on the settings page.
Operations
All operations return responses in JSON format. The base URL for all operations is https://www.webscript.io/api/0.1
.
Operation | HTTP Verb | URL | Description |
---|---|---|---|
List subdomains | GET | /api/0.1/subdomains | Returns a dictionary of subdomains. Example response:
{ "demo-krbnjo": { "expired": false, "expiration": "2012-12-07T20:51:32.479276", "scripts": [ "/script" ] } } |
Get subdomain | GET | /api/0.1/subdomain/<subdomain>
(e.g. /api/0.1/subdomain/examples) |
Returns the details of a single subdomain. Example response:
{ "expired": false, "expiration": "2012-12-07T20:51:32.479276", "scripts": [ "/script" ] } |
Get script | GET | /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email) |
Returns the code from a single script. |
Save script | PUT or POST | /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email) |
Create or overwrite a script with new code. The code should be contained in the body of the HTTP request. |
Delete script | DELETE | /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email) |
Delete a script. |
Delete subdomain | DELETE | /api/0.1/subdomain/<subdomain>
(e.g. /api/0.1/subdomain/examples) |
Delete an entire subdomain. |
Get request logs | GET | /api/0.1/logs/<subdomain>/<path>
(e.g. /api/0.1/logs/examples/hello) |
Retrieve a script's 20 most recent log entries in reverse chronological order as a JSON array. Each element of the array will be a hash containing timestamp , request , messages , and response members. Example response:[ { "timestamp": "2012-12-05T16:42:27.656081+00:00", "request": { "url": "examples.webscript.io/hello", "headers": { "X-Forwarded-Port": "80", "X-Forwarded-For": "71.197.165.147", "Connection": "close", "Accept": "*/*", "User-Agent": "curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5", "Host": "examples.webscript.io", "X-Forwarded-Proto": "http" }, "method": "GET" }, "messages": ["This is a log message."], "response": { "body": "Hello, World!", "status_code": 200, "headers": { "Content-Length": 13, "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*", "Cache-Control": "no-store" } } }, ... ] |