-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from pepe/docs
New documentation
- Loading branch information
Showing
3 changed files
with
174 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,156 @@ | ||
# circlet | ||
# Circlet | ||
|
||
Circlet is an HTTP and networking library for the [janet](https://github.com/janet-lang/janet) language. | ||
It provides an abstraction out of the box like Clojure's [ring](https://github.com/ring-clojure/ring), which | ||
is a server abstraction that makes it easy to build composable web applications. | ||
Circlet is an HTTP and networking library for the | ||
[janet](https://github.com/janet-lang/janet) language. | ||
It provides an abstraction out of the box like Clojure's | ||
[ring](https://github.com/ring-clojure/ring), which is a server abstraction | ||
that makes it easy to build composable web applications. | ||
|
||
Circlet uses [mongoose](https://cesanta.com/) as the underlying HTTP server engine. Mongoose | ||
is a portable, low footprint, event based server library. The flexible build system requirements | ||
of mongoose make it very easy to embed in other C programs and libraries. | ||
Circlet uses [mongoose](https://cesanta.com/) as the underlying HTTP server | ||
engine. Mongoose is a portable, low footprint, event based server library. The | ||
flexible build system requirements of mongoose make it very easy to embed | ||
in other C programs and libraries. | ||
|
||
## Building | ||
## Installing | ||
|
||
Building requires [janet](https://github.com/janet-lang/janet) to be installed on the system, as | ||
well as the `jpm` tool (installed by default with latest installs). | ||
You can add Circlet as a dependency in your `project.janet`: | ||
|
||
```sh | ||
jpm build | ||
```clojure | ||
(declare-project | ||
:name "web framework" :description "A framework for web development" | ||
:dependencies ["https://github.com/janet-lang/circlet.git"]) | ||
``` | ||
|
||
You can also just run `jpm` to see a list of possible build commands. | ||
You can also install it system-wide with `jpm`: | ||
|
||
## Testing | ||
``` | ||
sh jpm install circlet | ||
``` | ||
|
||
Run a server on localhost with the following command | ||
## Usage | ||
|
||
```sh | ||
jpm test | ||
``` | ||
### Creating a server | ||
|
||
You can create a HTTP server using the `circlet/server` function. The | ||
function is of the form `(circlet/server handler port &opt ip-address)` | ||
and takes the following parameters: | ||
|
||
- `handler` function that takes the incoming HTTP request object (explained in | ||
greater detail below) and returns the HTTP response object. | ||
- `port` number of the port on which the server will listen for incoming | ||
requests. | ||
- `ip-address` optional string representing the IP address on which the server | ||
will listen (defaults to `“127.0.0.1”`). The address `“*”` will | ||
cause the server to listen on all available IP addresses. | ||
|
||
The server runs immediately after creation. | ||
|
||
### Request | ||
|
||
The `handler` function takes a single parameter representing the request. The | ||
request is a Janet table containing all the information about the request. It | ||
contains the following keys: | ||
|
||
- `:uri` requested URI | ||
- `:method` HTTP method of the request as a Janet string (e.g. "GET", "POST") | ||
- `:protocol` version of the HTTP protocol used for request | ||
- `:headers` HTTP headers sent with the request as a Janet table. Keys in this | ||
table are Janet strings with standard header's name (e.g. "Host", “Accept"). | ||
Values are the values in the HTTP header. | ||
- `:body` body of the HTTP request | ||
- `:query-string` query string part of the requested URI | ||
- `:connection` internal mongoose connection serving this request | ||
|
||
### Response | ||
|
||
The return value of the `handler` function must be a Janet table containing | ||
at least the `status` key with an integer value that corresponds to the HTTP | ||
status of the response (e.g. 200 for success). | ||
|
||
Other possible keys include: | ||
|
||
- `:body` the body of the HTTP response (e.g. a string in HTML or JSON) | ||
- `:headers` a Janet table or struct with standard HTTP headers. The structure | ||
is the same as the HTTP request case described above. | ||
|
||
There is also special key `:kind` you can use. There are two possible values for | ||
this key: | ||
|
||
- `:file` for serving a file from the filesystem. The filename is specified by | ||
the `:file` key. You can specify `:mime` key with value of corresponding | ||
mime type, it defaults to text/html. | ||
- `:static` for serving static file from the filesystem. You have to provide | ||
`:root` key with value of the path you want to serve. | ||
|
||
### Middleware | ||
|
||
Circlet also allows for the creation of different “middleware”. Pieces | ||
of middleware can be thought of as links in a chain of functions that are | ||
used to consume the HTTP request. The `handler` function can be thought of | ||
as a piece of middleware and other middleware should match the signature and | ||
return type of the `handler` function, i.e. accept and return a Janet table. | ||
|
||
Middleware can be created in one of two ways. A user can define a function | ||
with the appropriate signature and return type or use Circlet’s | ||
`circlet/middleware` function to coerce an argument into a piece of | ||
middleware. Middleware pieces are often higher-order functions (meaning | ||
that they return another function). This allows for parameterization at | ||
creation time. | ||
|
||
#### Provided middleware | ||
|
||
There are three basic pieces of middleware provided by Circlet: | ||
|
||
- `(circlet/router routes)` simple routing facility. This function takes a | ||
Janet table containing the routes. Each key should be a Janet string matching | ||
a URI (e.g. `”/“`, `”/posts"`) with a value that is a function of the | ||
same form as the `handler` function described above. | ||
- `(circlet/logger nextmw)` simple logging facility. This function prints | ||
the request info on `stdout`. The only argument is the next middleware. | ||
- `(circlet/cookies nextmw)` middleware which extracts the cookies from the | ||
HTTP header and stores the value under the `:cookies` key in the request | ||
object. | ||
|
||
## Example | ||
|
||
The below example starts a very simple web server on port 8000. | ||
|
||
```lisp | ||
```clojure | ||
(import circlet) | ||
|
||
(defn myserver | ||
"A simple HTTP server" | ||
[req] | ||
"A simple HTTP server" [request] | ||
{:status 200 | ||
:headers {"Content-Type" "text/html"} | ||
:body "<!doctype html><html><body><h1>Hello.</h1></body></html>"}) | ||
:headers {"Content-Type" "text/html"} :body "<!doctype html><html><body><h1>Hello.</h1></body></html>"}) | ||
|
||
(circlet/server myserver 8000) | ||
``` | ||
|
||
## Development | ||
|
||
### Building | ||
|
||
Building requires [Janet](https://github.com/janet-lang/janet) to be installed | ||
on the system, as well as the `jpm` tool (installed by default with Janet). | ||
|
||
```sh | ||
jpm build | ||
``` | ||
|
||
You can also just run `jpm` to see a list of possible build commands. | ||
|
||
### Testing | ||
|
||
Run a server on localhost with the following command | ||
|
||
```sh | ||
jpm test | ||
``` | ||
|
||
This example is more involved, and shows all the functionality described in this | ||
document. | ||
|
||
## License | ||
|
||
Unlike [janet](https://github.com/janet-lang/janet), circlet is licensed under | ||
the GPL license in accordance with mongoose. | ||
Unlike [janet](https://github.com/janet-lang/janet), Circlet is licensed | ||
under the GPL license in accordance with mongoose. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,29 @@ | ||
(import build/circlet :as circlet) | ||
|
||
# Now build our server | ||
(circlet/server | ||
(circlet/server | ||
(-> | ||
{"/thing" {:status 200 | ||
:headers {"Content-Type" "text/html; charset=utf-8" | ||
"Thang" [1 2 3 4 5]} | ||
:body "<!doctype html><html><body> | ||
{"/thing" {:status 200 | ||
:headers {"Content-Type" "text/html; charset=utf-8" | ||
"Thang" [1 2 3 4 5]} | ||
:body "<!doctype html><html><body> | ||
<h1>Is a thing.</h1> | ||
<form action=\"bork\"> | ||
<input type=\"text\" name=\"firstname\"> | ||
<input type=\"submit\" value=\"Submit\"> | ||
</form> | ||
</body></html>"} | ||
"/blob" {:status 200 | ||
:body @"123\0123"} | ||
"/redirect" {:status 302 | ||
:headers {"Location" "/thing"}} | ||
:default {:kind :static | ||
:root "."}} | ||
circlet/router | ||
circlet/logger) | ||
"/bork" (fn [req] | ||
(let [[fname] (peg/match '(* "firstname=" (<- (any 1)) -1) (req :query-string))] | ||
{:status 200 :body (string "<!doctype html><html><body>Your firstname is " | ||
fname "?</body></html>")})) | ||
"/blob" {:status 200 | ||
:body @"123\0123"} | ||
"/redirect" {:status 302 | ||
:headers {"Location" "/thing"}} | ||
"/readme" {:kind :file :file "README.md" :mime "text/plain"} | ||
:default {:kind :static | ||
:root "."}} | ||
circlet/router | ||
circlet/logger) | ||
8000) |