Git Product home page Git Product logo

vex's Introduction

Logo

Easy-to-use, modular web framework for V.

CI

Example written on VEX

module main

import nedpals.vex.router
import nedpals.vex.server
import nedpals.vex.ctx

fn print_req_info(mut req ctx.Req, mut res ctx.Resp) {
	println('${req.method} ${req.path}')
}

fn do_stuff(mut req ctx.Req, mut res ctx.Resp) {
	println('incoming request!')
}

fn main() {
    mut app := router.new()
    app.use(do_stuff, print_req_info)

    app.route(.get, '/', fn (req &ctx.Req, mut res ctx.Resp) {
        res.send_file('index.html', 200)
    })

    app.route(.get, '/public/*path', fn (req &ctx.Req, mut res ctx.Resp) {
        res.send_file('public/' + req.params['path'], 200)
    })

    app.route(.get, '/path/:name', fn (req &ctx.Req, mut res ctx.Resp) {
        println('path is ${req.params["name"]}')
    }, fn (req &ctx.Req, mut res ctx.Resp) {
        res.send('path: ' + req.params['name'], 200)
    })

    app.route(.get, '/complex/:name/*path', fn (req &ctx.Req, mut res ctx.Resp) {
        res.send('username: ' + req.params['name'] + '\npath: ' + req.params['path'], 200)
    })

    server.serve(app, 6789)
}

Installation & Getting Started

Learn how to setup and use VEX by reading the Wiki.

Roadmap

  • Support for GET, POST, PUT, PATCH, DELETE, and OPTION HTTP methods.
  • HTTP Router (Wildcards are now supported)
  • Route groups (non-reusable for now)
  • Static file server
  • Params and query parsing
  • Middleware support
  • Cookie parsing (basic support)
  • Cookie manipulation / Session support
  • Websocket Server
  • Body parsing
    • application/x-www-form-urlencoded support
    • application/json support
    • multipart/form-data support

