Giter Site home page Giter Site logo

opium's Introduction

Opium

Since version 0.19.0, Opium uses httpaf. The last version that used Cohttp can be found at https://github.com/rgrinberg/opium/tree/0.18.0

Executive Summary

Sinatra like web toolkit for OCaml based on httpaf & lwt

Design Goals

  • Opium should be very small and easily learnable. A programmer should be instantly productive when starting out.

  • Opium should be extensible using independently developed plugins. This is a Rack inspired mechanism borrowed from Ruby. The middleware mechanism in Opium is called Rock.

Installation

Stable

The latest stable version is available on opam

$ opam install opium

Master

$ opam pin add rock.~dev https://github.com/rgrinberg/opium.git
$ opam pin add opium.~dev https://github.com/rgrinberg/opium.git

Documentation

For the API documentation:

The following tutorials walk through various usecases of Opium:

For examples of idiomatic usage, see the ./examples directory and the simple examples below.

Examples

Assuming the necessary dependencies are installed, $ dune build @example will compile all examples. The binaries are located in _build/default/example/.

You can execute these binaries directly, though in the examples below we use dune exec to run them.

Hello World

Here's a simple hello world example to get your feet wet:

$ cat hello_world.ml

open Opium

module Person = struct
  type t =
    { name : string
    ; age : int
    }

  let yojson_of_t t = `Assoc [ "name", `String t.name; "age", `Int t.age ]

  let t_of_yojson yojson =
    match yojson with
    | `Assoc [ ("name", `String name); ("age", `Int age) ] -> { name; age }
    | _ -> failwith "invalid person json"
  ;;
end

let print_person_handler req =
  let name = Router.param req "name" in
  let age = Router.param req "age" |> int_of_string in
  let person = { Person.name; age } |> Person.yojson_of_t in
  Lwt.return (Response.of_json person)
;;

let update_person_handler req =
  let open Lwt.Syntax in
  let+ json = Request.to_json_exn req in
  let person = Person.t_of_yojson json in
  Logs.info (fun m -> m "Received person: %s" person.Person.name);
  Response.of_json (`Assoc [ "message", `String "Person saved" ])
;;

let streaming_handler req =
  let length = Body.length req.Request.body in
  let content = Body.to_stream req.Request.body in
  let body = Lwt_stream.map String.uppercase_ascii content in
  Response.make ~body:(Body.of_stream ?length body) () |> Lwt.return
;;

let print_param_handler req =
  Printf.sprintf "Hello, %s\n" (Router.param req "name")
  |> Response.of_plain_text
  |> Lwt.return
;;

let _ =
  App.empty
  |> App.post "/hello/stream" streaming_handler
  |> App.get "/hello/:name" print_param_handler
  |> App.get "/person/:name/:age" print_person_handler
  |> App.patch "/person" update_person_handler
  |> App.run_command
;;

compile and run with:

$ dune exec examples/hello_world.exe &

then call

curl http://localhost:3000/person/john_doe/42

You should see the greeting

{"name":"john_doe","age":42}

Middleware

The two fundamental building blocks of opium are:

  • Handlers: Request.t -> Response.t Lwt.t
  • Middleware: Rock.Handler.t -> Rock.Handler.t

Almost all of opium's functionality is assembled through various middleware. For example: debugging, routing, serving static files, etc. Creating middleware is usually the most natural way to extend an opium app.

Here's how you'd create a simple middleware turning away everyone's favourite browser.

open Opium

module Reject_user_agent = struct
  let is_ua_msie =
    let re = Re.compile (Re.str "MSIE") in
    Re.execp re
  ;;

  let m =
    let filter handler req =
      match Request.header "user-agent" req with
      | Some ua when is_ua_msie ua ->
        Response.of_plain_text ~status:`Bad_request "Please upgrade your browser"
        |> Lwt.return
      | _ -> handler req
    in
    Rock.Middleware.create ~filter ~name:"Reject User-Agent"
  ;;
end

let index_handler _request = Response.of_plain_text "Hello World!" |> Lwt.return

let _ =
  App.empty
  |> App.get "/" index_handler
  |> App.middleware Reject_user_agent.m
  |> App.cmd_name "Reject UA"
  |> App.run_command
;;

Compile with:

$ dune build example/simple_middleware/main.ml

Here we also use the ability of Opium to generate a cmdliner term to run your app. Run your executable with --help to see the options that are available to you. For example:

# run in debug mode on port 9000
$ dune exec example/simple_middleware/main.exe -- -p 9000 -d

opium's People

Contributors

actionshrimp avatar andrebauer avatar anuragsoni avatar avsm avatar bbrietzke avatar bramford avatar c-cube avatar cuihtlauac avatar favo02 avatar github-actions[bot] avatar gitter-badger avatar glennsl avatar hcarty avatar joprice avatar joseferben avatar malthe avatar mattjbray avatar neilparikh avatar nymphium avatar pkel avatar reynir avatar rgrinberg avatar rizo avatar roddyyaga avatar rvantonder avatar rymdhund avatar seveneng avatar shonfeder avatar tmattio avatar venator 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

opium's Issues

Can we simulate slow internet connection by delay opium's response?

Normally, we wrote code to response as soon as possible, for example:

let getid req =
  let uri = Request.uri req in
  let ua = Option.value (Uri.get_query_param uri "ua") ~default:"na"
  in App.string_of_body_exn req >>| fun rbody ->
  print_endline ("body: "^rbody^", param:"^ua);
  respond (`String (rbody^ua))

