GithubHelp home page GithubHelp logo

nickel.rs's People

Contributors

abonander avatar axelmagn avatar berkerpeksag avatar bguiz avatar burntsushi avatar carols10cents avatar cburgdorf avatar danielorf avatar detegr avatar dotdash avatar dtolnay avatar euclio avatar gfour avatar hjr3 avatar homu avatar huonw avatar iterion avatar janpantel avatar jolhoeft avatar ncharlton02 avatar nielsle avatar nikomatsakis avatar ninjabear avatar rgs1 avatar robertohuertasm avatar ryman avatar simonteixidor avatar tanriol avatar veeti avatar vshell 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  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

nickel.rs's Issues

nickel-demo compile error

Following the demo steps on the nickel.rs website went well until I got this compiler error:

--> error: linking with cc failed: exit code: 1

Once I installed libssl-dev, the demo compiled correctly and ran. You may want to consider adding this to the notes, or check for it in your code.

Was testing on Ubuntu 14.04 Desktop.

-Thanks!
-- Nick

Type safety for Request/Middleware

The following code builds today:

extern crate nickel_postgres;
extern crate nickel;

use std::io::net::ip::Ipv4Addr;
use self::nickel::{Nickel, Request, Response, JsonBody};
use nickel_postgres::{ PostgresMiddleware, PostgresRequestExtensions };

fn main() {
    let mut server = Nickel::new();
    fn db_handler(req: &Request, response: &mut Response)
    {
        let db_conn = req.db_conn();
        response.send("doesn't work");
    }
    let mut router = Nickel::router();
    router.get("/", db_handler);

    server.utilize(router);
    server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
}

db_handler() will never be able to retrieve a database connection since we haven't utilized a PostgresMiddleware and we will get a crash at every request.

In my opinion, the whole point of writing web applications in a statically typed language is that the compiler will catch this kind of bugs for us. With the current situation we're no better than Python/Ruby/Whatever in that regard.

Could we discuss some approaches to solving this? I have some ideas that I'm going to try out but I'd like to hear some more thoughts on this too.

StaticFiles Middleware

Consider this example:

extern crate http;
extern crate nickel;

use std::io::net::ip::Ipv4Addr;
use nickel::{
    Nickel, Request, Response
};

fn main() {
    let mut server = Nickel::new();

    fn a_handler (_request: &Request, response: &mut Response) {
        response.set_content_type("html");
        response.send("hello world");
    }

    server.utilize(Nickel::static_files("assets/"));
    server.get("/foo", a_handler);
    server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
}

In https://github.com/nickel-org/nickel.rs/blob/master/src/static_files_handler.rs#L28 FileNotFound error is thrown and therefore routes defined after the StaticFiles Middleware are not processed anymore.

In thinking of middlewares, shouldn't the StaticFiles Middleware pass this on to the remaining middleware stack if it isn't able to process it.

Cheers benny

alternative to 'utilize'

Is there a reason .utilize() is used instead of .use()? 'Utilize' is a bit of an ugly filler word, and it's (perhaps) needlessly different from Express and other frameworks.

Use write! macro instead of write() in examples

It would improve readability to change following:

    let text = String::new()
                   .append("This is user: ")
                   .append(request.params.get(&"userid".to_string()).as_slice());

    response.write(text.as_bytes()); 

into following:

write!(response, "This is user: {}", request.params.get(&"userid".to_string()));

Should we rename this to express.rs?

The goal of this project is to create a web framework in Rust with a focus on simplicity. It should be easy to learn. Therefore it takes much inspiration from express.js. I wonder if it would help community adoption to actually rename it to express.rs.

Migrate to floor-org organization

I already tried it but this broke our documentation so I quickly rolled back. We need to make sure to change our documentation upgrade script to push into right repository before we move. That's because organization pages work slightly different from private repository pages.

Error compiling the project

Hi, I'm new to Rust. I'm very excited to try this new web framework backed by this new awesome language.
I'm having problems compiling the project, when compiling rust-openssl specifically.
This is what the error looks like:

$ make all
cargo build -v
     Running `rustc src/http/lib.rs --crate-name http --crate-type lib -g --out-dir /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps`
     Running `rustc lib.rs --crate-name openssl --crate-type lib -g --out-dir /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps`
     Running `rustc src/lib.rs --crate-name floor --crate-type lib -g --out-dir /Users/jcivancevich/Desktop/floor/target -L /Users/jcivancevich/Desktop/floor/target -L /Users/jcivancevich/Desktop/floor/target/deps`
   Compiling openssl v0.0.0 (https://github.com/sfackler/rust-openssl.git)
Could not execute process `rustc lib.rs --crate-name openssl --crate-type lib -g --out-dir /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps -L /Users/jcivancevich/Desktop/floor/target/deps` (status=101)
--- stderr
error: multiple input filenames provided

Thanks for your great work!
Hopefully, I can contribute to this project soon :)