Contributing

  1. Fork it (https://github.com/nedpals/vex/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Examples

Examples can be found at the /examples directory.

License

MIT

Contributors

vex's People

Contributors

alichraghi avatar azhai avatar chaosunity avatar danieldaeschle avatar dnkdev avatar islonely avatar itsdonnix avatar nedpals avatar ntbbloodbath avatar spaceface777 avatar spytheman avatar terisback avatar vincenzopalazzo avatar whoizit avatar yuyi98 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vex's Issues

cannot import module "http" (not found)

Platform:
Linux a98277977ce1 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 GNU/Linux

Running on a docker spec taken from
https://github.com/taojy123/docker-vlang/blob/master/Dockerfile

V Version: V 0.1.24 c949e9e
VPM Version: vpm version 0.0.2

Any idea why am getting this "http"
Using one of the example from the https://github.com/nedpals/vex/blob/master/examples/simple_example.v

Am i missing something here?

`root@a98277977ce1:/code/blogy# v run server.v

/root/.vmodules/vex/server/server.v:8:5: cannot import module "http" (not found)
6| import (
7| net
8| http
^
9| net.urllib
10| os

root@a98277977ce1:/code/blogy# `

Need your help.

Can't install via VPM

OS version

Linux raspberrypi 4.19.50+ #896 Thu Jun 20 16:09:52 BST 2019 armv6l GNU/Linux

V version

V 0.1.27 74686d0

Step to reproduce & issue

v install nedpals.vex
0

Error in decode() for Mod error_ptr=: %s
0


<style>
body {
  margin: 0; }

* {
  font-family: "Roboto", "Helvetica Neue";
  line-height: 1.5;
} 
pre {
  font-family: "Roboto Mono", "Menlo", "Courier New"; 
	 
} 

a {
  text-decoration: none;
  color: #4078C0; } 
.content {
	max-width: 800px; 
	margin: 0 auto;
} 
.mod {
	border: 1px solid #dfdfdf; 
	border-bottom: 0; 
	width: 400px; 
} 
.mod_name {
	width: 80% ; 
	display: table-cell; 
} 
.mod_name a {
	display: block;
	padding: 10px; 
} 
.mod:hover {
	background-color: rgb(225, 239, 255); 
} 
.mod_nr_downloads {
	width: 100px ; 
	display: table-cell; 
} 
.modules {
	margin-top: 20px; 
} 
input[type=text], input[type=url] {
padding: 3px; 
font-size: 14px; 
margin-bottom: 5px; 
} 
</style>
 
<div class="content"> 

<a href=/><img src="//vlang.io/img/vpm.png" style="height:100px"></a> 
<br> 




<!--
<h1>modules.vlang.io</h1>
-->



<pre>v install [module]
</pre>



<a href="/new">Submit a module</a>

<h3>71 modules </h3>


<div class="modules ">

<div class="mod ">
<div class="mod_name ">
<a href="/mod/ui">ui</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.args">nedpals.args</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/radare.r2">radare.r2</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/vpervenditti.vgram">vpervenditti.vgram</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nsauzede.vsdl2">nsauzede.vsdl2</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.vargs">nedpals.vargs</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/regex">regex</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/radare.toxml">radare.toxml</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.vex">nedpals.vex</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.mime">nedpals.mime</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/thecodrr.crayon">thecodrr.crayon</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/vsl">vsl</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nsauzede.vnk">nsauzede.vnk</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nsauzede.vig">nsauzede.vig</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/syou.picoev">syou.picoev</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/thecodrr.boxx">thecodrr.boxx</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/spytheman.regex">spytheman.regex</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/christopherzimmerman.vnum">christopherzimmerman.vnum</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.jsonrpc">nedpals.jsonrpc</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/damienfamed75.vraylib">damienfamed75.vraylib</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/thecodrr.vave">thecodrr.vave</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nedpals.vpkg">nedpals.vpkg</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/etienne-napoleone.chalk">etienne-napoleone.chalk</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/tianyazc.vttable">tianyazc.vttable</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Omega0x013.vgame">Omega0x013.vgame</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/patrickpissurno.redis">patrickpissurno.redis</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Iaiao.jsonmap">Iaiao.jsonmap</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/zenith391.vgtk3">zenith391.vgtk3</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lydiandy.vast">lydiandy.vast</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lydiandy.cjson">lydiandy.cjson</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/anihex.vaser">anihex.vaser</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/amalshaji.sorty">amalshaji.sorty</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Iaiao.speedrun">Iaiao.speedrun</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/HedariKun.voltcord">HedariKun.voltcord</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/zmeriksen.lol">zmeriksen.lol</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Puzomor.msgpack">Puzomor.msgpack</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/thecodrr.vspeech">thecodrr.vspeech</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/watchmen123456.valval">watchmen123456.valval</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/jamestomasino.veasing">jamestomasino.veasing</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lobotony.lmath">lobotony.lmath</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/zenith391.vwxml">zenith391.vwxml</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/popzxc.vbase64">popzxc.vbase64</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/popzxc.vtest">popzxc.vtest</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Bowero.owmw">Bowero.owmw</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lobotony.ldata">lobotony.ldata</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/ifndev.flogs">ifndev.flogs</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/radare.r2pipe">radare.r2pipe</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/alexesprit.colors">alexesprit.colors</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Chase-K.vbst">Chase-K.vbst</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/spytheman.vini">spytheman.vini</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lobotony.bitmap">lobotony.bitmap</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/emily33901.vproto">emily33901.vproto</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/spytheman.vperlin">spytheman.vperlin</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/medvednikov.sdl">medvednikov.sdl</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Bowero.riv">Bowero.riv</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/gaurav-gogia.filecheck">gaurav-gogia.filecheck</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/nevrome.vconrand">nevrome.vconrand</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lobotony.stbiw">lobotony.stbiw</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/alexesprit.semver">alexesprit.semver</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/londoed.gobjectv">londoed.gobjectv</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Puzomor.msgpackrpc">Puzomor.msgpackrpc</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/lobotony.stbtt">lobotony.stbtt</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/gaurav-gogia.valid">gaurav-gogia.valid</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/exastencil.vape">exastencil.vape</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/dhonx.vgobject">dhonx.vgobject</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/XcloudFance.hashmap">XcloudFance.hashmap</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Omega0x013.loadingbar">Omega0x013.loadingbar</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/adlesh.mathx">adlesh.mathx</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/Delta456.isthirt">Delta456.isthirt</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/asvvvad.vlipboard">asvvvad.vlipboard</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod ">
<div class="mod_name ">
<a href="/mod/shiipou.vapi">shiipou.vapi</a>
</div>
<div class="mod_nr_downloads ">
</div>
</div>

<div class="mod" style="border:0; border-top: 1px solid #dfdfdf">&nbsp;</div>
</div>

</div>


0

Error in decode() for Mod error_ptr=: %s
Errors while retrieving meta data for module nedpals.vex:
Skipping module "nedpals.vex", since it is missing name or url information.
Skipping module "nedpals.vex", since it is missing name or url information.

err: Failed to add route. Reason: Only one wildcard OR param route in a route list is allowed.

Hey there.

First off - great work on Vex. I'm really impressed.

My inquiry is - why do we need to have this error thrown? In restful, if I want to have a get request go to /todo/:id and a patch request go to /todo/:id, I think this should be allowed. However, it seems like this is discouraged. The validation will fail as part of the fn add in the router module. This is definitely allowed in other restful frameworks in other languages.

Can you explain why you did it this way and what you suggest as an alternative?

Thank you!

Thank you,

Failed To Read First Line

v -cg run main.v get an error log:

name: admin | param_name:  | children: /login
name: login | param_name:  | children: 
Failed To Read First Line

Simple example does not working, has an error : cannot register struct `nedpals.vex.ctx.Req`, another type with this name exists

I'm doing simple learning vex, through examples provided in README file.
here the code i'm trying to learn

import nedpals.vex.router
import nedpals.vex.ctx
import nedpals.vex.server

fn main() {
	mut router := route.new()
	router.route(.get, '/', fn (req &ctx.Req, mut res ctx.Resp) {
		res.send_file('index.html', 200)
	})
	server.serve(router, 6789)
}

i'm only have two files in my experiment folder, one is v file above, the other was html file.

$ ls 
index.html  main.v

when i'm trying to run v run main.v, i'm getting this error

$ v run "/home/green/vexper/main.v"
/home/green/.vmodules/nedpals/vex/ctx/ctx.v:23:12: error: cannot register struct `nedpals.vex.ctx.Req`, another type with this name exists
   21 | 
   22 | // Server request data
   23 | pub struct Req {
      |            ~~~
   24 | pub mut:
   25 |     body      []byte

I dont know what happen really, and i think no other Req struct was defined before

Any helps very appreciated ...
Thanks for the time

Why is the variable address the same for each request

https://github.com/nedpals/vex/blob/master/router/router.v#L44

pub fn (r Router) receive(method string, path string, raw_headers []string, body []byte) (int, []byte, []byte) {
	def_header := ('\r\n' + raw_headers.join('\r\n')).bytes()
	req_path := urllib.parse(path) or {
		internal_err_body := r.respond_error(500)
		return 500, def_header, internal_err_body
	}
	mut req := ctx.Req{
		method: method
		path: req_path.path
		raw_query: req_path.raw_query
		ctx: r.ctx
	}
	mut res := ctx.Resp{}
	req.parse_headers(raw_headers)
	println(ptr_str(&res.headers)) // here

print :

[VEX] HTTP Server has started.
[VEX] Running On http://localhost:6789
7ffee50e2ea0
/api/login
{'Content-Type': ['text/html; charset=UTF-8'], 'X-Powered-By': ['VEX/0.3.5'], 'Server': ['VEX'], 'Access-Control-Allow-Origin': ['http://localhost:3100'], 'Access-Control-Allow-Methods': ['POST'], 'Access-Control-Allow-Headers': ['x-requested-with, content-type']}
7ffee50e2ea0
/api/login
admin_login
No appropriate content type header for body found.
7ffee50e2ea0
/api/login
{'Content-Type': ['text/html; charset=UTF-8'], 'X-Powered-By': ['VEX/0.3.5'], 'Server': ['VEX']}

Blog links

What's the best way to add a link to a blog post showing V/Vex usage example? Here's a link to my blog post for example

Future of Vex

Let me tell you this straight: the Vex web framework is pretty much limited right now. Indeed, some of it's features simplifies the creation of web apps written on V such as routing and the concept of middlewares. But despite all of that, they are still useless which brings us here to this issue of the future of Vex and how we are going to solve of it despite some issues and limitations the V compiler has right now.

This issue will be updated frequently

  1. The Vex web framework borrows ideas from Express.js and to the real OG of this pattern - Sinatra from Ruby. They give you the power to start building your backend/web app server without too much boilerplate as seen from other frameworks like Rails. In V, this is absolutely the right pattern for the semantics of the language as you just insert functions into get, post handlers and you're done! But in reality, like I said earlier, due to the current limitations Vex faces, there are some edge cases wherein you cannot easily use. Like this:
import vex.server as vex
struct Blog {
  db Db
}

fn (blog Blog) get_index(req vex.Request, res mut vex.Response) {
      // assume we have queried the posts
      res.send(posts, 200)
}

fn main() {
    s := vex.new()
    // assume we have initiated the blog struct
    s.get('/blog', blog.get_index)
    s.serve(8000)
}

In this snippet, we would like to use blog.get_index when the /blog route hits into our server. However, the V compiler treats it as something other than a function which scratches our head. Indeed it's a wonderful thing to have but it might never been solve in this current state. Instead, Vex proposes a new change: the framework will do the context processing which includes initializing and injecting the request and the response data and you will take care the rest on how would you process the rest. However, you will still gonna register your routes as they will be used later when there is a matching route from the request. It works likes this:

import vex.server as vex

struct Blog {
    db Db
}

fn (blog Blog) get_index(req vex.Request, res mut vex.Response) {
      // assume we have queried the posts
      res.send(posts, 200)
}

fn (app App) handle_req(ctx mut vex.Context) {
   // assume we have initiated the blog struct

   // middlewares will be removed tho :((

    // the match statement will look for the appropriate route based on the pattern given, nothing else found, it returns an error.
    match ctx.current_route {
        '/blog' {
            blog.get_index(ctx.req, mut ctx.res) // it works!
        }
        else {
            ctx.res.send('Not found', 404)
        }
    }
}

fn main() {
    s := vex.new()
    s.register('get', '/blog')
   // or you can use this as well s.get('/blog')
    s.create(handle_req, 8000)
}

In this proposed change, the code is working indeed. But here's another catch which will be talking about in point number 2.

  1. As you may have seen, we might have finally solved the problem in the framework. But no you're wrong because we created another problem this time. You see the Blog struct initiated (assume it had one as the comment says) inside the handle_req function? Everytime there is a request coming from the client, that Blog struct had to initialize again which is not our main goal for this one.

The current DB example in our examples is not suitable and satisfied enough if you are constantly mutating the data/structs of your backend which bogs me this question: How are we gonna be able to share resources (like existing structs, DB, and etc.) within a single Vex server instance despite the current limitations in our compiler? Some of the code lying inside it were "patched" for vweb in order for it to run like the feature we want to have right now.

  1. HTML Templating is really a need right now. Most people who are gonna be using the services written on V and using Vex will surely be needing an HTML content. Client-side template handling like the valval framework does is something a user might decide instead of reinforcing it.

  2. The concept of having small, modular apps and connecting it to the main server is a pretty interesting problem to tackle. It's more or less similar to microservices (I haven't tried it yet so pardon my ignorance) that's been the talk of the town in the past couple of years. Vex (as well as other frameworks) should be a great thing to have development-wise but I haven't think of a great design on how to connect multiple apps into one vex instance. One would be connecting through a so-called "group routes" or into a single, main App struct so other ones can connect to it as well. But who knows? This is a tough decision to make as it can rewrite the whole API or something a whole new thing might happen in the code.

  3. I'm planning to separate the router as a module. Fun fact, v-mime, which is a module I created for identifying MIME types, is originally gonna be part of the Vex framework as a submodule. Anyways, my router implementation isn't that good enough so feel free to fork and improve the code. As time passes by, new features might be put into modules, and eventually Vex will be set of modules/toolkit for building your own web framework (or should I say "be a mother of all web frameworks" not to be ambitious though hahahaha)

I was planning to release a new version today, but it's too risky so might as well just share to you the things that might happen in the future releases, as well as the things that I'm struggle with right now. The "new unreleased" code is available in the experimental branch of the repository and feel free to submit any suggestions to it. Thank you,

[Updated: 9:10PM (+8 Manila) - added HTML templating section]

[Question] does vex support streaming uploads

Hi everyone

So I want to re-make one of my Python projects in V, and for that I have one big requirement: I need to be able to stream data to the server using a PUT or a POST request. The application I'm building will be the upload point for CI output that could reach a gigabyte in size, and I'd like to be able to stream multiple of these files at once to the server without having to completely load the file into memory. I tried this using vweb & discovered that vweb does try to load the entire file into memory, so I'd like to try vex, but only if it does support this feature.

tl;dr would vex load an entire file into memory when it's sent using a PUT request?

Thanks in advance!

How can you use a value inside an anonymous handler function, if the value is define outside this handler

I have a situation like this

fn main() {
	//initialize the app
	mut app := router.new()
	mut repo := &TaskRepo{}

	app.route(.post, '/task', fn (req &ctx.Req, mut resp &ctx.Resp) {
		 create_new_task(&repo, req, resp)
	})

TaskRepo is a struct defined in another module and is imported into the main module. If I try to use it in the '/task' handler, I get a very clear error message that the 'repo' variable is not defined inside the handler.

.\main.v:46:21: error: undefined ident: `repo`
   44 |
   45 |     app.route(.post, '/task', fn (req &ctx.Req, mut resp &ctx.Resp) {
   46 |          create_new_task(&repo, req, resp)
      |                           ~~~~
   47 |     })

Is there a way around this? Let me know if my question is clear enough also

Plugin system proposal

Hi,
in my fork here (in the branch 'plugin-poc') I'm working on the addition of a plugin system to try to help modularize parts of webapp (not in contrast with middleware api, but a complement to it); for example in a plugin you can define routes and many other stuff via its reference to Router; define methods to use when needed, etc.
In my code I'm adding some examples, hope you find useful/interesting.
I used a similar approach in a great Node.js framework and I find it very useful even to isolate some generic features in its own plugins and npm package.
My experiment is a Work-In-Progress, anyway if you think it's useful I can raise a PR so we can start to look/discuss if there is something good to integrate here.
I'm finding some problems in V so maybe some parts are still too early and more complex than could be, anyway it's a starting point.

Thanks for now.

Get error of middleware: Unknown method.

8 | struct Person {

middleware_example.v:24:6: error: unknown method: nedpals.vex.router.Router.get.
6 possibilities: group, inject, receive, respond_error, route, use.
22 | mut app := router.new()
23 | app.use(do_stuff, print_req_info)
24 | app.get('/', fn (req ctx.Req, mut res ctx.Resp) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 | res.send_json(Person{
26 | name: req.query['name']
middleware_example.v:30:6: error: unknown method: nedpals.vex.router.Router.get.
6 possibilities: group, inject, receive, respond_error, route, use.
28 | }, 200)
29 | })
30 | app.get('/hello', fn (req ctx.Req, mut res ctx.Resp) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31 | res.send('Hello World!', 200)
32 | })

Modular middleware api

Hey, thanks for building VEX. I am falling in love with V, and coming from a Node.js background this rings bells.

Looking at the code, it seems routes and middlewares are separate concepts. I am not sure but I think with your present setup you cannot add a middleware after having registered a route (an have it execute only after the route is called). The use case here is have some routes stand before some protected middleware.

Just as well, I don't think you can have multiple middlewares on routes ; nor can you register a top path and use route adding method over it to rganize better your code (I think express calls that a router).

By modifing a bit the design we could have each route handled as a simple middleware, and allow nesting lists of middlewares for graph-like execution. so that we can add multiple routes over a single top route, and that we can add multiple middlewares on top of a single route.

I am making any sense ? If such PR's are welcome, I'd be happy to offer one once the compatibility with 0.2 is fixed.

Also, It would be good to provide some basic middlewares (cors, JWT, logs). Mirroring express, cookie parsing, body decoding, file handling could probably exist as middlewares and not in the main VEX lib.

Compiling with -prod flag throws build error

When trying to compile the following simple program using the -prod flag it throws a build error. Details are below:

Simple server:

# vex-server.v

module main

import nedpals.vex.router
import nedpals.vex.server
import nedpals.vex.ctx

fn main() {
    mut app := router.new()
    app.route(.get, '/', fn (req &ctx.Req, mut res ctx.Resp){
        res.send('', 200)
    })
    server.serve(app, 6789)
}

Compiling throws an error:

$ v -gc boehm -prod -o vex-server vex-server.v
==================
/tmp/v_1000/vex-server.15941504213174346917.tmp.c: In function ‘nedpals__vex__router__Router_receive’:
/tmp/v_1000/vex-server.15941504213174346917.tmp.c:27884:113: error: field name not in record or union initializer
27884 |                         ((string*)map_set(&req.headers, &(string[]){_SLIT("Content-Type")}, &(Array_string[]) { .data)[0]_SLIT("multipart/form-data") });
      |                                                                                                                 ^
/tmp/v_1000/vex-server.15941504213174346917.tmp.c:27884:113: note: (near initialization for ‘(anonymous)’)
/tmp/v_1000/vex-server.15941504213174346917.tmp.c:27884:118: error: expected ‘=’ before ‘)’ token
27884 |                         ((string*)map_set(&req.headers, &(string[]){_SLIT("Content-Type")}, &(Array_string[]) { .data)[0]_SLIT("multipart/form-data") });
      |                                                                                                                      ^
/tmp/v_1000/vex-server.15941504213174346917.tmp.c:27884:118: error: expected ‘}’ before ‘)’ token
27884 |                         ((string*)map_set(&req.headers, &(string[]){_SLIT("Content-Type")}, &(Array_string[]) { .data)[0]_SLIT("multipart/form-data") });
      |                                                                                                               ~      ^