In some situations we need to simulate slow internet connection by delay the response, I was wondering can we do that in opium?

DSL for routes

I was looking at Opium as it's currently works and wondering if some sort of DSL for routes would be useful. It would basically provide a small layer of syntactic sugar that would boil down to exactly what it is now, just allowing to define routes in line easier. My main modivation is to try to get it closer to Sinatra's DSL.

rough example:

let middleware = def_middleware [ auth, capitalizer ]

let routes = def_routes [
   GET "hello/:name" print_name,
   POST "hello/:name post_name
]

let () =
    App.simple
    ~middleware
    ~routes

I apologize in advance if there exists something in the code base that's already like this. I'm not very familiar with it yet.

Alternative mimetype lookup

I need to return application/javascript; charset=utf-8 instead of the default for *.js files.

(Since my source files include non-ascii characters.)

Should Static_serve.m take an optional mimetypes module that allows a custom lookup?

`splat` returns unescaped strings

let foo =
  get "/*" begin fun req ->
    Lwt_io.eprintl (String.concat "/" (splat req)) >>= fun _ -> ...
  end

outputs not #a/b but %23a/b for a request /%23a/b. Is this as you expected?

Unable to build against latest master

OCaml 4.02.3 on OSX with opam pin add opium --dev-repo:

Trying to compile this code:

open Opium.Std