Make the example site more feature rich

Would be great to use that as a real life example to actually test out things like the static file handler. I guess it's plenty of bugs but nobody noticed until now :)

Pre/Post Hooks per route

The middleware system express uses (and which is soon to land in Floor as well) allows a stack of function to run before each request. However, those run before any route handler and are great for pretty generic things like a body parser or logging.

However, wouldn't it be also nice to be able to register pre/post hooks per route?

Like this:

let some_handler = fn (req: Request, res: Response) { //do something; };
let pre_hook1 = fn (req: Request, res: Response) { //do something; };
let pre_hook2 = fn (req: Request, res: Response) { //do something; };
let post_hook1 = fn (req: Request, res: Response) { //do something; };
let post_hook2 = fn (req: Request, res: Response) { //do something; };

let server = Floor::new();
server
    .get("/some/route", some_handler)
    .pre_hook(preHook1)
    .pre_hook(preHook2)
    .post_hook(postHook1)
    .post_hook(postHook2);

I wonder how @Kyjan @PascalPrecht and @apinnecke think about it

response.send always sets content-type "text/plain"

I believe that currently the only way to send a non-"text/plain" response is via reaching into response.origin, for example w/ something like this.

response.origin.headers.content_type = Some(MediaType {
    _type: "text".to_string(),
    subtype: "html".to_string(),
    parameters: Vec::new()
});
let _ = response.origin.write("<html></html>");

This is due to this in response.rs.

I don't have a particular approach in mind.

  • Matching an extension string from request.origin.request_uri could be useful (with some configurable default, probably defaulting to "text/html").
  • A response.send_with_code_and_headers could be useful.
  • Maybe instead of a string, send should take a trait implementation, allowing for an assortment of structs to be sent as responses.

Wrap ResponseWriter as Response and provide useful methods

We should wrap the ResponseWriter with our own Response struct and then move stuff life header handling there.

This is exactly what expressjs does:

https://github.com/visionmedia/express/blob/9bf1247716c1f43e2c31c96fc965387abfeae531/lib/response.js

We currently hard code the header which obviously is the wrong thing: https://github.com/cburgdorf/Floor/blob/master/src/server.rs#L28

If we would have methods like send, json etc on our Response object, we could figure out the correct header automatically (but still allow overwriting if needed).

This is exactly how express does it I think.

Make router a middleware

I was just pointed to a bug by @bguiz that roughly goes like this:

If you use the static_files middleware then all your responses from your regular matched route handler will be prepended with Not Found. It's unfortunately only the tip of the iceberg pointing out a bigger design flaw with the current request pipeline that nickel uses.

Why does that happen?

This is how the request pipeline in nickel looks like:

Request -> MiddlewareHandler -> MatchedRouteHandler
                       |
                       > ErrorHandler

What this means is that when your /foo/bar handler runs, the static_files handler has already yield an error because it couldn't find a file to serve at /foo/bar.

Why did this work before we had error handler?

Because at that time the static_files handler just set the status to NotFound and continued. Then your /foo/bar handler set the status to Ok again and everything lived in peace and harmony. Unfortunately though, there was no way to do things like custom error handler.

What do we want?

We want a request pipeline that looks more like this

Request -> MW:json_body_parser -> MW:foo -> MatchedRouteHandler -> MW:static_files
             |                        |              |               |
             > ErrorHandler           > EH            > EH            > EH    

This would make sure that the static_files middleware only runs if no other handler cut off the pipeline before.

I think the easiest solution to achieve this would be to make the router just a regular middleware that one can use with server.utilize(Nickel::router()). In order to get the pipeline from the picture above one could then do the boostrapping like this:

server.utilize(Nickel::json_body_parser())
server.utilize(Nickel::router())
server.utilize(Nickel::static_files("assets/"));

I think this is roughly what express does as well. They somehow also let you get away without adding a router explicitly but I didn't look into such details yet. I think we might be able to introduce that first and add some sugar later.

Thoughts? @bguiz @nielsle @janpantel

StaticFiles Middleware

Tried to setup my nickel.rs site on áēww.bennyklotz.at:3000

Setup steps:

$ cargo build --release
$ ./target/release/website &

After starting my binary in background everything worked fine, after I closed the ssh connection to my server and exited the shell "No data received" was returned.

Here my coresponding src/main.rs file and screenshots without StaticFilesHandler:

extern crate http;
extern crate nickel;

use std::io::net::ip::Ipv4Addr;
use nickel::{
    Nickel, Request, Response
};

fn page (_request: &Request, response: &mut Response) {
        response.set_content_type("html");
        response.send("<h1>Hello Rust!</h1>");
}

fn main() {
    let mut server = Nickel::new();

    // server.utilize(Nickel::static_files("assets/"));

    server.get("/rust", page);
    server.listen(Ipv4Addr(134, 119, 3, 19), 3000);
}

After exiting from the ssh shell it's still working:

http://s30.postimg.org/9g9k8qpkh/working_root.png
http://s27.postimg.org/9cxm4cp8z/working_rust.png

Here my coresponding src/main.rs and screenshots with StaticFilesHandler:

extern crate http;
extern crate nickel;

use std::io::net::ip::Ipv4Addr;
use nickel::{
    Nickel, Request, Response
};

fn page (_request: &Request, response: &mut Response) {
        response.set_content_type("html");
        response.send("<h1>Hello Rust!</h1>");
}

fn main() {
    let mut server = Nickel::new();

    server.utilize(Nickel::static_files("assets/"));

    server.get("/rust", page);
    server.listen(Ipv4Addr(134, 119, 3, 19), 3000);
}

Before exiting fom the ssh connection everything works:

http://postimg.org/image/5v8l4o79r/
http://postimg.org/image/e20kw8xcf/

After exiting from the ssh connection it doesn't work anymore:

http://postimg.org/image/76cppvist/
http://postimg.org/image/jm9fjmc4t/

Allow optional strongly typed handlers

It would be neat if we could optionally pass a struct to the handler function to have the request parameter / data automatically be deserialized into that struct. Just like ASP.NET MVC does it.

Something like this:

struct Person {
    first_name: String,
    last_name: String
}

fn user_handler (request: Request, response: &mut ResponseWriter, person:Person) {

};

Alternatively something like this may also be possible.

fn user_handler (request: Request, response: &mut ResponseWriter) {
    let first_name = request.data.first_name;
};

server.get<Person>("/user/:userid", user_handler);

This may or may not be possible with Rust. Needs investigating. People on IRC also pointed out that macros could be helpful here but I'm not sold yet. Would rather like to solve this with Generics and without macros. I'm sure @Kyjan would also be interested in this kind of things :)

Could not compile `anymap`.... nickel.rs make all

Could not compile anymap.

--- stderr
src/lib.rs:56:41: 56:44 error: explicit lifetime bound required
src/lib.rs:56 impl<'a> UncheckedAnyRefExt<'a> for &'a Any {
^~~
src/lib.rs:74:48: 74:51 error: explicit lifetime bound required
src/lib.rs:74 impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any {
^~~
src/lib.rs:111:31: 111:34 error: explicit lifetime bound required
src/lib.rs:111 data: HashMap<TypeId, Box, TypeIdHasher>,
^~~
error: aborting due to 3 previous errors

[root@localhost nickel]# rustc -v
rustc 0.12.0-pre-nightly (5419b2ca2 2014-08-29 22:16:20 +0000)

make don't work with more than one job

When make is invoked with -j2, deps and floor are being built simultaneously, which ends up with:

src/lib.rs:18:1: 18:19 error: can't find crate for `http`

Additionaly, make in subdirectories should not be invoked directly, but rather as $(MAKE). And also we can avoid rebuilding everything with each invocation of make.

But this failing with -j2 problem is the most important one, because I think it's really common case for people to have such flags as defaults.

Maybe concurrency?

How about spawning a task for each request? Rust has awesome Tasks built in. Otherwise 1 long request will cause freezing whole app.

Response sending status code?

Would you be open to have Response optionally send a status code in addition to the body text? That seems to be typical for many web frameworks in other languages.

implement route variables

Floor does currently not allow routes with variables such as /user/:userId.

We can take some inspiration from rustful which already handles such routes.

My plan is to stick as closely to the expressjs API as possible. However, since JS is weakly typed and Rust is strongly typed we might have to make some trade offs.

In expressjs you would simply access your userId variable like this:

function(request, response) {
    var userId = request.params.userId;
}

it should be fairly easy to come up with something somewhat similarish for us:

Solution 1:

fn sample_handler (request: &Request, response: &mut ResponseWriter) -> () {
    let userId = request.params.get("userId");
};

ideally we would love to have this:

Solution 2:

fn sample_handler (request: &Request, response: &mut ResponseWriter) -> () {
    let userId = request.params.userId
};

The latter might be even possible but I'm not as far down the road to answer it yet.

Allowing closures as handlers

I would like to define my handlers as a closure instead of a named function. For example:

router.get("/some/*/route", |_request: &Request, response: &mut Response| {
    response.send("foo");
});

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.