/tmp/v_1000/vex-server.15941504213174346917.tmp.c:27884:151: error: expected ‘)’ before ‘}’ token
...
==================
(Use `v -cg` to print the entire error message)

db_example.v is not working

Hi,
I tried running the db_example.v provided in the example. It seems like it wont run as per the spec of the vlang.
But , I was able to compile the db_example.v to C code, but the generated C code was not compiling to executable .

The problem is at the point of reffering db variable in route handlers. For eg: here

As per the documentation of Vlang, functions are pure by default, thus, it can not use any variable defined outside of the function right? ( But still, I m surprised on the fact that, V file compiled successfully to C code )

if that is the case, how we can expect this to work ?

( I manually edited the generated C code and made slight modifications to allow global variables, then C code successfully compiled and I was able to run the example. I seen the example in action. It was super cool. Thanks! )

Critical memory leaks

Thanks for creating this project. While performing a simple test to verify the speed and resource consumption of your framework I discovered critical memory leaks that would prevent anyone from using this framework in a production environment. Details are below.

System info:

OS: Manjaro Linux x86_64
Kernel: 5.15.28-1-MANJARO
CPU: Intel i9-9900K (16) @ 5.000GHz
Memory: 64227MiB

Simple server:

# vex-server.v

module main

import nedpals.vex.router
import nedpals.vex.server
import nedpals.vex.ctx