let () =
  App.empty
  |> get "/" (fun _req -> `String "Hello world" |> respond')
  |> App.cmd_name "HW"
  |> App.run_command

I get:

$ ocamlbuild -use-ocamlfind -package opium.unix o.native
+ ocamlfind ocamlopt -linkpkg -package opium.unix o.cmx -o o.native
File "_none_", line 1:
Error: No implementations provided for the following modules:
         Cohttp_lwt_body referenced from /Users/hcarty/.opam/pipeline/lib/opium/opium_kernel.cmxa(Opium_misc),
           /Users/hcarty/.opam/pipeline/lib/opium/opium_kernel.cmxa(Opium_rock),
           /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_app)
         Lwt_log referenced from /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_debug),
           /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_app)
         Cohttp_lwt_unix referenced from /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_app),
           /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_static_serve)
         Lwt_main referenced from /Users/hcarty/.opam/pipeline/lib/opium/opium.cmxa(Opium_app)
Command exited with code 2.

Problem with type Rock.Handler.t

Hello,

I must be missing something but the following code:

open Core.Std
open Async.Std
open Opium.Std

let hello =
  get "/"
  (fun req -> `String "Hello World" |> respond')

let () =
  App.empty
  |> hello
  |> App.command
  |> Command.run

gives me an error:

File "server.ml", line 33, characters 2-48:
Error: This expression should not be a function, the expected type is
Rock.Handler.t

But Rock.Handler.t seems to be a functional type, from its definition in rock/rock.mli.
When I put an annotation like

((fun req -> `String "Hello World" |> respond') : Rock.Handler.t)

I get:

Error: This expression has type
         Opium.Std.Rock.Handler.t =
           Opium.Std.Rock.Request.t ->
           Opium.Std.Rock.Response.t Async.Std.Deferred.t
       but an expression was expected of type Rock.Handler.t

So it seems like Rock.Handler.t is different from Opium.Std.Rock.Handler.t, but I don't understand why.

Compiling against CoHttp 0.12.0

When compiling against cohttp v0.12.0 ( lastest from the mirage-dev repository ), I am getting the following compile error when running make:

File "_tags", line 52, characters 20-28:
Warning: the tag "pkg_pcre" is not used in any flag declaration, so it will have no effect; it may be a typo. Otherwise use `mark_tag_used` in your myocamlbuild.ml to disable this warning.
+ /Users/brietzkeb/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -I rock -package async -package cohttp.async -package core -package cow -syntax camlp4o -package cow.syntax -package fieldslib -syntax camlp4o -package fieldslib.syntax -package humane_re -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -thread -I opium -I rock -o opium/router.cmo opium/router.ml
File "opium/router.ml", line 57, characters 39-55:
Error: This expression has type Cohttp.Code.meth
       but an expression was expected of type
         [< `DELETE | `GET | `HEAD | `OPTIONS | `PATCH | `POST | `PUT ]
       The second variant type does not allow tag(s) `Other
Command exited with code 2.
Compilation unsuccessful after building 33 targets (0 cached) in 00:00:03.
E: Failure("Command ''/usr/local/bin/ocamlbuild' rock/opium_rock.cma rock/opium_rock.cmxa rock/opium_rock.a rock/opium_rock.cmxs opium/opium.cma opium/opium.cmxa opium/opium.a opium/opium.cmxs -tag debug' terminated with error code 10")
make: *** [all] Error 1

Opium and opium_rock both define a module named Rock

Hello,

I'm trying to compile my first app using Opium. I use ocamlfind to compile:

ocamlfind ocamlopt -o app -package opium -linkpkg -linkall ...

I get the following message:

Error: Files ..../.opam/4.01.0/lib/opium/opium.cmxa
       and ..../.opam/4.01.0/lib/opium_rock/rock.cmxa
       both define a module named Rock

I don't know about oasis/ocamlfind machinery, so I can't fix the problem.

Can't install opium on arm =(

Hello, I'm trying to run my litle website writen with opium on my orange pi (clone of raspberry pi), everything works well on my x86 laptop, but I can't install opium through opam on arm (orange pi):

$ opam install opium
Your request can't be satisfied:
  - No package matches opium.

No solution found, exiting
$ opam search opium
# Existing packages for 4.03.0:
opium  --  Sinatra like web toolkit based on Lwt + Cohttp

I've already successfully installed lwt, cohttp, conf-libev, camlp4. Could you please help me - what is the reason and where should I look to investigate the problem?

Notes as I build a site with Opium

I hope you don't mind if I maintain a little issue list that I'm running across as I make my Opium site. I'll submit pull requests for these right after the site is done and if you think they are good ideas. Will edit this as I go along.

  • not clear from docs how to do more modern auth middleware which redirects to a login page and uses session cookies. This requires overriding the handler with a login-specific one.
  • helper function to do a HTTP redirect directly as a handler shortcut would be useful.
  • I've got a little REST module that glues together get/put/delete handlers (via a higher order rest db get put del base = base |> get db |> del db |> put db interface that also passes a database handle into each of the sub handlers.
  • What is the difference between Opium and Rock? App can be converted from one to the other, but I'm still not entirely sure (aside from that Rock is middleware and lower level?)
  • cant get cookies working. I added App.middleware Cookie.m but Cookie.get in a subsequent middleware fails. Can middlewares depend on previous ones setting the environment like this? Cookies work fine via manually adding them to the Rock.Request.headers using Cohttp's header generation directly.
  • since the move to Lwt, the README is out of date and still refers to Command instead of Cmdliner.
  • Lwt_log debugging is annoying to get working -- need to set LWT_DEBUG env in addition to the -d flag to the Opium app (I think). Also would be nice to know how to activate the middleware tracing. (#27)
  • HTTP headers get overwritten for non-String responses (#29)
  • On a more positive note, Opium is really fun to work with :)

JavaScript / BuckleScript / Reason support

So, this is more of a tracking topic than an immediately-relevant feature-request; but I'm curious what would be required to abstract opium away from cohttp, and make it eventually compileable to JavaScript via BuckleScript.

It sounds like this is on your mind already, based on your choice of LWT / this comment, so that's exciting!

Aside from splitting out the cohttp requirement so it can run on top of JavaScript / Node.js APIs, the biggest blocker right now seems to be the heavy dependence on PPX extensions. I'm assuming this is an inflexible requirement? If so, maybe an explicit ‘I'd love to support BuckleScript and Reason, but we need support for idiomatic OCaml code, which means we need PPXes.’ from you is something I can take back to the BuckleScript team, and start to convince them to relax their position against PPX. (=

Let me know if this is on the roadmap!

Using ~f for request handler might be better syntactically

This is a nitpick, but in case you have not thought about it, you can get rid of begin-end block here if you use a labelled parameter:

let h =
  put "/hello/:x/from/:y" begin fun req ->
    (* ... *)
  end

With labelled parameter (could be ~f or ~action):

let h =
  put "/hello/:x/from/:y" ~f:fun req ->
    (* ... *)

This is a quirk of OCaml syntax that I discovered recently.

Unbound record field Server.callback in `rock/opium_rock.ml` on OSX

Log:

#=== ERROR while installing opium.0.11.0 ======================================#
# opam-version 1.2.0
# os           darwin
# command      make build
# path         /Users/dch/.opam/system/build/opium.0.11.0
# compiler     system (4.02.1)
# exit-code    2
# env-file     /Users/dch/.opam/system/build/opium.0.11.0/opium-62776-c61e7b.env
# stdout-file  /Users/dch/.opam/system/build/opium.0.11.0/opium-62776-c61e7b.out
# stderr-file  /Users/dch/.opam/system/build/opium.0.11.0/opium-62776-c61e7b.err
### stdout ###
# ...[truncated]
# /Users/dch/.opam/system/bin/ocamlfind ocamldep -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -modules rock/opium_rock.mli > rock/opium_rock.mli.depends
# /Users/dch/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -thread -I rock -o rock/opium_rock.cmi rock/opium_rock.mli
# /Users/dch/.opam/system/bin/ocamlfind ocamldep -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -modules rock/opium_rock.ml > rock/opium_rock.ml.depends
# /Users/dch/.opam/system/bin/ocamlfind ocamldep -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -modules rock/opium_misc.ml > rock/opium_misc.ml.depends
# /Users/dch/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -thread -I rock -o rock/opium_misc.cmo rock/opium_misc.ml
# /Users/dch/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -thread -I rock -o rock/opium_rock.cmo rock/opium_rock.ml
# + /Users/dch/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -package cohttp.lwt -package core -package fieldslib -syntax camlp4o -package fieldslib.syntax -package lwt -package lwt.unix -package sexplib -syntax camlp4o -package sexplib.syntax -package threads -thread -I rock -o rock/opium_rock.cmo rock/opium_rock.ml
# File "rock/opium_rock.ml", line 116, characters 6-21:
# Error: Unbound record field Server.callback
# Command exited with code 2.
### stderr ###
# W: Cannot find source file matching module 'opium' in library opium
# E: Failure("Command ''/usr/local/bin/ocamlbuild' rock/opium_rock.cma rock/opium_rock.cmxa rock/opium_rock.a rock/opium_rock.cmxs opium/opium.cma opium/opium.cmxa opium/opium.a opium/opium.cmxs -tag debug' terminated with error code 10")
# make: *** [build] Error 1

Overriding a static path

I'd like to have a default middleware that attempts to find a static file if no other dynamic override is present. E.g.:

  |> App.middleware (Middleware.static ~local_path:"../html" ~uri_prefix:"/")
  |> Dynamic.generate_index task

In this case, the / Uri prefix is immediately served as a Not_found -- it looks like the Dynamic registration for / is being ignored despite it being passed to the next handler by the static middleware. Is this intentional? I'm working around it by specifically registering multiple static servers for images/ css/ etc in my site.

core_kernel dependency?

Just wondering if the dependency towards core_kernel is really necessary? Seems that you only need an universal map implementation.

Lwt Support

If anybody wants to see this, leave a message here =)

Make a response helper for serving static files

Currently, AFAIK, we can only serve static files in Opium by using the static middleware. If we want to, say, serve a specific file on a specific route (examples: GET / => index.html, response code 404 => 404.html), we have to write the code ourselves.

But I guess we could share the code from this file and use it as a helper.

Wouldn't it be nice?

Encoding error on get cookie?

Testing code

open Opium.Std

let all_cookies = get "/cookies" begin fun req ->
  let cookies = req
                |> Cookie.cookies
                |> List.map ~f:(fun (k,v) -> k ^ "=" ^ v)
                |> String.concat "\n"
  in
  `String (Printf.sprintf "<pre>%s</pre>" cookies) |> respond |> return
end

let app = 
  App.empty
  |> all_cookies
  |> middleware Cookie.m

let _ =
  app |> App.run_command

Compile and run as

corebuild -pkg opium.unix get_cookie.native ; ./get_cookie.native -p 9001 -d

Testing by cUrl:

$ curl -v --cookie "name=li" http://127.0.0.1:9001/cookies       
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 9001 (#0)
> GET /cookies HTTP/1.1
> Host: 127.0.0.1:9001
> User-Agent: curl/7.43.0
> Accept: */*
> Cookie: name=li
>
< HTTP/1.1 200 OK
< content-length: 17
<
* Connection #0 to host 127.0.0.1 left intact
<pre>���=��</pre>~                                                                                                           ⋊> 

It has been changed to ��.

A way to add options to command line

It would be nice to have a way to add command line options handled by Command.run, i.e. returned by App.command. Something like App.add_command_option.

Error installing in osx

I was trying to install on osx and I go this error I tried to pin this version but no luck

~/c/real_world_ocaml ❯❯❯ opam pin add opium 0.15.1                                                   ⏎ master ✱ ◼
[NOTE] opium is currently version-pinned to 0.15.0.
Proceed ? [Y/n] y
opium is now version-pinned to 0.15.1

[opium] https://github.com/rgrinberg/opium/archive/v0.15.1.tar.gz downloaded

opium needs to be installed.
Your request can't be satisfied:
  - opium.0.15.1 is not available because the package is pinned to version 0.15.1.

No solution found, exiting
[NOTE] Pinning command successful, but your installed packages may be out of sync.
~/c/real_world_ocaml ❯❯❯ opam install opium                                                          ⏎ master ✱ ◼

=-=- Synchronising pinned packages =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫
Your request can't be satisfied:
  - opium is not available because the package is pinned to version 0.15.1.

No solution found, exiting

Support for yojson?

ppx_deriving_yojson is pretty useful. Ezjsonm and jsonm don't seem to have equivalents. Would it be possible to somehow functorize over the json implementation? Obviously I can just pass yojson-as-string but this feels a bit hacky.

Decouple `App.run` and `Lwt_main.run`

I've got some Lwt actions to run in order to setup my handlers (a db connection to Irmin). It would be useful to decouple App.run from actually doing Lwt_main.run, as that would let me compose a few initialisation actions and then run Lwt_main.run on the result.

can't build hello_world

pinned opium to dev version per instructions on #48.

Per Readme, I issue the ocamlbuild instruction:

$ ocamlbuild -pkg opium.unix hello_world.native
Warning: tag "package" does not expect a parameter, but is used with parameter "opium.unix"
/usr/bin/ocamlc.opt -c -I /home/pnathan/.opam/4.02.3/lib/base64 -I /home/pnathan/.opam/4.02.3/lib/bytes -I /home/pnathan/.opam/4.02.3/lib/cmdliner -I /home/pnathan/.opam/4.02.3/lib/cohttp -I /home/pnathan/.opam/4.02.3/lib/conduit -I /home/pnathan/.opam/4.02.3/lib/cstruct -I /home/pnathan/.opam/4.02.3/lib/ezjsonm -I /home/pnathan/.opam/4.02.3/lib/fieldslib -I /home/pnathan/.opam/4.02.3/lib/hex -I /home/pnathan/.opam/4.02.3/lib/hmap -I /home/pnathan/.opam/4.02.3/lib/ipaddr -I /home/pnathan/.opam/4.02.3/lib/jsonm -I /home/pnathan/.opam/4.02.3/lib/lwt -I /home/pnathan/.opam/4.02.3/lib/magic-mime -I /home/pnathan/.opam/4.02.3/lib/ocaml -I /home/pnathan/.opam/4.02.3/lib/ocaml/compiler-libs -I /home/pnathan/.opam/4.02.3/lib/ocplib-endian -I /home/pnathan/.opam/4.02.3/lib/opium -I /home/pnathan/.opam/4.02.3/lib/ppx_core -I /home/pnathan/.opam/4.02.3/lib/ppx_deriving -I /home/pnathan/.opam/4.02.3/lib/ppx_driver -I /home/pnathan/.opam/4.02.3/lib/ppx_fields_conv -I /home/pnathan/.opam/4.02.3/lib/ppx_optcomp -I /home/pnathan/.opam/4.02.3/lib/ppx_sexp_conv -I /home/pnathan/.opam/4.02.3/lib/ppx_type_conv -I /home/pnathan/.opam/4.02.3/lib/re -I /home/pnathan/.opam/4.02.3/lib/sexplib -I /home/pnathan/.opam/4.02.3/lib/stringext -I /home/pnathan/.opam/4.02.3/lib/uri -I /home/pnathan/.opam/4.02.3/lib/uutf -o hello_world.cmo hello_world.ml
+ /usr/bin/ocamlc.opt -c -I /home/pnathan/.opam/4.02.3/lib/base64 -I /home/pnathan/.opam/4.02.3/lib/bytes -I /home/pnathan/.opam/4.02.3/lib/cmdliner -I /home/pnathan/.opam/4.02.3/lib/cohttp -I /home/pnathan/.opam/4.02.3/lib/conduit -I /home/pnathan/.opam/4.02.3/lib/cstruct -I /home/pnathan/.opam/4.02.3/lib/ezjsonm -I /home/pnathan/.opam/4.02.3/lib/fieldslib -I /home/pnathan/.opam/4.02.3/lib/hex -I /home/pnathan/.opam/4.02.3/lib/hmap -I /home/pnathan/.opam/4.02.3/lib/ipaddr -I /home/pnathan/.opam/4.02.3/lib/jsonm -I /home/pnathan/.opam/4.02.3/lib/lwt -I /home/pnathan/.opam/4.02.3/lib/magic-mime -I /home/pnathan/.opam/4.02.3/lib/ocaml -I /home/pnathan/.opam/4.02.3/lib/ocaml/compiler-libs -I /home/pnathan/.opam/4.02.3/lib/ocplib-endian -I /home/pnathan/.opam/4.02.3/lib/opium -I /home/pnathan/.opam/4.02.3/lib/ppx_core -I /home/pnathan/.opam/4.02.3/lib/ppx_deriving -I /home/pnathan/.opam/4.02.3/lib/ppx_driver -I /home/pnathan/.opam/4.02.3/lib/ppx_fields_conv -I /home/pnathan/.opam/4.02.3/lib/ppx_optcomp -I /home/pnathan/.opam/4.02.3/lib/ppx_sexp_conv -I /home/pnathan/.opam/4.02.3/lib/ppx_type_conv -I /home/pnathan/.opam/4.02.3/lib/re -I /home/pnathan/.opam/4.02.3/lib/sexplib -I /home/pnathan/.opam/4.02.3/lib/stringext -I /home/pnathan/.opam/4.02.3/lib/uri -I /home/pnathan/.opam/4.02.3/lib/uutf -o hello_world.cmo hello_world.ml
File "hello_world.ml", line 1, characters 0-1:
Error: /home/pnathan/.opam/4.02.3/lib/ocaml/pervasives.cmi
is not a compiled interface
Command exited with code 2.

Help? I was hoping to use this as my starter project to start using OCaml, so the error message is (1) intimidating and (2) ... suggesting that there's something else problematic besides my compile?

before 0.15

build is broken for me (because of fieldslib.syntax), and I think it would be nice to get rid of camlp4 (is there a ppx replacement for fieldslib?).

Also, hosting doc on github pages should be easy, I can submit a PR if you want (once I find how to generate the doc!)

build failed for 0.14.0

[vagrant@localhost ~]$ opam install opium
The following actions will be performed:
  ∗  install opium 0.14.0

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[opium] Archive in cache

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[ERROR] The compilation of opium failed at "make".
Processing  1/1: [opium: ocamlfind remove]
#=== ERROR while installing opium.0.14.0 ======================================#
# opam-version 1.2.2
# os           linux
# command      make
# path         /home/vagrant/.opam/4.02.3/build/opium.0.14.0
# compiler     4.02.3
# exit-code    2
# env-file     /home/vagrant/.opam/4.02.3/build/opium.0.14.0/opium-23954-5f1023.env
# stdout-file  /home/vagrant/.opam/4.02.3/build/opium.0.14.0/opium-23954-5f1023.out
# stderr-file  /home/vagrant/.opam/4.02.3/build/opium.0.14.0/opium-23954-5f1023.err
### stdout ###
# [...]
# --- Checking for ocamlfind... (found /home/vagrant/.opam/4.02.3/bin/ocamlfind)
# --- Checking for ocamlc.opt... (found /home/vagrant/.opam/4.02.3/bin/ocamlc.opt)
# --- Checking for ocamlopt.opt... (found /home/vagrant/.opam/4.02.3/bin/ocamlopt.opt)
# --- Checking whether ocamlc understands the "z" warnings... (yes)
# *** omake: finished reading OMakefiles (0.03 sec)
# --- Checking if ocamldep understands -modules... (yes)
# - build _build/opium opium_static_serve.o
# + ocamlfind ocamlopt -syntax camlp4o -package core_kernel,cohttp.lwt,camlp4,fieldslib.syntax,sexplib.syntax,ezjsonm,cmdliner -g -bin-annot -thread -I . -I ../opium_rock -c opium_static_serve.ml
# *** omake: 46/108 targets are up to date
# *** omake: failed (1.91 sec, 6/6 scans, 10/15 rules, 59/155 digests)
### stderr ###
# [...]
# *** omake: warning: stdout is not a tty, disabling the progress bar
#    (use --progress to override).
# File "opium_static_serve.ml", line 24, characters 20-37:
# Error: Unbound module Magic_mime
# *** omake: targets were not rebuilt because of errors:
#    _build/opium/opium_static_serve.cmx
#       depends on: _build/opium/opium_static_serve.ml
#    _build/opium/opium_static_serve.o
#       depends on: _build/opium/opium_static_serve.ml
# make: *** [build] Error 2



=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The following actions failed
  ∗  install opium 0.14.0
No changes have been performed

about the name (aka: bikeshedding)

First off I just want to thank you so much for this wonderful product that you all have been creating. It makes me so happy to see a viable way to make web apps in OCaml. Keep up the good work.

This is totally bikesheading on my part but I find it odd to name this project after a drug. Is there a reason for this? I feel like a drug theme is not exactly the most professional. Naturally the name of somthing isn't the most important thing but I feel it will matter in the marketing aspect. Just my two cents.

Is opium sanitising paths?

Say one does:

let print_ymd =
  get "/:title"
      begin fun req ->
      let filename = param req "title" in
      let filepath = "dir/" ^ filename in
      `Html load_file filepath |> respond'
      end

There could be an issue with a malicious request containing ../../. But using telnet I noticed that opium seems to ignore the first ../../. Is that normal behaviour?

Example does not work on print_param route

When running the base example, the second route is running correctly but I am getting a 404 Not Found on the first route.

Screenshot of my "debugging session" joined:

opium_bug

Mirage compatibility?

I haven't tried to use Opium with my Mirage site for some time now, but I'm curious if it would work? I'd like to drop my current janky routing.

Cmdliner composability

Opium has Cmdliner term/args for convenience but these are no longer useful when a user wants their own CLI. Perhaps we can still expose the terms/args Opium defines to make it easier for people to construct their own CLI's.

Example hello_world.ml doesn't compile

Hi,

When I try to build the example hello_world.ml, I get the following output:

ocamlfind ocamldep -syntax camlp4o -package opium -package bin_prot.syntax -package sexplib.syntax,comparelib.syntax,fieldslib.syntax,variantslib.syntax -package core -modules hello_world.ml > hello_world.ml.depends

  • ocamlfind ocamldep -syntax camlp4o -package opium -package bin_prot.syntax -package sexplib.syntax,comparelib.syntax,fieldslib.syntax,variantslib.syntax -package core -modules hello_world.ml > hello_world.ml.depends
    File "hello_world.ml", line 12, characters 21-25:
    Failure: "Pa_type_conv: "json" is not a supported type generator. (supported generators: bin_io, variants, compare, of_sexp, bin_read, bin_type_class, sexp_of, sexp, fields, bin_write)"
    Preprocessing error on file hello_world.ml
    Error while running external preprocessor
    Command line: camlp4 '-I' '/usr/local/lib/ocaml/camlp4' '-I' '/Users/cuicui/.opam/system/lib/type_conv' '-I' '/usr/local/lib/ocaml' '-I' '/usr/local/lib/ocaml' '-I' '/Users/cuicui/.opam/system/lib/bin_prot' '-I' '/Users/cuicui/.opam/system/lib/bin_prot' '-I' '/Users/cuicui/.opam/system/lib/sexplib' '-I' '/Users/cuicui/.opam/system/lib/sexplib' '-I' '/Users/cuicui/.opam/system/lib/comparelib' '-I' '/Users/cuicui/.opam/system/lib/comparelib' '-I' '/Users/cuicui/.opam/system/lib/fieldslib' '-I' '/Users/cuicui/.opam/system/lib/fieldslib' '-I' '/Users/cuicui/.opam/system/lib/variantslib' '-I' '/Users/cuicui/.opam/system/lib/variantslib' '-parser' 'o' '-parser' 'op' '-printer' 'p' 'pa_type_conv.cma' 'unix.cma' 'bigarray.cma' 'bin_prot.cma' 'pa_bin_prot.cma' 'sexplib.cma' 'pa_sexp_conv.cma' 'comparelib.cma' 'pa_compare.cma' 'fieldslib.cma' 'pa_fields_conv.cma' 'variantslib.cma' 'pa_variants_conv.cma' 'hello_world.ml' > /var/folders/k2/wdwtr40n3f1_3kvys86y6wrm0000gn/T/ocamlpp292e5b

Command exited with code 2.

I used the command written in the README.md:

corebuild -pkg opium hello_world.native

Is this the best practice to extract the get parameter?

I've read the code in the examples folder, I found all the example put its parameter in the absolute path.

I want to extract the get parameter such as http://localhost:9001/gid?ua=haha, and I found a way

let getid = get "/gid" (fun req ->
  let uri = Request.uri req in
  let ua = Uri.get_query_param uri "ua" in
  match ua with
  | Some cont -> begin `String cont |> respond' end
  | None -> begin `String "none" |> respond' end)

Well, it works as I expected, but I'm wondering if it's the best practice, because if there are many get arguments, the pattern matching code would be not elegant.

try to change port in app code

please what am I doing wrong please?

I am new in OCaml and playing with opium
I am trying to change port in code like that

let app =    
        App.empty   
        |> middleware uppercase   
        |> home
        |> hello
        |> vers
        |> App.cmd_name "demo1"
let _ = 
    let localport = 8000 in 
    printf "Run server on port %d \n" localport ; flush stdout ;
    app |> App.port localport |>  App.run_command

but I got

./demo1.native -v
Run server on port 8000 
demo1.native: main: Running on port: 3000
  • Do you have a mailing list for opium question/request please ?

thanks

Readme.cpp.md

I'm not sure what this file is for (I was hoping to do a pull request for some documentation)

Also, if I where to write more comprehensive documentation, is there a place you would like it to be?

Documentation on how routes are prioritized

Given a modified version of the README example:

open Opium.Std

let print_param = get "/hello/:name" begin fun req ->
    `String ("Hello " ^ param req "name") |> respond'
  end

let print_other = get "**" begin fun req ->
    `String "Hello everyone else" |> respond'
  end

let () =
  App.empty
  (* Order matters! *)
  |> print_other
  |> print_param
  (* Order matters! *)
  |> App.run_command

With this code I see "Hello test" if I GET /hello/test and "Hello everyone else" if I use other paths. However, if I swap the lines between the comments above then the only response "Hello everyone else". OCaml 4.02.3 + opium 0.13.3 + cohttp 0.19.3 from opam.

I'm not sure what the right approach is here. It's useful to be able to have specific routes with an catch-all to handle all other requests. It would be useful if the right way to do this were shown in the README or somewhere similarly visible.

How to properly shut down an opium application?

My opium application needs to do some work before shutting down, so I can't just kill it. Unfortunately the Exit exception is caught by opium's main loop.

Is there a proper way to exit an app?

Logo

It sounds stupid but logos can actually help attract people to a project. I think it helps make the project seem like it has people that love and support it. However I have little expertiese in making a logo but I threw some together on http://www.squarespace.com/logo

Here's some ideas:

opium-logo 1

opium-logo 2

opium-logo 3

Installation error on Arch Linux

Opium isn't installing because libfam.so.0 is missing. Should that be in depext?

The following actions will be performed:
  ∗  install opium 0.15.0

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[opium] Archive in cache

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[ERROR] The compilation of opium failed at "make install".
Processing  1/1: [opium: ocamlfind remove]
#=== ERROR while installing opium.0.15.0 ======================================#
# opam-version 1.2.2
# os           linux
# command      make install
# path         .opam/4.03.0/build/opium.0.15.0
# compiler     4.03.0
# exit-code    2
# env-file     .opam/4.03.0/build/opium.0.15.0/opium-27414-d2c37b.env
# stdout-file  .opam/4.03.0/build/opium.0.15.0/opium-27414-d2c37b.out
# stderr-file  .opam/4.03.0/build/opium.0.15.0/opium-27414-d2c37b.err
### stderr ###
# omake: error while loading shared libraries: libfam.so.0: cannot open shared object file: No such file or directory
# make: *** [Makefile:21: install] Error 127

Logging doesn't work

My toy website is something like this:

let index = get "/" (fun _ -> `Html index_html |> respond')

let _ = App.empty |> App.port 3333 |> index |> App.run_command

I run it like this:

$ dune exec -- bin/lkl_web_server.exe --help
$ dune exec -- bin/lkl_web_server.exe -v

The first command works and displays me the Opium help.
The second one works in the sense that it launches the webserver and it serves the web page.
But the -v option doesn't seem to have any effect. It doesn't log anything to the console I'm calling it from, or to any file as it seems.

Is there any way to load html files?

Sometimes I only want to display some html files. In Racket, I use web-server/templates library's function include-template.

I'm wondering whether opium support loading html files.

Expose the new on_exn hook in cohttp_lwt_unix?

Cohttp_lwt_unix recently added an on_exn hook: https://github.com/mirage/ocaml-cohttp/pull/518/files which might be a useful addition to Opium. The use case I have in mind is long polling, where the Opium_rock.Service is a long-running Lwt thread. If the client closes the connection, that thread should be cancelled.

I could probably manage a PR, but it would change some module signatures so I thought I would check with you first. Would you be open to exposing on_exn, and if so where?

Installation error on OSX

Opium isn't installing, but I don't know how to resolve ...

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫
[opium] https://github.com/rgrinberg/opium.git already up-to-date

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫
[ERROR] The compilation of opium failed at "make install".
Processing  1/1: [opium: ocamlfind remove]
#=== ERROR while installing opium.0.15.0 ======================================#
# opam-version 1.2.2
# os           darwin
# command      make install
# path         .opam/system/build/opium.0.15.0
# compiler     system (4.03.0)
# exit-code    2
# env-file     .opam/system/build/opium.0.15.0/opium-79612-d8a4ae.env
# stdout-file  .opam/system/build/opium.0.15.0/opium-79612-d8a4ae.out
# stderr-file  .opam/system/build/opium.0.15.0/opium-79612-d8a4ae.err
### stdout ###
# [...]
# --- Checking for ocamllex.opt... (found /usr/local/bin/ocamllex.opt)
# --- Checking whether ocamlc understands the "z" warnings... (yes)
# *** omake: finished reading OMakefiles (0.03 sec)
# --- Checking if ocamldep understands -modules... (yes)
# - build opium_kernel opium_hmap.cmi
# + ocamlfind ocamlc.opt -package hmap,cohttp.lwt-core,ppx_deriving,ppx_fields_conv,ppx_sexp_conv,ezjsonm -g -bin-annot -thread -g -I . -c opium_hmap.mli
# - build opium_kernel opium_misc.o
# + ocamlfind ocamlc.opt -package hmap,cohttp.lwt-core,ppx_deriving,ppx_fields_conv,ppx_sexp_conv,ezjsonm -g -bin-annot -thread -g -I . -c opium_misc.ml
# *** omake: 43/106 targets are up to date
# *** omake: failed (0.17 sec, 14/14 scans, 2/2 rules, 20/54 digests)
### stderr ###
# *** omake: targets were not rebuilt because of errors:
# [...]
#    opium_kernel/opium_misc.cmi
#       depends on: opium_kernel/opium_misc.ml
#    opium_kernel/opium_misc.cmo
#       depends on: opium_kernel/opium_misc.ml
#    opium_kernel/opium_misc.cmx
#       depends on: opium_kernel/opium_misc.ml
#    opium_kernel/opium_misc.o
#       depends on: opium_kernel/opium_misc.ml
# make: *** [install] Error 2

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.