Git Product home page Git Product logo

naboris's Introduction

naboris

Simple, fast, minimalist web framework for OCaml/ReasonML built on httpaf and lwt.

https://naboris.dev

Build Status opam version 0.1.3

// ReasonML
let serverConfig: Naboris.ServerConfig.t(unit) = Naboris.ServerConfig.create()
  |> Naboris.ServerConfig.setRequestHandler((route, req, res) => switch(Naboris.Route.path(route)) {
    | ["hello"] =>
      res
        |> Naboris.Res.status(200)
        |> Naboris.Res.text(req, "Hello world!");
    | _ =>
      res
        |> Naboris.Res.status(404)
        |> Naboris.Res.text(req, "Resource not found.");
  });

Lwt_main.run(Naboris.listenAndWaitForever(3000, serverConfig));
/* In a browser navigate to http://localhost:3000/hello */
(* OCaml *)
let server_config: unit Naboris.ServerConfig.t = Naboris.ServerConfig.create ()
  |> Naboris.ServerConfig.setRequestHandler(fun route req res ->
    match (Naboris.Route.path route) with
      | ["hello"] ->
        res
          |> Naboris.Res.text req "Hello world!";
      | _ ->
        res
          |> Naboris.Res.status 404
          |> Naboris.Res.text req "Resource not found.";
  ) in