fn main() {
    mut app := router.new()
    app.route(.get, '/', fn (req &ctx.Req, mut res ctx.Resp){
        res.send('', 200)
    })
    server.serve(app, 6789)
}

Compile and start the server:

$ v vex-server.v
$ ./vex-server
[VEX] HTTP Server has started.
[VEX] Running On http://localhost:6789

Take the initial memory allocation:

$ pmap $(pgrep vex-server) | grep total
 total             6048K

Execute a simple load test (I'm using pewpew here)

$ pewpew benchmark http://127.0.0.1:6789 --rps 200 -d 30

Take the memory allocation after the load test:

$ pmap $(pgrep vex-server) | grep total
 total           835404K

You can see the memory spiked from ~8MB to ~835MB in just 30 seconds of running the load test with ~200 requests/sec.

Furthermore, repeating the above tests with Valgrind indeed confirms the leaks. First start the server with valgrind then run the benchmark with pewpew once again:

$ valgrind ./vex-server 
==1907295== Memcheck, a memory error detector
==1907295== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1907295== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==1907295== Command: ./vex-server
==1907295== 
[VEX] HTTP Server has started.
[VEX] Running On http://localhost:6789
^C==1907295== 
==1907295== Process terminating with default action of signal 2 (SIGINT)
==1907295== 
==1907295== HEAP SUMMARY:
==1907295==     in use at exit: 808,412,463 bytes in 801,440 blocks
==1907295==   total heap usage: 957,621 allocs, 156,181 frees, 827,025,445 bytes allocated
==1907295== 
==1907295== LEAK SUMMARY:
==1907295==    definitely lost: 19,422,529 bytes in 654,341 blocks
==1907295==    indirectly lost: 787,359,215 bytes in 144,001 blocks
==1907295==      possibly lost: 1,310,720 bytes in 10 blocks
==1907295==    still reachable: 319,999 bytes in 3,088 blocks
==1907295==         suppressed: 0 bytes in 0 blocks
==1907295== Rerun with --leak-check=full to see details of leaked memory
==1907295== 
==1907295== For lists of detected and suppressed errors, rerun with: -s
==1907295== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

With Valgrind, what you want to see to ensure no memory leaks are found is the following output:

HEAP SUMMARY:
    in use at exit: 0 bytes in 0 blocks
 
All heap blocks were freed -- no leaks are possible
 
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Error "cannot register struct `nedpals.vex.ctx.Req`"

Hi,

I've installed vex and trying it with a simple example code:

module main

import nedpals.vex.server
import nedpals.vex.ctx

fn main() {
	mut s := server.new()

	s.get('/greet/:name', fn (req ctx.Req, mut res ctx.Resp) {
		name := req.params['name']
		res.send('Hello, $name!', 200)
	})
	println('Starting server listening on port 5005...')
	s.serve(5005)
}

But when I try to run it I've got it:

cebob@ubuntu:~/work/moleculerjs/sidecar/examples/full/v$ v run demo-vex.v
/home/icebob/.vmodules/nedpals/vex/ctx/context.v:5:12: error: cannot register struct `nedpals.vex.ctx.Req`, another type with this name exists
    3 | import time
    4 | 
    5 | pub struct Req {
      |            ~~~
    6 | pub mut:
    7 |     body string

Could you help me? I'm using V 0.2 e4f94b6.

Thanks in advance!

Off-Topic: Spry

Seeing your activity, I thought you might be interested in Spry (perfect documentation on http://sprylang.se/manual.html ). It's a language from the very opposite end of spectrum than V resides. Spry is the most dynamic language you could think of (it does all computation by just manipulating the live AST). One can use similar programming techniques like for TCL, but safer, nicer, moderner 😉.

Feel free to make your hands dirty with Spry and you might be enlightened how can problems be nicely structured (yeah, it's not Spry, but Red, which is "the same", but somewhat less modern).

Missing documentation "how to run/build"

First, thanks and great work!

How do I run/build this code? Thanks :)

How do I use it as a library in my project? I tried using v install nedpals.vex but I got a series of errors :s

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.