2021-05-15 04:53:25 +02:00
|
|
|
# vweb - the V Web Server #
|
2019-07-29 19:46:26 +02:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
A simple yet powerful web server with built-in routing, parameter handling,
|
|
|
|
templating, and other features.
|
2019-12-09 22:16:39 +01:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
## Alpha level software ##
|
2019-07-29 19:46:26 +02:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
Some features may not be complete, and there may still be bugs. However, it is
|
|
|
|
still a very useful tool. The [gitly](https://gitly.org/) site is based on vweb.
|
2019-07-29 18:50:25 +02:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
## Features ##
|
2019-07-30 21:15:17 +02:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
- **Very fast** performance of C on the web.
|
|
|
|
- **Small binary** hello world website is <100 KB.
|
|
|
|
- **Easy to deploy** just one binary file that also includes all templates.
|
|
|
|
No need to install any dependencies.
|
|
|
|
- **Templates are precompiled** all errors are visible at compilation time,
|
|
|
|
not at runtime.
|
|
|
|
|
|
|
|
There is no formal documentation yet - here is a simple
|
|
|
|
[example](https://github.com/vlang/v/tree/master/examples/vweb/vweb_example.v)
|
|
|
|
|
|
|
|
There's also the V forum, [vorum](https://github.com/vlang/vorum)
|
2019-07-30 21:15:17 +02:00
|
|
|
|
|
|
|
`vorum.v` contains all GET and POST actions.
|
2019-07-29 18:50:25 +02:00
|
|
|
|
2020-11-18 18:28:28 +01:00
|
|
|
```v ignore
|
2019-07-29 18:50:25 +02:00
|
|
|
pub fn (app mut App) index() {
|
|
|
|
posts := app.find_all_posts()
|
|
|
|
$vweb.html()
|
|
|
|
}
|
|
|
|
|
2019-12-09 22:16:39 +01:00
|
|
|
// TODO ['/post/:id/:title']
|
|
|
|
// TODO `fn (app App) post(id int)`
|
2019-07-29 18:50:25 +02:00
|
|
|
pub fn (app App) post() {
|
2019-12-09 22:16:39 +01:00
|
|
|
id := app.get_post_id()
|
2019-07-29 18:50:25 +02:00
|
|
|
post := app.retrieve_post(id) or {
|
2020-12-31 17:47:20 +01:00
|
|
|
app.redirect('/')
|
2019-12-09 22:16:39 +01:00
|
|
|
return
|
2019-07-29 18:50:25 +02:00
|
|
|
}
|
|
|
|
comments := app.find_comments(id)
|
2019-12-09 22:16:39 +01:00
|
|
|
show_form := true
|
2019-07-29 18:50:25 +02:00
|
|
|
$vweb.html()
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
`index.html` is an example of the V template language:
|
|
|
|
|
2019-07-29 19:46:26 +02:00
|
|
|
```html
|
2019-12-09 22:16:39 +01:00
|
|
|
@for post in posts
|
2019-07-29 18:50:25 +02:00
|
|
|
<div class=post>
|
2019-12-09 22:16:39 +01:00
|
|
|
<a class=topic href="@post.url">@post.title</a>
|
|
|
|
<img class=comment-img>
|
|
|
|
<span class=nr-comments>@post.nr_comments</span>
|
2019-07-29 18:50:25 +02:00
|
|
|
<span class=time>@post.time</span>
|
|
|
|
</div>
|
|
|
|
@end
|
|
|
|
```
|
|
|
|
|
2020-12-31 17:47:20 +01:00
|
|
|
`$vweb.html()` compiles an HTML template into V during compilation,
|
2021-05-15 04:53:25 +02:00
|
|
|
and embeds the resulting code into the current action.
|
2019-07-29 18:50:25 +02:00
|
|
|
|
2019-09-14 22:54:14 +02:00
|
|
|
That means that the template automatically has access to that action's entire environment.
|
2019-07-29 19:46:26 +02:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
## Deploying vweb apps ##
|
2019-07-29 19:46:26 +02:00
|
|
|
|
|
|
|
Everything, including HTML templates, is in one binary file. That's all you need to deploy.
|
2021-03-03 13:39:04 +01:00
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
## Getting Started ##
|
|
|
|
|
|
|
|
To start with vweb, you have to import the module `vweb`. After the import,
|
|
|
|
define a struct to hold vweb.Context (and any other variables your program will
|
|
|
|
need).
|
2021-03-03 13:39:04 +01:00
|
|
|
|
2021-05-17 07:51:49 +02:00
|
|
|
The web server can be started by calling `vweb.run(&App{}, port)`.
|
2021-03-03 13:39:04 +01:00
|
|
|
|
|
|
|
**Example:**
|
2021-05-15 04:53:25 +02:00
|
|
|
|
2021-03-03 13:39:04 +01:00
|
|
|
```v ignore
|
|
|
|
import vweb
|
|
|
|
|
|
|
|
struct App {
|
|
|
|
vweb.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2021-05-17 07:51:49 +02:00
|
|
|
vweb.run(&App{}, 8080)
|
2021-03-03 13:39:04 +01:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-05-15 04:53:25 +02:00
|
|
|
### Defining endpoints ###
|
|
|
|
|
2021-03-03 13:39:04 +01:00
|
|
|
To add endpoints to your web server, you have to extend the `App` struct.
|
|
|
|
For routing you can either use auto-mapping of function names or specify the path as an attribute.
|
|
|
|
The function expects a response of the type `vweb.Result`.
|
|
|
|
|
|
|
|
**Example:**
|
2021-05-15 04:53:25 +02:00
|
|
|
|
2021-03-03 13:39:04 +01:00
|
|
|
```v ignore
|
|
|
|
// This endpoint can be accessed via http://localhost:port/hello
|
|
|
|
fn (mut app App) hello() vweb.Result {
|
|
|
|
return app.text('Hello')
|
|
|
|
}
|
|
|
|
|
|
|
|
// This endpoint can be accessed via http://localhost:port/foo
|
|
|
|
["/foo"]
|
|
|
|
fn (mut app App) world() vweb.Result {
|
|
|
|
return app.text('World')
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
To create an HTTP POST endpoint, you simply add a `[post]` attribute before the function definition.
|
|
|
|
|
|
|
|
**Example:**
|
2021-05-15 04:53:25 +02:00
|
|
|
|
2021-03-03 13:39:04 +01:00
|
|
|
```v ignore
|
|
|
|
[post]
|
|
|
|
fn (mut app App) world() vweb.Result {
|
|
|
|
return app.text('World')
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-04-09 18:17:33 +02:00
|
|
|
To pass a parameter to an endpoint, you simply define it inside
|
2021-03-03 13:39:04 +01:00
|
|
|
an attribute, e. g. `['/hello/:user]`.
|
|
|
|
After it is defined in the attribute, you have to add it as a function parameter.
|
|
|
|
|
|
|
|
**Example:**
|
2021-05-15 04:53:25 +02:00
|
|
|
|
2021-03-03 13:39:04 +01:00
|
|
|
```v ignore
|
|
|
|
['/hello/:user']
|
|
|
|
fn (mut app App) hello_user(user string) vweb.Result {
|
|
|
|
return app.text('Hello $user')
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-04-09 18:17:33 +02:00
|
|
|
You have access to the raw request data such as headers
|
2021-03-03 13:39:04 +01:00
|
|
|
or the request body by accessing `app` (which is `vweb.Context`).
|
|
|
|
If you want to read the request body, you can do that by calling `app.req.data`.
|
2021-05-15 04:53:25 +02:00
|
|
|
To read the request headers, you just call `app.req.header` and access the
|
|
|
|
header you want, e.g. `app.req.header.get(.content_type)`. See `struct Header`
|
|
|
|
for all available methods (`v doc net.http Header`).
|