let _ = Lwt_main.run(Naboris.listenAndWaitForever 3000 server_config)
(* In a browser navigate to http://localhost:3000/hello *)

Pre 1.0.0 the API may be changing a bit. A list of these changes will be kept below.

Contents

Installation

Note

Naboris makes heavy use of Lwt. For better performance it is highly recommended (however optional) to also install conf-libev which will configure Lwt to run with the libev scheduler. If you are using esy you will have to install conf-libev using a special package.

conf-libev also requires that the libev be installed. This can usually be done via your package manager.

brew install libev

or

apt install libev-dev

opam

opam install naboris

esy

"@opam/naboris": "^0.1.3"

dune

(libraries naboris)

Scaffolding

For a basic Reason project

git clone [email protected]:shawn-mcginty/naboris-re-scaffold.git
cd naboris-re-scaffold
npm run install
npm run build
npm run start

For a basic OCaml project

git clone [email protected]:shawn-mcginty/naboris-ml-scaffold.git
cd naboris-ml-scaffold
npm run install
npm run build
npm run start

Development

Any help would be greatly appreciated! 👍

To run tests

esy install
npm run test

Breaking Changes

From To Breaking Change
0.1.2 0.1.3 secret argument added to all session configuration APIs.
0.1.0 0.1.1 ServerConfig.setSessionGetter changed to ServerConfig.setSessionConfig which also allows ~maxAge and ~sidKey to be passed in optionally.
0.1.0 0.1.1 All RequestHandler.t and Middleware.t now return Lwt.t(Res.t) instead of Lwt.t(unit)
0.1.0 0.1.1 Res.reportError now taxes exn as the first argument to match more closely the rest of the Res API.

naboris's People

Contributors

shawn-mcginty avatar brianshukwit avatar

Stargazers

Andrei-Paul Ionescu avatar  avatar Dimitris Mostrous avatar Lucas Alexander Floriani avatar Enieber Cunha avatar  avatar Julien Sagot avatar Pavel Volokitin avatar Nyi Nyi avatar Ghilia Weldesselasie avatar Evgeny avatar Andrej Dundovic avatar Henrik avatar Kai Klingenberg avatar Alex Pentland avatar Hyeseong Kim avatar Seif avatar joseferben avatar Tung Dao avatar Kamil Chmielewski avatar Jarrod avatar  avatar Sean Powell avatar Marcin Dziewulski avatar  avatar Ali Elshishini avatar  avatar  avatar Yuki Kodama avatar Michele Riva avatar Marcus Roberts avatar David Landa avatar WANG YEFU avatar Ashish Chandwani avatar Sebastian Porto avatar Cem Turan avatar Alfredo Beaumont avatar Craig Ferguson avatar Yusuf YILDIRIM avatar Tim Kendall avatar  avatar Jihchi Lee avatar Masanori Ogino avatar Florian Hammerschmidt avatar Travis Brady avatar Chad Armond avatar David Sancho avatar Erhan Gundogan avatar Adam Recvlohe avatar Seb Mondet avatar Scott Bell avatar Nikita avatar Rizo I avatar Ronan Le Hy avatar schinns avatar Alexis H. Munsayac avatar Ulugbek Abdullaev avatar Tom Ekander avatar Sora Morimoto avatar Yawar Amin avatar Alain Armand avatar  avatar Khalid Adil avatar Cédric Le Moigne avatar Karolis Narkevicius avatar Medson Oliveira avatar Juang Wiantoro avatar Gabriel Rubens Abreu avatar SelasieHanson avatar Bikal Lem avatar Marcello Seri avatar

Watchers

James Cloos avatar  avatar

naboris's Issues

Unix.EINVAL when serving static under load test

Fatal error: exception Unix.Unix_error(Unix.EINVAL, "select", "")

App code

let server_config: unit Naboris.ServerConfig.t = Naboris.ServerConfig.create ()
  |> Naboris.ServerConfig.setRequestHandler(fun route req res ->
    match ((Naboris.Route.meth route), (Naboris.Route.path route)) with
      | (Naboris.Method.GET, "static" :: static_path) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") static_path req res 
      | (Naboris.Method.GET, "/" :: []) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") ["/index.html"] req res
      | (Naboris.Method.GET, "" :: []) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") ["/index.html"] req res
      | _ ->
        res
          |> Naboris.Res.status 404
          |> Naboris.Res.text req "Resource not found.";
  )

let _ = Lwt_main.run begin
    Naboris.listenAndWaitForever 3000 server_config
end

vegeta targets file content
veg.txt
Request all files from static folder

GET http://localhost:3000/static/main-1f6385083dfd82fb9d36.css
GET http://localhost:3000/static/1.1f6385083dfd82fb9d36-build.js
GET http://localhost:3000/static/1f6385083dfd82fb9d36-build.js
GET http://localhost:3000/static/logo.png
GET http://localhost:3000

First test execution:

vegeta -cpus 1 attack -duration=20s -targets veg.txt | tee results.bin | vegeta report
Requests      [total, rate, throughput]  1000, 50.06, 50.05
Duration      [total, attack, wait]      19.979108875s, 19.976830593s, 2.278282ms
Latencies     [mean, 50, 95, 99, max]    4.25599ms, 2.605914ms, 6.75315ms, 12.32878ms, 160.517914ms
Bytes In      [total, mean]              134701400, 134701.40
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    100.00%
Status Codes  [code:count]               200:1000  

Second one:

vegeta -cpus 1 attack -duration=20s -targets veg.txt | tee results.bin | vegeta report
Requests      [total, rate, throughput]  1000, 50.05, 23.13
Duration      [total, attack, wait]      21.837638678s, 19.979902873s, 1.857735805s
Latencies     [mean, 50, 95, 99, max]    278.843405ms, 2.774347ms, 1.122188958s, 3.228599022s, 4.313448889s
Bytes In      [total, mean]              68024207, 68024.21
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    50.50%
Status Codes  [code:count]               0:495  200:505  
Error Set:
Get http://localhost:3000/static/1.1f6385083dfd82fb9d36-build.js: read tcp 127.0.0.1:62836->127.0.0.1:3000: read: connection reset by peer
Get http://localhost:3000/static/1f6385083dfd82fb9d36-build.js: read tcp 127.0.0.1:62838->127.0.0.1:3000: read: connection reset by peer
Get http://localhost:3000/static/main-1f6385083dfd82fb9d36.css: read tcp 127.0.0.1:62834->127.0.0.1:3000: read: connection reset by peer
Get http://localhost:3000/static/logo.png: dial tcp 0.0.0.0:0->[::1]:3000: connect: connection refused
Get http://localhost:3000: dial tcp 0.0.0.0:0->[::1]:3000: connect: connection refused
Get http://localhost:3000/static/main-1f6385083dfd82fb9d36.css: dial tcp 0.0.0.0:0->[::1]:3000: connect: connection refused
Get http://localhost:3000/static/1.1f6385083dfd82fb9d36-build.js: dial tcp 0.0.0.0:0->[::1]:3000: connect: connection refused
Get http://localhost:3000/static/1f6385083dfd82fb9d36-build.js: dial tcp 0.0.0.0:0->[::1]:3000: connect: connection refused

When -cpus more than 1 it always fails.

Seems like it is known issue of Lwt/OCaml ocsigen/lwt#529

add redirect

Should be easy to redirect a request to another uri

Static files OCaml example in readme

There are some typos in readme for OCaml static files example, but I was able to make it work like this:

let server_config: unit Naboris.ServerConfig.t = Naboris.ServerConfig.create ()
  |> Naboris.ServerConfig.setRequestHandler(fun route req res ->
    match ((Naboris.Route.meth route), (Naboris.Route.path route)) with
      | (Naboris.Method.GET, "static" :: static_path) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") static_path req res 
      | (Naboris.Method.GET, "/" :: []) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") ["/index.html"] req res
      | (Naboris.Method.GET, "" :: []) ->
        Naboris.Res.static (Sys.getcwd() ^ "/static") ["/index.html"] req res
      | _ ->
        res
          |> Naboris.Res.status 404
          |> Naboris.Res.text req "Resource not found.";
  )

let _ = Lwt_main.run begin
    Naboris.listenAndWaitForever 3000 server_config
end

By this index.html file from static folder is opened when gethttp://localhost:3000/ or http://localhost:3000.
Would be nice to have static folder by default or via parameter in ServerConfig for serving up static files. It can be useful for SPA.

Unify Res API

Change Res redirect API to take req res as first arguments like most of the Res API

Add middleware hooks and unify API

add hooks for middleware

maybe beforeRouteRequest?

beforeRouteRequest could be a fn that takes something like Route.t -> Req.t -> Res.t -> (Route.t -> Req.t -> Res.t -> (Route.t * Req.t * Res.t) Lwt.t) -> (Route.t * Req.t * Res.t) Lwt.t) meaning it's last arg is the routeRequest function, which should be called to continue the lifecycle of the request.

maybe afterRouteRequest? I'm not as sure about that one

weirdness w/ chrome

Sometimes requests from chrome will lock the entire Naboris server up. If using cURL or incognito chrome everything works fine. Or even after clearing cookies/cache from chrome it will work again. Something with the state of chrome after a while causes it to spin forever. Need to track this down.

Expose main lwt promise

Naboris.listen encapsulates the Lwt_main.runing of the promise. There should be a function to get the raw promise allowing the user to manage his own top level Lwt_main.run

Something like Naboris.listen_promise: int serverConfig -> 'a Lwt

Any performance numbers to share?

Naboris looks great, definitely much more user-friendly than other options out there.

Would be interested to see how Naboris performs on the techempower benchmark or even a simple hello world.

thanks

Better documentation

A real frontend web app for documentation, something like expressjs.com. Probably find a free host or a cheap one, and a domain.

OCaml example from readme

Hi!
I was trying to execute OCaml example from readme

(* OCaml *)
let server_config: unit Naboris.ServerConfig.t = Naboris.ServerConfig.create ()
  |> Naboris.ServerConfig.setRequestHandler(fun route req res ->
    match (Naboris.Route.path route) with
      | ["hello"] ->
        res
          |> Naboris.Res.text req "Hello world!";
      | _ ->
        res
          |> Naboris.Res.status 404
          |> Naboris.Res.text req "Resource not found.";
  ) in

Naboris.listenAndWaitForever 3000 server_config
(* In a browser navigate to http://localhost:3000/hello *)

but I didn't get success.

Here are the steps:

opam switch create . ocaml-base-compiler.4.09.0
eval $(opam env)
opam install merlin ocp-indent dune utop naboris
touch main.ml #paste OCaml example
touch dune #paste dune config
(executable
    (name main)
    (libraries naboris)
)
dune build main.exe

No errors.
Execute

dune exec ./main.exe 
# or
_build/default/main.exe 

nothing happens.
I'm beginner in OCaml, so maybe I did something wrong. I would appreciate any advice. Thanks.

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.