Compare commits

...

41 Commits

Author SHA1 Message Date
Anton Bachin
27ff43177b
Typo in README.md 2024-12-20 11:18:22 +03:00
Mostafa Touny
204a792b57
example/h-sql: tup2 is deprecated (#370) 2024-12-17 12:47:11 +03:00
asymmetric
da94944400
example/w-template-logic: explain % (#366) 2024-12-10 14:08:48 +03:00
Anton Bachin
ac92bc072e Module Dream assumes latest dream-httpaf 2024-12-01 20:24:14 +03:00
alxtuz
deb4526387
Replace all #files anchors by #folders-and-files (#361) 2024-11-04 21:47:42 +03:00
alxtuz
59ce312808
dream.mli: use #folders-and-files in example links (#360) 2024-11-01 17:43:55 +03:00
alxtuz
e4fa99812b
Docs: link to example/e-json from Dream.json (#359) 2024-11-01 11:59:45 +03:00
Anton Bachin
e94401a7d8
CI: try dune-cache (#353) 2024-10-25 08:13:50 +03:00
alxtuz
6c75fb9e22 CI: skip example/w-dream-html (#358)
w-dream-html depends on external package dream-html, which, in turn,
depends on package dream, which makes it awkward to install dream-html
inside Dream's CI. So skip this example.
2024-10-22 09:20:32 +03:00
alxtuz
186ab997d8 Fix opam lint in examples (#356)
Resolves #350.
2024-10-17 18:47:09 +03:00
Emmanuel Ferdman
b7b477379f
Update e-json.opam reference (#354)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-10-15 11:23:58 +03:00
Anton Bachin
a888e44e88
Replace vendored httpaf with httpun (#351) 2024-10-14 20:00:57 +03:00
Yawar Amin
c8ec9d1af9
Add dream-html example (#323) 2024-10-14 19:59:53 +03:00
Andrey Popp
6a1a2f0db2
Examples: add w-mlx (#330) 2024-10-14 19:39:10 +03:00
Anton Bachin
91b470dcd8
CI: use Ubuntu 22.04 (#352)
See https://github.com/ocaml/setup-ocaml/issues/872
2024-10-14 19:24:27 +03:00
Anton Bachin
d088771512 Dream.run docs: remove mention of ~stop_on_input
It was removed in #46, but a dangling reference to it still remained.
Caught by Yawar Amin in

  https://github.com/aantron/dream/issues/46#issuecomment-1962267244
2024-09-09 19:01:14 +03:00
Anton Bachin
5858e47c92
Log fd numbers (#345) 2024-09-05 18:56:19 +03:00
Anton Bachin
3f556c89f0 Fix some whitespace 2024-09-05 13:26:31 +03:00
Anton Bachin
1bf9f992f8 Fix typo 2024-09-05 12:56:41 +03:00
Anton Bachin
e84720d2ee Adjust whitespace and disabled job 2024-09-04 00:58:59 +03:00
Max Große
d3cb68bf18
Fix CI (#337)
Fixes #338.
Incorporates and closes #335.

Co-authored-by: Anton Bachin <antonbachin@yahoo.com>
2024-09-04 00:54:04 +03:00
Max Große
f8958e71cf
Fix typo in .opam description (#343) 2024-09-03 10:09:25 +03:00
Max Große
2b13c3206a
Remove unused documentation (#342)
upload_event was removed from dream.mli in 018e8e273c5e01e24efefa8e2b2b5a9e4145c7a1
new_global was removed in d81b1986b67ccf8024deeb3d1c223452116fdb4d
2024-09-03 09:49:21 +03:00
Anton Bachin
d2656380b5 Bump version shown in the docs 2024-09-03 09:43:54 +03:00
Anton Bachin
5a7871f845 Add make release-clean target 2024-09-03 09:40:22 +03:00
Anton Bachin
05a04f56c2 Dream.run: warn on any use of ~adjust_terminal 2024-08-23 16:00:18 +03:00
Anton Bachin
ea262bce22 Adjust whitespace after preceding commit 2024-08-23 15:50:39 +03:00
Max Große
b3f89c860f
Dream.run: disable ~adjust_terminal behavior (#336) 2024-08-23 15:46:13 +03:00
Anton Bachin
b0b401bf4b
Warn upon re-entrant call to Dream.sql (#333)
Resolves #332.
2024-08-21 17:29:44 +03:00
Anton Bachin
6081749621 Document Dream.sql_pool ?size argument
Prompted by #332.
2024-08-21 11:52:24 +03:00
Anton Bachin
4ea4d94ca6 Touch up Makefiles 2024-08-21 11:51:30 +03:00
Anton Bachin
17c113380f
Adapt to mirage-crypto 1.0.0 (#334)
Fixes #328.
Closes #331.
2024-08-21 11:10:28 +03:00
Anton Bachin
7e5f18abcb Add html_of_jsx as with-test dependency 2024-07-25 09:06:13 +03:00
David Sancho
d72f21d18f
Add html_of_jsx example (#326) 2024-07-25 09:05:05 +03:00
Anton Bachin
b059575c57 Install tyxml-jsx as a test dep
Possible since https://github.com/ocsigen/tyxml/pull/312 was released in
TyXML 4.6.0.
2024-07-24 14:48:31 +03:00
Anton Bachin
41eaac9afc Docs: add a lot more links 2024-05-29 22:57:14 +03:00
Anton Bachin
d30fa5e322 make release: use SHA-256 instead of MD5
As recommended by the linter in opam-repository.
2024-05-28 15:46:06 +03:00
Anton Bachin
8eb7cf2c40 Docs: update version and copyright year 2024-05-28 14:52:20 +03:00
Anton Bachin
b2abbecfe5 Try again to disable dream.as GitHub Actions 2024-05-28 12:43:42 +03:00
Anton Bachin
e71c7aed2f Remove references to playground and dream.as
Maintaining dream.as has become a time sink and it is often down. This
is likely due to an upstream issue in the HTTP stack, which might be
replaced soon anyway. For now, it is best not to try to run the
playground.

Closes #123.
Closes #222.
2024-05-28 12:34:00 +03:00
Anton Bachin
3033ad6f85 make release: handle opam versions better 2024-05-28 12:00:53 +03:00
158 changed files with 2184 additions and 1263 deletions

View File

@ -1,9 +1,9 @@
name: docker-esy name: docker-esy
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-docker-esy/**' # - 'example/z-docker-esy/**'
- .github/workflows/docker-esy.yml # - .github/workflows/docker-esy.yml
jobs: jobs:
deploy: deploy:

View File

@ -1,9 +1,9 @@
name: docker-opam name: docker-opam
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-docker-opam/**' # - 'example/z-docker-opam/**'
- .github/workflows/docker-opam.yml # - .github/workflows/docker-opam.yml
jobs: jobs:
deploy: deploy:

View File

@ -1,9 +1,9 @@
name: systemd name: systemd
on: on: workflow_call
push: # push:
paths: # paths:
- 'example/z-systemd/**' # - 'example/z-systemd/**'
- .github/workflows/systemd.yml # - .github/workflows/systemd.yml
jobs: jobs:
deploy: deploy:

View File

@ -7,101 +7,98 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-latest # Until https://github.com/ocaml/setup-ocaml/issues/872.
# When fixing, search for other instances of this string in this file.
- ubuntu-22.04
ocaml: ocaml:
- 5.0.x - 5.2.x
- 4.14.x - 4.14.x
- 4.13.x
- 4.12.x
- 4.11.x
- 4.10.x
- 4.09.x
- 4.08.x
include: include:
- os: macos-latest - os: macos-latest
ocaml: 4.12.x ocaml: 4.14.x
- os: windows-latest - os: windows-latest
ocaml: 4.14.x ocaml: 4.14.x
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- uses: avsm/setup-ocaml@v2 - uses: ocaml/setup-ocaml@v3
if: runner.os != 'Windows'
with: with:
ocaml-compiler: ${{matrix.ocaml}} ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
- uses: avsm/setup-ocaml@v2 # For Caqti PostgreSQL examples. opam does actually install PostgreSQL for
# us. However, Homebrew doesn't link it by default, so we have to install
# and link it manually.
- run: brew install postgresql@15 && brew link --overwrite postgresql@15
if: runner.os == 'macOS'
# Workaround https://github.com/savonet/ocaml-ssl/issues/155 and/or
# https://github.com/ocaml/setup-ocaml/issues/856.
- run: opam pin add ssl 0.6.0 --no-action
if: runner.os == 'Windows' if: runner.os == 'Windows'
with:
ocaml-compiler: ${{matrix.ocaml}}
opam-repositories: |
opam-repository-mingw: https://github.com/ocaml-opam/opam-repository-mingw.git#sunset
default: https://github.com/ocaml/opam-repository.git
- run: opam depext --yes conf-sqlite3 - run: opam exec -- make deps
- run: opam depext --yes conf-postgresql
- run: opam depext --yes conf-libev - run: opam exec -- make
# Tests on Windows are disabled because of a difference in ppx_expect
# output. See https://github.com/aantron/dream/pull/282. This difference
# remains as of ppx_expect 0.16.
- run: opam exec -- make test
if: runner.os != 'Windows' if: runner.os != 'Windows'
# The tests require ppx_expect. The latest versions of it introduced changes - run: opam lint --recursive example
# in the formatting of the output, and also require OCaml >= 4.10, which
# makes testing on < 4.10 awkward. So, we skip tests on < 4.10. - name: Build examples
- shell: bash if: runner.os != 'Windows'
run: | run: |
set -e set -e
set -x set -x
EXCLUDED_EXAMPLES='w-mirage*|r-tyxml|w-dream-html'
WITH_TEST=--with-test EXAMPLES=$(find example -maxdepth 1 -type d | grep -Ev $EXCLUDED_EXAMPLES | grep -v "^example/0" | grep -v "^example$" | sort)
case ${{matrix.ocaml}} in
4.09.x) WITH_TEST=;;
4.08.x) WITH_TEST=;;
esac
# Tests on Windows are disabled because of a difference in ppx_expect
# output. See https://github.com/aantron/dream/pull/282.
case ${{runner.os}} in
Windows) WITH_TEST=;;
esac
OPAM=$(which opam || true)
if [ -z "$OPAM" ]
then
OPAM=D:\\cygwin\\wrapperbin\\opam.cmd
fi
$OPAM install --yes --deps-only $WITH_TEST ./dream-pure.opam ./dream-httpaf.opam ./dream.opam
if [ ! -z "$WITH_TEST" ]
then
$OPAM exec -- dune runtest
EXAMPLES=$(find example -maxdepth 1 -type d -not -name "w-mirage*" -not -name "r-tyxml" | grep -v "^example/0" | grep -v "^example$" | sort)
shopt -s nullglob shopt -s nullglob
for EXAMPLE in $EXAMPLES for EXAMPLE in $EXAMPLES
do do
FILE=$(ls $EXAMPLE/*.ml $EXAMPLE/*.re $EXAMPLE/server/*.ml $EXAMPLE/server/*.re) FILE=$(find $EXAMPLE -maxdepth 1 -type f -and -path "${EXAMPLE}/*.ml")
FILE+=$(find $EXAMPLE -maxdepth 1 -type f -and -path "${EXAMPLE}/*.re")
FILE+=$(find $EXAMPLE -maxdepth 2 -type f -and -path "${EXAMPLE}/server/*.ml")
FILE+=$(find $EXAMPLE -maxdepth 2 -type f -and -path "${EXAMPLE}/server/*.re")
if [[ "$FILE" == "" ]]; then
continue
fi
EXE=$(echo $FILE | sed 's/\..*$/.exe/g') EXE=$(echo $FILE | sed 's/\..*$/.exe/g')
echo dune build $EXE echo dune build $EXE
$OPAM exec -- dune build $EXE opam exec -- dune build $EXE
done done
fi
quickstart: quickstart:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-latest - ubuntu-22.04
- macos-latest ocaml:
- 5.2.x
- 4.14.x
include:
- os: macos-latest
ocaml: 4.14.x
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- name: Quick start - uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
- name: Run quickstart.sh
shell: bash
run: | run: |
set -x set -x
touch output touch output
@ -117,25 +114,29 @@ jobs:
fi fi
mirage: mirage:
runs-on: ubuntu-latest if: false
runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- run: mkdir ../repo-copy - run: mkdir ../repo-copy
- run: cp -r * ../repo-copy/ - run: cp -r * ../repo-copy/
- uses: avsm/setup-ocaml@v2 - uses: ocaml/setup-ocaml@v3
with: with:
ocaml-compiler: 4.14.x ocaml-compiler: 4.14.x
dune-cache: true
# Needed until https://github.com/robur-coop/ocaml-letsencrypt/pull/34.
- run: opam pin add letsencrypt git+https://github.com/hannesm/ocaml-letsencrypt.git#no-cstruct --no-action
- run: opam install --yes --deps-only ./dream-pure.opam ./dream-httpaf.opam ./dream.opam ./dream-mirage.opam - run: opam install --yes --deps-only ./dream-pure.opam ./dream-httpaf.opam ./dream.opam ./dream-mirage.opam
- run: opam install --yes mirage mirage-clock-unix - run: opam install --yes mirage mirage-clock-unix mirage-crypto-rng-mirage
- run: cd example/w-mirage && mv config.ml config.ml.backup - run: cd example/w-mirage && mv config.ml config.ml.backup
- run: cd example/w-mirage && sed -e 's/package "dream-mirage"//' < config.ml.backup > config.ml - run: cd example/w-mirage && sed -e 's/package "dream-mirage"//' < config.ml.backup > config.ml
- run: cd example/w-mirage && opam exec -- mirage configure -t unix - run: cd example/w-mirage && opam exec -- mirage configure -t unix
- run: cd example/w-mirage && opam exec -- make depends - run: cd example/w-mirage && opam exec -- make depends
- run: cd example/w-mirage && ls duniverse - run: cd example/w-mirage && ls duniverse
- run: cp -r ../repo-copy example/w-mirage/duniverse/dream - run: cp -r ../repo-copy example/w-mirage/duniverse/dream
- run: cd example/w-mirage/duniverse && rm -rf ocaml-cstruct logs ke fmt lwt bytes seq mirage-flow sexplib0 ptime tls domain-name ocaml-ipaddr mirage-clock ocplib-endian - run: cd example/w-mirage/duniverse && rm -rf ocaml-cstruct logs ke fmt lwt bytes seq mirage-flow sexplib0 ptime tls domain-name ocaml-ipaddr mirage-clock ocplib-endian digestif eqaf mirage-crypto mirage-runtime
- run: cd example/w-mirage && mv config.ml.backup config.ml - run: cd example/w-mirage && mv config.ml.backup config.ml
- run: cd example/w-mirage && sed -e 's/(libraries/(libraries dream-mirage/' < dune.build > dune.build.2 - run: cd example/w-mirage && sed -e 's/(libraries/(libraries dream-mirage/' < dune.build > dune.build.2
- run: cd example/w-mirage && mv dune.build.2 dune.build - run: cd example/w-mirage && mv dune.build.2 dune.build

16
.gitmodules vendored
View File

@ -1,16 +0,0 @@
[submodule "src/vendor/httpaf"]
path = src/vendor/httpaf
url = https://github.com/aantron/httpaf.git
[submodule "src/vendor/gluten"]
path = src/vendor/gluten
url = https://github.com/aantron/gluten.git
[submodule "src/vendor/websocketaf"]
path = src/vendor/websocketaf
url = https://github.com/aantron/websocketaf.git
[submodule "src/vendor/h2"]
path = src/vendor/h2
url = https://github.com/aantron/ocaml-h2.git
[submodule "src/vendor/paf"]
path = src/vendor/paf
url = https://github.com/aantron/paf-le-chien.git
branch = dream

View File

@ -1,4 +1,4 @@
Copyright (c) 2021-2023, Anton Bachin Copyright (c) 2021-2024, Anton Bachin
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -10,7 +10,8 @@ watch :
.PHONY : deps .PHONY : deps
deps : deps :
opam install --deps-only --with-test ./dream-pure.opam ./dream-httpaf.opam ./dream.opam opam install --deps-only --with-test --with-doc \
./dream-pure.opam ./dream-httpaf.opam ./dream.opam
TEST ?= test TEST ?= test
ROOT := $(shell [ -f ../dune-workspace ] && echo .. || echo .) ROOT := $(shell [ -f ../dune-workspace ] && echo .. || echo .)
@ -151,9 +152,9 @@ release : clean
(cd _release && tar xf $(RELEASE).tar.gz) (cd _release && tar xf $(RELEASE).tar.gz)
opam remove -y dream-pure dream-httpaf dream gluten httpaf h2 websocketaf paf opam remove -y dream-pure dream-httpaf dream gluten httpaf h2 websocketaf paf
opam pin remove -y dream-pure dream-httpaf dream opam pin remove -y dream-pure dream-httpaf dream
opam pin add -y --no-action dream-pure _release/$(RELEASE) --kind=path opam pin add -y --no-action dream-pure.dev _release/$(RELEASE) --kind=path
opam pin add -y --no-action dream-httpaf _release/$(RELEASE) --kind=path opam pin add -y --no-action dream-httpaf.dev _release/$(RELEASE) --kind=path
opam pin add -y --no-action dream _release/$(RELEASE) --kind=path opam pin add -y --no-action dream.dev _release/$(RELEASE) --kind=path
opam reinstall -y --verbose dream opam reinstall -y --verbose dream
@echo Run make release-finish to complete after killing the server @echo Run make release-finish to complete after killing the server
cd example/1-hello && dune exec --root . ./hello.exe || true cd example/1-hello && dune exec --root . ./hello.exe || true
@ -162,5 +163,9 @@ release : clean
release-finish : release-finish :
opam remove -y dream-pure dream-httpaf dream opam remove -y dream-pure dream-httpaf dream
opam pin remove -y dream-pure dream-httpaf dream opam pin remove -y dream-pure dream-httpaf dream
md5sum $(RELEASE).tar.gz sha256sum $(RELEASE).tar.gz
ls -l $(RELEASE).tar.gz ls -l $(RELEASE).tar.gz
.PHONY : release-clean
release-clean :
rm -rf $(RELEASE) $(RELEASE).tar.gz _release

View File

@ -12,7 +12,6 @@ Easy-to-use, feature-complete Web framework without boilerplate.
<p align="center"> <p align="center">
<a href="#quick-start">Quick Start</a> | <a href="#quick-start">Quick Start</a> |
<a href="http://dream.as">Playground</a> |
<a href="https://github.com/aantron/dream/tree/master/example#readme"> <a href="https://github.com/aantron/dream/tree/master/example#readme">
Tutorial</a> | Tutorial</a> |
<a href="https://aantron.github.io/dream/">Reference</a> <a href="https://aantron.github.io/dream/">Reference</a>
@ -78,24 +77,24 @@ Dream binary][one-binary], or use Dream in a subcommand. Dream tries to be as
functional as possible, touching global runtime state only lazily, when called functional as possible, touching global runtime state only lazily, when called
into. into.
[https]: https://github.com/aantron/dream/tree/master/example/l-https#files [https]: https://github.com/aantron/dream/tree/master/example/l-https#folders-and-files
[websocket]: https://github.com/aantron/dream/tree/master/example/k-websocket#files [websocket]: https://github.com/aantron/dream/tree/master/example/k-websocket#folders-and-files
[graphql]: https://github.com/aantron/dream/tree/master/example/w-graphql-subscription#files [graphql]: https://github.com/aantron/dream/tree/master/example/w-graphql-subscription#folders-and-files
[templates]: https://github.com/aantron/dream/tree/master/example/7-template#files [templates]: https://github.com/aantron/dream/tree/master/example/7-template#folders-and-files
[reason-templates]: https://github.com/aantron/dream/tree/master/example/r-template#files [reason-templates]: https://github.com/aantron/dream/tree/master/example/r-template#folders-and-files
[middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[handler]: https://aantron.github.io/dream/#type-handler [handler]: https://aantron.github.io/dream/#type-handler
[routing]: https://github.com/aantron/dream/tree/master/example/3-router#files [routing]: https://github.com/aantron/dream/tree/master/example/3-router#folders-and-files
[cookies]: https://aantron.github.io/dream/#cookies [cookies]: https://aantron.github.io/dream/#cookies
[forms]: https://aantron.github.io/dream/#forms [forms]: https://aantron.github.io/dream/#forms
[sessions]: https://github.com/aantron/dream/tree/master/example/b-session#files [sessions]: https://github.com/aantron/dream/tree/master/example/b-session#folders-and-files
[back-ends]: https://aantron.github.io/dream/#back-ends [back-ends]: https://aantron.github.io/dream/#back-ends
[errors]: https://github.com/aantron/dream/tree/master/example/9-error#files [errors]: https://github.com/aantron/dream/tree/master/example/9-error#folders-and-files
[crypto]: https://aantron.github.io/dream/#cryptography [crypto]: https://aantron.github.io/dream/#cryptography
[logging]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [logging]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[melange]: https://github.com/aantron/dream/tree/master/example/r-fullstack-melange#files [melange]: https://github.com/aantron/dream/tree/master/example/r-fullstack-melange#folders-and-files
[rescript]: https://github.com/aantron/dream/tree/master/example/w-fullstack-rescript#files [rescript]: https://github.com/aantron/dream/tree/master/example/w-fullstack-rescript#folders-and-files
[jsoo]: https://github.com/aantron/dream/tree/master/example/w-fullstack-jsoo#files [jsoo]: https://github.com/aantron/dream/tree/master/example/w-fullstack-jsoo#folders-and-files
[types]: https://aantron.github.io/dream/#types [types]: https://aantron.github.io/dream/#types
[basic-read]: https://aantron.github.io/dream/#val-body [basic-read]: https://aantron.github.io/dream/#val-body
[streaming]: https://aantron.github.io/dream/#streaming [streaming]: https://aantron.github.io/dream/#streaming
@ -103,23 +102,19 @@ into.
[alpn]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation [alpn]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
[libs]: https://github.com/aantron/dream/tree/master/src [libs]: https://github.com/aantron/dream/tree/master/src
[deploy]: https://github.com/aantron/dream/tree/master/example#deploying [deploy]: https://github.com/aantron/dream/tree/master/example#deploying
[jsx]: https://github.com/aantron/dream/tree/master/example/r-tyxml#files [jsx]: https://github.com/aantron/dream/tree/master/example/r-tyxml#folders-and-files
[one-binary]: https://github.com/aantron/dream/tree/master/example/w-one-binary#files [one-binary]: https://github.com/aantron/dream/tree/master/example/w-one-binary#folders-and-files
<br> <br>
## Quick start ## Quick start
Visit one of the first tutorials in the [online You can get
playground][2-middleware-playground], and read its [one](https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files)
[docs](https://github.com/aantron/dream/tree/master/example/2-middleware#files). of the first [tutorials][tutorial] and build it locally with:
You can get and build it locally with:
<pre><b>bash -c "$(curl -fsSL https://raw.githubusercontent.com/aantron/dream/master/example/quickstart.sh)"</b></pre> <pre><b>bash -c "$(curl -fsSL https://raw.githubusercontent.com/aantron/dream/master/example/quickstart.sh)"</b></pre>
Most of the other [examples][tutorial] are also loaded in the playground. See
the links on its [home page][playground].
### opam ### opam
Create a project directory with an optional local switch: Create a project directory with an optional local switch:
@ -144,12 +139,10 @@ After that, go to any of the [examples][tutorial], such as
dune exec ./middleware.exe dune exec ./middleware.exe
``` ```
[esy-example]: https://github.com/aantron/dream/tree/master/example/w-esy#files [esy-example]: https://github.com/aantron/dream/tree/master/example/w-esy#folders-and-files
[quickstart.sh]: https://github.com/aantron/dream/blob/master/example/quickstart.sh [quickstart.sh]: https://github.com/aantron/dream/blob/master/example/quickstart.sh
[esy]: https://esy.sh/ [esy]: https://esy.sh/
[2-middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#files [2-middleware]: https://github.com/aantron/dream/tree/master/example/2-middleware#folders-and-files
[playground]: http://dream.as
[2-middleware-playground]: http://dream.as/2-middleware
## esy ## esy
@ -180,14 +173,14 @@ esy`, and started with `npx esy start`.
[tutorial]: https://github.com/aantron/dream/tree/master/example#readme [tutorial]: https://github.com/aantron/dream/tree/master/example#readme
[examples]: https://github.com/aantron/dream/tree/master/example#examples [examples]: https://github.com/aantron/dream/tree/master/example#examples
[1-hello]: https://github.com/aantron/dream/tree/master/example/1-hello#files [1-hello]: https://github.com/aantron/dream/tree/master/example/1-hello#folders-and-files
[r-hello]: https://github.com/aantron/dream/tree/master/example/r-hello#files [r-hello]: https://github.com/aantron/dream/tree/master/example/r-hello#folders-and-files
[reason-examples]: https://github.com/aantron/dream/tree/master/example#reason [reason-examples]: https://github.com/aantron/dream/tree/master/example#reason
[deploying]: https://github.com/aantron/dream/tree/master/example#deploying [deploying]: https://github.com/aantron/dream/tree/master/example#deploying
[api-main]: https://aantron.github.io/dream/#types [api-main]: https://aantron.github.io/dream/#types
[fullstack]: https://github.com/aantron/dream/tree/master/example#full-stack [fullstack]: https://github.com/aantron/dream/tree/master/example#full-stack
[watch]: https://github.com/aantron/dream/tree/master/example/w-watch#files [watch]: https://github.com/aantron/dream/tree/master/example/w-watch#folders-and-files
[reload]: https://github.com/aantron/dream/tree/master/example/w-live-reload#files [reload]: https://github.com/aantron/dream/tree/master/example/w-live-reload#folders-and-files
<br> <br>
@ -224,7 +217,7 @@ Apart from the [issues](https://github.com/aantron/dream/issues), good places
to discuss Dream are... to discuss Dream are...
- #dream on the [Reason Discord](https://discord.gg/2JTYRq2rYh). - #dream on the [Reason Discord](https://discord.gg/2JTYRq2rYh).
- #webdev on the [OCaml Discord](https://discord.gg/sx45hPkkWV) - #webdev on the [OCaml Discord](https://discord.gg/sx45hPkkWV).
- The [OCaml Discuss forum](https://discuss.ocaml.org/). - The [OCaml Discuss forum](https://discuss.ocaml.org/).
- The development stream on [Twitch](https://www.twitch.tv/antron_ML). - The development stream on [Twitch](https://www.twitch.tv/antron_ML).

View File

@ -1,7 +1,7 @@
(executable (executable
(name index) (name index)
(modules index) (modules index)
(libraries common lambdasoup)) (libraries common lambdasoup str))
(library (library
(name common) (name common)

File diff suppressed because it is too large Load Diff

View File

@ -271,11 +271,11 @@ nav ~ * a[href="#templates"] {
font-style: italic; font-style: italic;
} }
a[href*=example] { header a[href*=example], .spec-doc a[href*=example] {
font-weight: bold; font-weight: bold;
} }
a[href^=http]::after { header a[href^=http]::after, .spec-doc a[href^=http]::after {
content: "\f35d"; content: "\f35d";
font-family: FontAwesome; font-family: FontAwesome;
font-size: 10px; font-size: 10px;
@ -434,7 +434,6 @@ p + .odoc-spec {
#val-origin_referrer_check + .spec-doc li + li, #val-origin_referrer_check + .spec-doc li + li,
#val-form + .spec-doc li + li, #val-form + .spec-doc li + li,
#type-part + .spec-doc li + li, #type-part + .spec-doc li + li,
#type-upload_event + .spec-doc li + li,
#val-upload + .spec-doc li + li, #val-upload + .spec-doc li + li,
#val-static + .spec-doc li + li, #val-static + .spec-doc li + li,
#val-from_path + .spec-doc li + li { #val-from_path + .spec-doc li + li {

View File

@ -36,10 +36,10 @@ init_theme();
</div> </div>
<ul> <ul>
<li><code>1.0.0~alpha5</code></li> <li><code>1.0.0~alpha7</code></li>
<li><code>opam install dream</code></li> <li><code>opam install dream</code></li>
<li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream">GitHub</a></li> <li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream">GitHub</a></li>
<li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/blob/master/src/dream.mli">Edit these docs</a></li> <li><a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/edit/master/src/dream.mli">Edit these docs</a></li>
</ul> </ul>
<div class="toolbar"> <div class="toolbar">
@ -123,18 +123,13 @@ init_theme();
<li> <li>
A <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#readme"> A <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#readme">
Tutorial</a> &mdash; get started at Tutorial</a> &mdash; get started at
<a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example/1-hello#files"> <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example/1-hello#folders-and-files">
<code>1-hello</code></a>! <code>1-hello</code></a>!
</li> </li>
<li> <li>
Many <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#reason"> Many <a target="_blank" rel="noreferrer noopener" href="https://github.com/aantron/dream/tree/master/example#reason">
Examples</a>, covering all kinds of scenarios. Examples</a>, covering all kinds of scenarios.
</li> </li>
<li>
An online <a target="_blank" rel="noreferrer noopener" href="http://dream.as/">
<b>Playground</b></a>, where you can try Dream without installing
anything!
</li>
</ul> </ul>
</div> </div>
</header> </header>
@ -143,7 +138,7 @@ init_theme();
<div id="api"></div> <div id="api"></div>
<footer> <footer>
Copyright © 2021 Anton Bachin. Copyright © 2021-2024 Anton Bachin.
<br> <br>
Released under the MIT license. See Released under the MIT license. See
<a href="https://github.com/aantron/dream/blob/master/LICENSE.md"> <a href="https://github.com/aantron/dream/blob/master/LICENSE.md">

View File

@ -15,31 +15,18 @@ maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [ depends: [
"dream-pure" "dream-pure"
"dune" {>= "2.7.0"} # --instrument-with. "dune" {>= "2.7.0"} # --instrument-with.
"gluten"
"gluten-lwt-unix"
"h2" {< "0.13.0"}
"h2-lwt-unix"
"httpun" {< "0.2.0"}
"httpun-lwt-unix"
"httpun-ws"
"lwt" "lwt"
"lwt_ppx" {>= "1.2.2"} "lwt_ppx" {>= "1.2.2"}
"lwt_ssl" "lwt_ssl"
"ocaml" {>= "4.08.0"} "ocaml" {>= "4.08.0"}
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol. "ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.
# Currently vendored.
# "gluten"
# "gluten-lwt-unix"
# "httpaf"
# "httpaf-lwt-unix"
# "h2"
# "h2-lwt-unix"
# "hpack"
# "websocketaf"
# Dependencies of vendored packages.
"angstrom" {>= "0.14.0"}
"base64" {>= "3.0.0"}
"bigstringaf" {>= "0.5.0"} # h2.
"digestif" {>= "0.7.2"} # websocket/af, sha1, default implementation.
"faraday" {>= "0.6.1"}
"faraday-lwt-unix"
"lwt_ssl" {>= "1.2.0"} # Gluten.
"psq" # h2.
] ]
build: [ build: [

View File

@ -29,7 +29,7 @@ Within this model, Dream adds:
- Helpers for Web formats, such as Base64url, and a modern cipher. - Helpers for Web formats, such as Base64url, and a modern cipher.
Because of the simple programming model, everything is optional and Because of the simple programming model, everything is optional and
composable. It is trivailly possible to strip Dream down to just a composable. It is trivially possible to strip Dream down to just a
bare driver of the various HTTP protocols. bare driver of the various HTTP protocols.
Dream is presented as a single module, whose API is documented on one Dream is presented as a single module, whose API is documented on one

View File

@ -29,7 +29,7 @@ Within this model, Dream adds:
- Helpers for Web formats, such as Base64url, and a modern cipher. - Helpers for Web formats, such as Base64url, and a modern cipher.
Because of the simple programming model, everything is optional and Because of the simple programming model, everything is optional and
composable. It is trivailly possible to strip Dream down to just a composable. It is trivially possible to strip Dream down to just a
bare driver of the various HTTP protocols. bare driver of the various HTTP protocols.
Dream is presented as a single module, whose API is documented on one Dream is presented as a single module, whose API is documented on one
@ -54,7 +54,8 @@ depends: [
"caqti-lwt" {>= "2.0.0"} "caqti-lwt" {>= "2.0.0"}
("conf-libev" {os != "win32"} | "ocaml" {os = "win32"}) ("conf-libev" {os != "win32"} | "ocaml" {os = "win32"})
"cstruct" {>= "6.0.0"} "cstruct" {>= "6.0.0"}
"dream-httpaf" {>= "1.0.0~alpha3"} "digestif" {>= "0.7"} # to_raw_string.
"dream-httpaf" {>= "1.0.0~alpha4"}
"dream-pure" {>= "1.0.0~alpha2"} "dream-pure" {>= "1.0.0~alpha2"}
"dune" {>= "2.7.0"} # --instrument-with. "dune" {>= "2.7.0"} # --instrument-with.
"fmt" {>= "0.8.7"} # `Italic. "fmt" {>= "0.8.7"} # `Italic.
@ -68,8 +69,8 @@ depends: [
"magic-mime" "magic-mime"
"markup" {>= "1.0.2"} "markup" {>= "1.0.2"}
"mirage-clock" {>= "3.0.0"} # now_d_ps : unit -> int * int64. "mirage-clock" {>= "3.0.0"} # now_d_ps : unit -> int * int64.
"mirage-crypto" {>= "0.8.1"} # AES-256-GCM. "mirage-crypto" {>= "1.0.0"}
"mirage-crypto-rng" "mirage-crypto-rng" {>= "1.0.0"}
"mirage-crypto-rng-lwt" "mirage-crypto-rng-lwt"
"multipart_form" {>= "0.4.0"} "multipart_form" {>= "0.4.0"}
"multipart_form-lwt" "multipart_form-lwt"
@ -85,16 +86,14 @@ depends: [
"caqti-driver-postgresql" {with-test} "caqti-driver-postgresql" {with-test}
"caqti-driver-sqlite3" {with-test} "caqti-driver-sqlite3" {with-test}
"crunch" {with-test} "crunch" {with-test}
"html_of_jsx" {with-test}
"js_of_ocaml" {with-test} "js_of_ocaml" {with-test}
"js_of_ocaml-ppx" {with-test} "js_of_ocaml-ppx" {with-test}
"ppx_expect" {with-test & >= "v0.15.0"} # Formatting changes. "ppx_expect" {with-test & >= "v0.15.0" & < "v0.17.0"} # Breaking changes.
"ppx_yojson_conv" {with-test} "ppx_yojson_conv" {with-test}
"reason" {with-test} "reason" {with-test}
"tyxml" {with-test & >= "4.5.0"} "tyxml" {with-test & >= "4.5.0"}
"tyxml-jsx" {with-test}
# Blocked until https://github.com/ocsigen/tyxml/pull/312.
# "tyxml-jsx" {with-test & >= "4.5.0"}
# "tyxml-ppx" {with-test & >= "4.5.0"}
] ]
build: [ build: [

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -24,8 +24,7 @@ browser. Your terminal probably makes the link clickable.
</code></pre> </code></pre>
If you go to [http://localhost:8080](http://localhost:8080), you will, of If you go to [http://localhost:8080](http://localhost:8080), you will, of
course, see `Good morning, world!`. You can also try it in the [Dream course, see `Good morning, world!`.
Playground](http://dream.as/1-hello).
<br> <br>
@ -41,17 +40,17 @@ name of the `.ml` file, but with `.ml` changed to `.exe`.
**Next steps:** **Next steps:**
- The next example, [**`2-middleware`**](../2-middleware#files), adds a logger - The next example, [**`2-middleware`**](../2-middleware#folders-and-files), adds a logger
to the app. to the app.
- [**`3-router`**](../3-router#files) sends requests to different handlers, - [**`3-router`**](../3-router#folders-and-files) sends requests to different handlers,
depending on their path. depending on their path.
<br> <br>
**See also:** **See also:**
- [**`r-hello`**](../r-hello#files) is a Reason syntax version of this example. - [**`r-hello`**](../r-hello#folders-and-files) is a Reason syntax version of this example.
- [**`w-watch`**](../w-watch#files) sets up a development watcher. - [**`w-watch`**](../w-watch#folders-and-files) sets up a development watcher.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -4,7 +4,7 @@
*Middleware* is just functions that take handlers and wrap them, producing *Middleware* is just functions that take handlers and wrap them, producing
bigger handlers that do a little bit more. This example takes the handler from bigger handlers that do a little bit more. This example takes the handler from
[**`1-hello`**](../1-hello#files) and wraps it in one of the most useful [**`1-hello`**](../1-hello#folders-and-files) and wraps it in one of the most useful
middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger): middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger):
```ocaml ```ocaml
@ -33,15 +33,14 @@ let () =
<br> <br>
When you run this server and visit When you run this server and visit
[http://localhost:8080](http://localhost:8080) [http://localhost:8080](http://localhost:8080), you get much more interesting
[[playground](http://dream.as/2-middleware)], you get much more interesting
(and colorful!) output: (and colorful!) output:
![Dream log example](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/log-sanitized.png) ![Dream log example](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/log-sanitized.png)
You can write your own messages to the log using You can write your own messages to the log using
[`Dream.log`](https://aantron.github.io/dream/#val-log). See example [`Dream.log`](https://aantron.github.io/dream/#val-log). See example
[**`a-log`**](../a-log#files) for more logging options. Now that we have the [**`a-log`**](../a-log#folders-and-files) for more logging options. Now that we have the
logger, we will use it in all other examples, even though it's not really logger, we will use it in all other examples, even though it's not really
necessary &mdash; it just makes it much easier to see what is going on. necessary &mdash; it just makes it much easier to see what is going on.
@ -49,14 +48,14 @@ necessary &mdash; it just makes it much easier to see what is going on.
There's not much else to middlewares &mdash; they are really just functions There's not much else to middlewares &mdash; they are really just functions
from handlers to handlers, so you can create them anywhere. Example from handlers to handlers, so you can create them anywhere. Example
[**`4-counter`**](../4-counter#files) already shows a simple custom middleware. [**`4-counter`**](../4-counter#folders-and-files) already shows a simple custom middleware.
<!-- <!--
There are also more complicated middlewares defined in There are also more complicated middlewares defined in
- [**`m-locals`**](../m-locals/#files), - [**`m-locals`**](../m-locals#folders-and-files),
- [**`w-auto-reload`**](../w-auto-reload/#files), and - [**`w-auto-reload`**](../w-auto-reload#folders-and-files), and
- [**`w-index-html`**](../w-index-html/#files). - [**`w-index-html`**](../w-index-html#folders-and-files).
--> -->
<!-- TODO Fill out this list; probably a-promise belongs here. --> <!-- TODO Fill out this list; probably a-promise belongs here. -->
@ -65,10 +64,10 @@ There are also more complicated middlewares defined in
**Next steps:** **Next steps:**
- The next example, [**`3-router`**](../3-router#files), shows - The next example, [**`3-router`**](../3-router#folders-and-files), shows
[*routes*](https://aantron.github.io/dream/#routing), the other way to build [*routes*](https://aantron.github.io/dream/#routing), the other way to build
up handlers in Dream. up handlers in Dream.
- [**`4-counter`**](../4-counter#files) builds the first custom middleware. - [**`4-counter`**](../4-counter#folders-and-files) builds the first custom middleware.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -32,9 +32,7 @@ let () =
<br> <br>
This is also our first dynamic site! A request to `/echo/foo` gets the response This is also our first dynamic site! A request to `/echo/foo` gets the response
`foo`, and a request to `/echo/bar` gets `bar`! Try it in the `foo`, and a request to `/echo/bar` gets `bar`!
[playground](http://dream.as/3-router/echo/foo) &mdash; once the server loads,
edit the URL in the right pane to visit `/echo/bar`.
The syntax `:word` in a route creates a path parameter, which can be read with The syntax `:word` in a route creates a path parameter, which can be read with
[`Dream.param`](https://aantron.github.io/dream/#val-param). [`Dream.param`](https://aantron.github.io/dream/#val-param).
@ -44,20 +42,20 @@ The syntax `:word` in a route creates a path parameter, which can be read with
When none of the routes match, the router returns a `404 Not Found` response. When none of the routes match, the router returns a `404 Not Found` response.
Except for the status code, the `404 Not Found` response is *completely* empty, Except for the status code, the `404 Not Found` response is *completely* empty,
so it might not display well in your browser. In example so it might not display well in your browser. In example
[**`9-error`**](../9-error#files), we will decorate all error responses with [**`9-error`**](../9-error#folders-and-files), we will decorate all error responses with
an error template in one central location. an error template in one central location.
<br> <br>
The router can do more than match simple routes: The router can do more than match simple routes:
- [**`f-static`**](../f-static#files) forwards all requests with a certain - [**`f-static`**](../f-static#folders-and-files) forwards all requests with a certain
prefix to a static file handler. prefix to a static file handler.
<!-- - [**`w-scope`**](../w-scope/#files) applies middlewares to groups of routes <!-- - [**`w-scope`**](../w-scope#folders-and-files) applies middlewares to groups of routes
&mdash; but only when they match. &mdash; but only when they match.
- [**`w-subsite`**](../w-subsite/#files) attaches a handler as a complete, - [**`w-subsite`**](../w-subsite#folders-and-files) attaches a handler as a complete,
nested sub-site, which might have its own router. --> nested sub-site, which might have its own router. -->
<!-- TODO --> <!-- TODO -->
@ -65,9 +63,9 @@ The router can do more than match simple routes:
**Next steps:** **Next steps:**
- [**`4-counter`**](../4-counter#files) counts requests, and exposes a route for - [**`4-counter`**](../4-counter#folders-and-files) counts requests, and exposes a route for
getting the count. getting the count.
- [**`5-promise`**](../5-promise#files) introduces - [**`5-promise`**](../5-promise#folders-and-files) introduces
[Lwt](https://github.com/ocsigen/lwt), the promise library used by Dream. [Lwt](https://github.com/ocsigen/lwt), the promise library used by Dream.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -4,8 +4,7 @@
This example shows how easy it is to define a custom middleware, This example shows how easy it is to define a custom middleware,
`count_requests`. It exposes the request count at `count_requests`. It exposes the request count at
[http://localhost:8080/](http://localhost:8080/) [http://localhost:8080/](http://localhost:8080/), in a sort of dashboard:
[[playground](http://dream.as/4-counter)], in a sort of dashboard:
```ocaml ```ocaml
let count = ref 0 let count = ref 0
@ -38,16 +37,16 @@ which means they usually also
This example's middleware only does something *before* calling the This example's middleware only does something *before* calling the
`inner_handler`. To do something *after*, we will need to await the response `inner_handler`. To do something *after*, we will need to await the response
promise with [Lwt](https://github.com/ocsigen/lwt#readme), the promise library promise with [Lwt](https://github.com/ocsigen/lwt#readme), the promise library
used by Dream. The next example, [**`5-promise`**](../5-promise#files), does used by Dream. The next example, [**`5-promise`**](../5-promise#folders-and-files), does
exactly that! exactly that!
<br> <br>
**Next steps:** **Next steps:**
- [**`5-promise`**](../5-promise#files) shows a middleware that awaits - [**`5-promise`**](../5-promise#folders-and-files) shows a middleware that awaits
responses using [Lwt](https://github.com/ocsigen/lwt). responses using [Lwt](https://github.com/ocsigen/lwt).
- [**`6-echo`**](../6-echo#files) responds to `POST` requests and reads their - [**`6-echo`**](../6-echo#folders-and-files) responds to `POST` requests and reads their
bodies. bodies.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,7 +2,7 @@
<br> <br>
[**`4-counter`**](../4-counter#files) was limited to counting requests *before* [**`4-counter`**](../4-counter#folders-and-files) was limited to counting requests *before*
passing them on to the rest of the app. With the promise library passing them on to the rest of the app. With the promise library
[Lwt](https://github.com/ocsigen/lwt), we can await responses, and do something [Lwt](https://github.com/ocsigen/lwt), we can await responses, and do something
*after*. In this example, we separately count requests that were handled *after*. In this example, we separately count requests that were handled
@ -44,8 +44,6 @@ let () =
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./promise.exe</b></code></pre> <b>$ dune exec --root . ./promise.exe</b></code></pre>
Try it in the [playground](http://dream.as/5-promise).
<br> <br>
As you can see, the As you can see, the
@ -93,8 +91,8 @@ We will stick to `let%lwt` in the examples and keep things tidy.
**Next steps:** **Next steps:**
- [**`6-echo`**](../6-echo#files) uses Dream and Lwt to read a request body. - [**`6-echo`**](../6-echo#folders-and-files) uses Dream and Lwt to read a request body.
- [**`7-template`**](../7-template#files) shows how to interleave HTML and - [**`7-template`**](../7-template#folders-and-files) shows how to interleave HTML and
OCaml. OCaml.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -24,8 +24,6 @@ let () =
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./echo.exe</b></code></pre> <b>$ dune exec --root . ./echo.exe</b></code></pre>
...or run it in the [playground](http://dream.as/6-echo).
<br> <br>
You can test it with curl: You can test it with curl:
@ -48,11 +46,11 @@ foo
We usually want to do something more interesting with the request body than just We usually want to do something more interesting with the request body than just
echo it, and there are several examples for that! echo it, and there are several examples for that!
- [**`d-form`**](../d-form#files) parses request bodies as forms. - [**`d-form`**](../d-form#folders-and-files) parses request bodies as forms.
- [**`e-json`**](../e-json#files) parses bodies as JSON. - [**`e-json`**](../e-json#folders-and-files) parses bodies as JSON.
- [**`g-upload`**](../g-upload#files) receives file upload forms. - [**`g-upload`**](../g-upload#folders-and-files) receives file upload forms.
- [**`i-graphql`**](../i-graphql#files) receives GraphQL queries. - [**`i-graphql`**](../i-graphql#folders-and-files) receives GraphQL queries.
- [**`j-stream`**](../j-stream#files) streams huge bodies. - [**`j-stream`**](../j-stream#folders-and-files) streams huge bodies.
We delay these examples a bit, so we can squeeze in a couple security topics We delay these examples a bit, so we can squeeze in a couple security topics
first. These examples do take client input, after all! So, it's better to first. These examples do take client input, after all! So, it's better to
@ -64,9 +62,9 @@ present them the right way.
**Next steps:** **Next steps:**
- [**`7-template`**](../7-template#files) builds responses from templates and - [**`7-template`**](../7-template#folders-and-files) builds responses from templates and
guards against injection attacks (XSS). guards against injection attacks (XSS).
- [**`8-debug`**](../8-debug#files) renders error information in responses. - [**`8-debug`**](../8-debug#folders-and-files) renders error information in responses.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -84,15 +84,11 @@ already escaped, or if it is safe for some other reason. But be careful!
To show the danger, let's launch a **script injection (XSS) attack** against To show the danger, let's launch a **script injection (XSS) attack** against
this tiny Web app! First, go to this tiny Web app! First, go to
[`template.eml.ml`](https://github.com/aantron/dream/blob/master/example/7-template/template.eml.ml#L4), [`template.eml.ml`](https://github.com/aantron/dream/blob/master/example/7-template/template.eml.ml#L4),
change the substitution to `<%s! param %>`, and restart the app. You can also change the substitution to `<%s! param %>`, and restart the app. Then, visit
make the edit in the [playground](http://dream.as/7-template/foo). Then,
visit
this highly questionable URL: this highly questionable URL:
[http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E](http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E) [http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E](http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E)
If you are using the playground, change the host and port accordingly.
This URL will cause our Web app to display an alert box, which we, as the This URL will cause our Web app to display an alert box, which we, as the
developers, did not intend! developers, did not intend!
@ -129,27 +125,31 @@ and not supported by Dream.
**Next steps:** **Next steps:**
- [**`8-debug`**](../8-debug#files) shows how to turn on debug responses, and - [**`8-debug`**](../8-debug#folders-and-files) shows how to turn on debug responses, and
get more info about errors. get more info about errors.
- [**`9-error`**](../9-error#files) sets up a central error template for all - [**`9-error`**](../9-error#folders-and-files) sets up a central error template for all
errors. errors.
- [**`r-template`**](../r-template#files) is a Reason syntax version of this - [**`r-template`**](../r-template#folders-and-files) is a Reason syntax version of this
example. example.
<br> <br>
**See also:** **See also:**
- [**`w-template-files`**](../w-template-files#files) moves the template into a - [**`w-template-files`**](../w-template-files#folders-and-files) moves the template into a
separate `.eml.html` to avoid problems with editor support. separate `.eml.html` to avoid problems with editor support.
- [**`w-template-logic`**](../w-template-logic#files) shows how to put control - [**`w-template-logic`**](../w-template-logic#folders-and-files) shows how to put control
flow into templates. flow into templates.
- [**`w-tyxml`**](../w-tyxml#files) shows how to use - [**`w-tyxml`**](../w-tyxml#folders-and-files) shows how to use
[TyXML](https://github.com/ocsigen/tyxml), a different templater that uses [TyXML](https://github.com/ocsigen/tyxml), a different templater that uses
OCaml's type system to prevent emitting many kinds of invalid HTML. OCaml's type system to prevent emitting many kinds of invalid HTML.
- [**`r-tyxml`**](../r-tyxml#files) if you are using Reason. You can use TyXML - [**`r-tyxml`**](../r-tyxml#folders-and-files) if you are using Reason. You can use TyXML
with JSX syntax server-side! with JSX syntax server-side!
- [**`w-template-stream`**](../w-template-stream#files) streams templates to - [**`w-dream-html`**](../w-dream-html#folders-and-files) shows how to use
[dream-html](https://github.com/yawaramin/dream-html), another alternative
library for generating HTML from OCaml, which is more closely integrated with
Dream.
- [**`w-template-stream`**](../w-template-stream#folders-and-files) streams templates to
responses, instead of building up complete response strings. responses, instead of building up complete response strings.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -30,11 +30,10 @@ let () =
The rest of the app just adds two routes for triggering two kinds of The rest of the app just adds two routes for triggering two kinds of
failures that the debugger will detail. Visit failures that the debugger will detail. Visit
[http://localhost:8080/bad](http://localhost:8080/bad) [http://localhost:8080/bad](http://localhost:8080/bad) to trigger a
[[playground](http://dream.as/8-debug/bad)] to trigger a `400 Bad Request` `400 Bad Request` response, and
response, and [http://localhost:8080/fail](http://localhost:8080/fail) [http://localhost:8080/fail](http://localhost:8080/fail) to trigger an
[[playground](http://dream.as/8-debug/fail)] to trigger an exception. The exception. The debugger will show reports like this:
debugger will show reports like this:
``` ```
Failure("The Web app failed!") Failure("The Web app failed!")
@ -95,7 +94,7 @@ work with in development.
You can have Dream show a custom error page with any information or graphics You can have Dream show a custom error page with any information or graphics
that you like &mdash; we will do this in the [very next that you like &mdash; we will do this in the [very next
example](../9-error#files)! example](../9-error#folders-and-files)!
<!-- TODO Fix after stack trace is fixed. --> <!-- TODO Fix after stack trace is fixed. -->
<!-- TODO Show the log --> <!-- TODO Show the log -->
@ -105,9 +104,9 @@ example](../9-error#files)!
**Next steps:** **Next steps:**
- [**`9-error`**](../9-error#files) handles all errors in one place, including - [**`9-error`**](../9-error#folders-and-files) handles all errors in one place, including
displaying the debugger output. displaying the debugger output.
- [**`a-log`**](../a-log#files) shows [log - [**`a-log`**](../a-log#folders-and-files) shows [log
levels](https://aantron.github.io/dream/#type-log_level) and levels](https://aantron.github.io/dream/#type-log_level) and
[sub-logs](https://aantron.github.io/dream/#type-sub_log). [sub-logs](https://aantron.github.io/dream/#type-sub_log).

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -36,8 +36,6 @@ let () =
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./error.exe</b></code></pre> <b>$ dune exec --root . ./error.exe</b></code></pre>
Try it in the [playground](http://dream.as/9-error).
<br> <br>
We kept the error template simple for the sake of the example, but this is We kept the error template simple for the sake of the example, but this is
@ -65,7 +63,7 @@ including return a completely new response.
<br> <br>
`debug_info` is a multiline string containing the same information as in the `debug_info` is a multiline string containing the same information as in the
previous example, [**`8-debug`**](../8-debug#files). previous example, [**`8-debug`**](../8-debug#folders-and-files).
<!-- TODO Images of the generated pages. --> <!-- TODO Images of the generated pages. -->
@ -82,9 +80,9 @@ Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet
**Next steps:** **Next steps:**
- [**`a-log`**](../a-log#files) shows how to write messages to Dream's - [**`a-log`**](../a-log#folders-and-files) shows how to write messages to Dream's
[log](https://aantron.github.io/dream/#logging). [log](https://aantron.github.io/dream/#logging).
- [**`b-session`**](../b-session#files) adds [session - [**`b-session`**](../b-session#folders-and-files) adds [session
management](https://aantron.github.io/dream/#sessions) for associating state management](https://aantron.github.io/dream/#sessions) for associating state
with clients. with clients.

View File

@ -2,46 +2,46 @@
Dream's first several examples make up a **tutorial**. Each example is a Dream's first several examples make up a **tutorial**. Each example is a
complete project with a helpful README, and plenty of links to next steps and complete project with a helpful README, and plenty of links to next steps and
documentation. You can begin at [**`1-hello`**](1-hello#files), or look in the documentation. You can begin at [**`1-hello`**](1-hello#folders-and-files), or look in the
list below and jump to whatever interests you! list below and jump to whatever interests you!
- [**`1-hello`**](1-hello/#files) &nbsp;&mdash;&nbsp; the simplest Dream server - [**`1-hello`**](1-hello#folders-and-files) &nbsp;&mdash;&nbsp; the simplest Dream server
responds to every request with the same friendly message. responds to every request with the same friendly message.
- [**`2-middleware`**](2-middleware/#files) &nbsp;&mdash;&nbsp; adds the first - [**`2-middleware`**](2-middleware#folders-and-files) &nbsp;&mdash;&nbsp; adds the first
Dream middleware: the *logger*. Dream middleware: the *logger*.
- [**`3-router`**](3-router/#files) &nbsp;&mdash;&nbsp; different handlers for - [**`3-router`**](3-router#folders-and-files) &nbsp;&mdash;&nbsp; different handlers for
different paths. different paths.
- [**`4-counter`**](4-counter/#files) &nbsp;&mdash;&nbsp; the first *custom* - [**`4-counter`**](4-counter#folders-and-files) &nbsp;&mdash;&nbsp; the first *custom*
middleware! middleware!
- [**`5-promise`**](5-promise/#files) &nbsp;&mdash;&nbsp; introduces Lwt, the - [**`5-promise`**](5-promise#folders-and-files) &nbsp;&mdash;&nbsp; introduces Lwt, the
promise library used by Dream. promise library used by Dream.
- [**`6-echo`**](6-echo/#files) &nbsp;&mdash;&nbsp; reads request bodies. - [**`6-echo`**](6-echo#folders-and-files) &nbsp;&mdash;&nbsp; reads request bodies.
- [**`7-template`**](7-template/#files) &nbsp;&mdash;&nbsp; renders responses - [**`7-template`**](7-template#folders-and-files) &nbsp;&mdash;&nbsp; renders responses
from inline HTML templates and guards against XSS. from inline HTML templates and guards against XSS.
- [**`8-debug`**](8-debug/#files) &nbsp;&mdash;&nbsp; includes detailed - [**`8-debug`**](8-debug#folders-and-files) &nbsp;&mdash;&nbsp; includes detailed
information about errors in responses. information about errors in responses.
- [**`9-error`**](9-error/#files) &nbsp;&mdash;&nbsp; customize all error - [**`9-error`**](9-error#folders-and-files) &nbsp;&mdash;&nbsp; customize all error
responses in one place. responses in one place.
- [**`a-log`**](a-log/#files) &nbsp;&mdash;&nbsp; writing messages to Dream's - [**`a-log`**](a-log#folders-and-files) &nbsp;&mdash;&nbsp; writing messages to Dream's
log. log.
- [**`b-session`**](b-session/#files) &nbsp;&mdash;&nbsp; associates state with - [**`b-session`**](b-session#folders-and-files) &nbsp;&mdash;&nbsp; associates state with
client sessions. client sessions.
- [**`c-cookie`**](c-cookie/#files) &nbsp;&mdash;&nbsp; sets custom cookies. - [**`c-cookie`**](c-cookie#folders-and-files) &nbsp;&mdash;&nbsp; sets custom cookies.
- [**`d-form`**](d-form#files) &nbsp;&mdash;&nbsp; reads forms with CSRF - [**`d-form`**](d-form#folders-and-files) &nbsp;&mdash;&nbsp; reads forms with CSRF
prevention. prevention.
- [**`e-json`**](e-json#files) &nbsp;&mdash;&nbsp; sends and receives JSON - [**`e-json`**](e-json#folders-and-files) &nbsp;&mdash;&nbsp; sends and receives JSON
securely. securely.
- [**`f-static`**](f-static#files) &nbsp;&mdash;&nbsp; serves static files from - [**`f-static`**](f-static#folders-and-files) &nbsp;&mdash;&nbsp; serves static files from
a local directory. a local directory.
- [**`g-upload`**](g-upload#files) &nbsp;&mdash;&nbsp; receives file uploads. - [**`g-upload`**](g-upload#folders-and-files) &nbsp;&mdash;&nbsp; receives file uploads.
- [**`h-sql`**](h-sql#files) &nbsp;&mdash;&nbsp; queries an SQL database. - [**`h-sql`**](h-sql#folders-and-files) &nbsp;&mdash;&nbsp; queries an SQL database.
- [**`i-graphql`**](i-graphql#files) &nbsp;&mdash;&nbsp; serves a GraphQL - [**`i-graphql`**](i-graphql#folders-and-files) &nbsp;&mdash;&nbsp; serves a GraphQL
schema and GraphiQL. schema and GraphiQL.
- [**`j-stream`**](j-stream#files) &nbsp;&mdash;&nbsp; streams request and - [**`j-stream`**](j-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams request and
response bodies. response bodies.
- [**`k-websocket`**](k-websocket#files) &nbsp;&mdash;&nbsp; opens a WebSocket - [**`k-websocket`**](k-websocket#folders-and-files) &nbsp;&mdash;&nbsp; opens a WebSocket
between client and server. between client and server.
- [**`l-https`**](l-https#files) &nbsp;&mdash;&nbsp; enables HTTPS and HTTP/2 - [**`l-https`**](l-https#folders-and-files) &nbsp;&mdash;&nbsp; enables HTTPS and HTTP/2
upgrades. upgrades.
That's it for the tutorial! That's it for the tutorial!
@ -52,43 +52,43 @@ That's it for the tutorial!
There are several examples showing Dream with Reason syntax. There are several examples showing Dream with Reason syntax.
- [**`r-hello`**](r-hello#files) &nbsp;&mdash;&nbsp; the simplest Dream server. - [**`r-hello`**](r-hello#folders-and-files) &nbsp;&mdash;&nbsp; the simplest Dream server.
- [**`r-template`**](r-template#files) &nbsp;&mdash;&nbsp; renders HTML - [**`r-template`**](r-template#folders-and-files) &nbsp;&mdash;&nbsp; renders HTML
templates and protects against XSS. templates and protects against XSS.
- [**`r-template-files`**](r-template-files#files) &nbsp;&mdash;&nbsp; templates - [**`r-template-files`**](r-template-files#folders-and-files) &nbsp;&mdash;&nbsp; templates
in separate `.html` files for better editor support. in separate `.html` files for better editor support.
- [**`r-template-logic`**](r-template-logic#files) &nbsp;&mdash;&nbsp; control - [**`r-template-logic`**](r-template-logic#folders-and-files) &nbsp;&mdash;&nbsp; control
flow inside templates. flow inside templates.
- [**`r-template-stream`**](r-template-stream#files) &nbsp;&mdash;&nbsp; streams - [**`r-template-stream`**](r-template-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams
templates as response bodies. templates as response bodies.
- [**`r-tyxml`**](r-tyxml#files) &nbsp;&mdash;&nbsp; type-checked server-side - [**`r-tyxml`**](r-tyxml#folders-and-files) &nbsp;&mdash;&nbsp; type-checked server-side
JSX templates. JSX templates.
- [**`r-graphql`**](r-graphql#files) &nbsp;&mdash;&nbsp; serves a GraphQL - [**`r-graphql`**](r-graphql#folders-and-files) &nbsp;&mdash;&nbsp; serves a GraphQL
schema. schema.
<br> <br>
# Full-stack # Full-stack
- [**`r-fullstack-melange`**](r-fullstack-melange#files) &nbsp;&mdash;&nbsp; - [**`r-fullstack-melange`**](r-fullstack-melange#folders-and-files) &nbsp;&mdash;&nbsp;
server *and* client written in Reason! server *and* client written in Reason!
- [**`w-fullstack-rescript`**](w-fullstack-rescript#files) &nbsp;&mdash;&nbsp; - [**`w-fullstack-rescript`**](w-fullstack-rescript#folders-and-files) &nbsp;&mdash;&nbsp;
shares OCaml code between server and client using ReScript. shares OCaml code between server and client using ReScript.
- [**`w-fullstack-jsoo`**](w-fullstack-jsoo#files) &nbsp;&mdash;&nbsp; shares - [**`w-fullstack-jsoo`**](w-fullstack-jsoo#folders-and-files) &nbsp;&mdash;&nbsp; shares
OCaml code between server and client using js_of_ocaml. OCaml code between server and client using js_of_ocaml.
<br> <br>
# Deploying # Deploying
- [**`z-heroku`**](z-heroku#files) &nbsp;&mdash;&nbsp; to - [**`z-heroku`**](z-heroku#folders-and-files) &nbsp;&mdash;&nbsp; to
[Heroku](https://www.heroku.com). [Heroku](https://www.heroku.com).
- [**`z-fly`**](z-fly#files) &nbsp;&mdash;&nbsp; to [Fly.io](https://fly.io/). - [**`z-fly`**](z-fly#folders-and-files) &nbsp;&mdash;&nbsp; to [Fly.io](https://fly.io/).
- [**`z-docker-esy`**](z-docker-esy#files) &nbsp;&mdash;&nbsp; on a server, - [**`z-docker-esy`**](z-docker-esy#folders-and-files) &nbsp;&mdash;&nbsp; on a server,
using Docker, with package manager esy. using Docker, with package manager esy.
- [**`z-docker-opam`**](z-docker-opam#files) &nbsp;&mdash;&nbsp; on a server, - [**`z-docker-opam`**](z-docker-opam#folders-and-files) &nbsp;&mdash;&nbsp; on a server,
using Docker, with package manager opam. using Docker, with package manager opam.
- [**`z-systemd`**](z-systemd#files) &nbsp;&mdash;&nbsp; on a server, as a - [**`z-systemd`**](z-systemd#folders-and-files) &nbsp;&mdash;&nbsp; on a server, as a
systemd daemon. systemd daemon.
<br> <br>
@ -102,49 +102,51 @@ if something is missing!
<br> <br>
- [**`w-template-files`**](w-template-files#files) &nbsp;&mdash;&nbsp; templates - [**`w-template-files`**](w-template-files#folders-and-files) &nbsp;&mdash;&nbsp; templates
in separate `.html` files for better editor support. in separate `.html` files for better editor support.
- [**`w-template-logic`**](w-template-logic#files) &nbsp;&mdash;&nbsp; control - [**`w-template-logic`**](w-template-logic#folders-and-files) &nbsp;&mdash;&nbsp; control
flow inside templates. flow inside templates.
- [**`w-graphql-subscription`**](w-graphql-subscription#files) - [**`w-graphql-subscription`**](w-graphql-subscription#folders-and-files)
&nbsp;&mdash;&nbsp; GraphQL subscriptions. &nbsp;&mdash;&nbsp; GraphQL subscriptions.
- [**`w-postgres`**](w-postgres#files) &nbsp;&mdash;&nbsp; connects to a - [**`w-postgres`**](w-postgres#folders-and-files) &nbsp;&mdash;&nbsp; connects to a
PostgreSQL database. PostgreSQL database.
- [**`w-flash`**](w-flash#files) &nbsp;&mdash;&nbsp; using flash messages, which - [**`w-flash`**](w-flash#folders-and-files) &nbsp;&mdash;&nbsp; using flash messages, which
are displayed on the next request. are displayed on the next request.
- [**`w-chat`**](w-chat#files) &nbsp;&mdash;&nbsp; a chat room based on - [**`w-chat`**](w-chat#folders-and-files) &nbsp;&mdash;&nbsp; a chat room based on
WebSockets. WebSockets.
- [**`w-content-security-policy`**](w-content-security-policy#files) - [**`w-content-security-policy`**](w-content-security-policy#folders-and-files)
&nbsp;&mdash;&nbsp; sandboxes Web pages using `Content-Security-Policy`. &nbsp;&mdash;&nbsp; sandboxes Web pages using `Content-Security-Policy`.
- [**`w-esy`**](w-esy#files) &nbsp;&mdash;&nbsp; gives detail on packaging with - [**`w-esy`**](w-esy#folders-and-files) &nbsp;&mdash;&nbsp; gives detail on packaging with
[esy](https://esy.sh/), an npm-like package manager. [esy](https://esy.sh/), an npm-like package manager.
- [**`w-one-binary`**](w-one-binary#files) &nbsp;&mdash;&nbsp; bakes static - [**`w-one-binary`**](w-one-binary#folders-and-files) &nbsp;&mdash;&nbsp; bakes static
assets into a self-contained server binary. assets into a self-contained server binary.
- [**`w-watch`**](w-watch#files) &nbsp;&mdash;&nbsp; sets up a development - [**`w-watch`**](w-watch#folders-and-files) &nbsp;&mdash;&nbsp; sets up a development
watcher. watcher.
- [**`w-live-reload`**](w-live-reload#files) &nbsp;&mdash;&nbsp; a simple - [**`w-live-reload`**](w-live-reload#folders-and-files) &nbsp;&mdash;&nbsp; a simple
live-reloading setup. live-reloading setup.
- [**`w-nginx`**](w-nginx#files) &nbsp;&mdash;&nbsp; uses nginx as a - [**`w-nginx`**](w-nginx#folders-and-files) &nbsp;&mdash;&nbsp; uses nginx as a
reverse proxy. reverse proxy.
- [**`w-tyxml`**](w-tyxml#files) &nbsp;&mdash;&nbsp; uses TyXML for type-checked - [**`w-tyxml`**](w-tyxml#folders-and-files) &nbsp;&mdash;&nbsp; uses TyXML for type-checked
HTML templating. HTML templating.
- [**`w-long-polling`**](w-long-polling#files) &nbsp;&mdash;&nbsp; old form of - [**`w-dream-html`**](../w-dream-html#folders-and-files) &nbsp;&mdash;&nbsp; uses
dream-html for convenient HTML generation from OCaml.
- [**`w-long-polling`**](w-long-polling#folders-and-files) &nbsp;&mdash;&nbsp; old form of
asynchronous communication without WebSockets. asynchronous communication without WebSockets.
- [**`w-query`**](w-query#files) &nbsp;&mdash;&nbsp; reads URL query parameters. - [**`w-query`**](w-query#folders-and-files) &nbsp;&mdash;&nbsp; reads URL query parameters.
- [**`w-server-sent-events`**](w-server-sent-events#files) &nbsp;&mdash;&nbsp; - [**`w-server-sent-events`**](w-server-sent-events#folders-and-files) &nbsp;&mdash;&nbsp;
[`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource),
an older alternative to WebSockets. an older alternative to WebSockets.
- [**`w-template-stream`**](w-template-stream#files) &nbsp;&mdash;&nbsp; sends - [**`w-template-stream`**](w-template-stream#folders-and-files) &nbsp;&mdash;&nbsp; sends
templates asynchronously, one chunk at a time. templates asynchronously, one chunk at a time.
- [**`w-upload-stream`**](w-upload-stream#files) &nbsp;&mdash;&nbsp; streams - [**`w-upload-stream`**](w-upload-stream#folders-and-files) &nbsp;&mdash;&nbsp; streams
uploaded files. uploaded files.
- [**`w-stress-response`**](w-stress-response#files) &nbsp;&mdash;&nbsp; - [**`w-stress-response`**](w-stress-response#folders-and-files) &nbsp;&mdash;&nbsp;
benchmarks streaming very large responses. benchmarks streaming very large responses.
- [**`w-stress-websocket-send`**](w-stress-websocket-send#files) - [**`w-stress-websocket-send`**](w-stress-websocket-send#folders-and-files)
&nbsp;&mdash;&nbsp; benchmarks sending WebSocket messages quickly. &nbsp;&mdash;&nbsp; benchmarks sending WebSocket messages quickly.
- [**`w-multipart-dump`**](w-multipart-dump#files) &nbsp;&mdash;&nbsp; echoes - [**`w-multipart-dump`**](w-multipart-dump#folders-and-files) &nbsp;&mdash;&nbsp; echoes
`multipart/form-data` bodies for debugging. `multipart/form-data` bodies for debugging.
- [**`z-playground`**](z-playground#files) &nbsp;&mdash;&nbsp; source code of - [**`z-playground`**](z-playground#folders-and-files) &nbsp;&mdash;&nbsp; source code of
the Dream playground. the Dream playground.
<br> <br>
@ -167,7 +169,7 @@ Ideas:
Basics: Basics:
- `w-content-negotiation` - `w-content-negotiation`
- [**`w-query`**](w-query#files) &nbsp;&mdash;&nbsp; done. - [**`w-query`**](w-query#folders-and-files) &nbsp;&mdash;&nbsp; done.
- `w-scope` &nbsp;&mdash;&nbsp; for - `w-scope` &nbsp;&mdash;&nbsp; for
[`Dream.scope`](https://aantron.github.io/dream/#val-scope). [`Dream.scope`](https://aantron.github.io/dream/#val-scope).
- `w-subsite` &nbsp;&mdash;&nbsp; for - `w-subsite` &nbsp;&mdash;&nbsp; for

View File

@ -30,8 +30,7 @@ let () =
<br> <br>
If you visit [http://localhost:8080](http://localhost:8080) If you visit [http://localhost:8080](http://localhost:8080) and then
[[playground](http://dream.as/a-log)] and then
[http://localhost:8080/fail](http://localhost:8080/fail), you will find these [http://localhost:8080/fail](http://localhost:8080/fail), you will find these
messages in the log, between the others: messages in the log, between the others:
@ -77,9 +76,9 @@ let () =
**Next steps:** **Next steps:**
- [**`b-session`**](../b-session#files) returns Web development proper with - [**`b-session`**](../b-session#folders-and-files) returns Web development proper with
session management. session management.
- [**`c-cookie`**](../c-cookie#files) shows cookie handling in Dream. - [**`c-cookie`**](../c-cookie#folders-and-files) shows cookie handling in Dream.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -28,8 +28,8 @@ let () =
<br> <br>
The first time you access the app [[playground](http://dream.as/b-session)], it The first time you access the app, it “logs you in” by saving you user name in
“logs you in” by saving you user name in a session. The session manager, a session. The session manager,
[`Dream.memory_sessions`](https://aantron.github.io/dream/#val-memory_sessions), [`Dream.memory_sessions`](https://aantron.github.io/dream/#val-memory_sessions),
a middleware, adds a `dream.session` cookie to the response, containing the a middleware, adds a `dream.session` cookie to the response, containing the
session key. The next time you access the app, the session is looked up again session key. The next time you access the app, the session is looked up again
@ -68,7 +68,7 @@ There are two other session back ends, which are persistent:
using a different random encryption key each time it starts. using a different random encryption key each time it starts.
- [`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions) - [`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions)
stores sessions in a database. It is shown in example stores sessions in a database. It is shown in example
[**`h-sql`**](../h-sql#files). [**`h-sql`**](../h-sql#folders-and-files).
<br> <br>
@ -90,7 +90,7 @@ new session will, again, be an empty pre-session.
It is best to use HTTPS when using sessions, to prevent session cookies from It is best to use HTTPS when using sessions, to prevent session cookies from
being easily observed by third parties. See being easily observed by third parties. See
[`Dream.run`](https://aantron.github.io/dream/#val-run) argument `~https`, and [`Dream.run`](https://aantron.github.io/dream/#val-run) argument `~https`, and
example [**`l-https`**](../l-https#files). If you redirect from HTTP to HTTPS, example [**`l-https`**](../l-https#folders-and-files). If you redirect from HTTP to HTTPS,
do not issue sessions for HTTP requests. If you do, don't accept them later do not issue sessions for HTTP requests. If you do, don't accept them later
from HTTPS requests. from HTTPS requests.
@ -100,8 +100,8 @@ from HTTPS requests.
**Next steps:** **Next steps:**
- Sessions already use cookies internally, but in - Sessions already use cookies internally, but in
[**`c-cookie`**](../c-cookie#files) we set cookies for our own purposes! [**`c-cookie`**](../c-cookie#folders-and-files) we set cookies for our own purposes!
- [**`d-form`**](../d-form#files) builds secure forms on top of sessions. - [**`d-form`**](../d-form#folders-and-files) builds secure forms on top of sessions.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -29,10 +29,9 @@ let () =
<br> <br>
The first time you access this app [[playground](http://dream.as/c-cookie)], it The first time you access this app, it sets up a language preference, `ut-OP`.
sets up a language preference, `ut-OP`. This string is sent to the client in a This string is sent to the client in a `ui.language` cookie. On the next
`ui.language` cookie. On the next request, the client sends it back. The app request, the client sends it back. The app retrieves and displays it.
retrieves and displays it.
<br> <br>
@ -97,9 +96,9 @@ The easiest way to do that for general data is to use
**Next steps:** **Next steps:**
- [**`d-form`**](../d-form#files) builds secure forms on top of sessions, and - [**`d-form`**](../d-form#folders-and-files) builds secure forms on top of sessions, and
introduces automatic handling of CSRF tokens. introduces automatic handling of CSRF tokens.
- [**`e-json`**](../e-json#files) sends and receives JSON instead! - [**`e-json`**](../e-json#folders-and-files) sends and receives JSON instead!
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,7 +2,7 @@
<br> <br>
With the session middleware from example [**`b-session`**](../b-session#files), With the session middleware from example [**`b-session`**](../b-session#folders-and-files),
we can build a [secure form](https://aantron.github.io/dream/#forms): we can build a [secure form](https://aantron.github.io/dream/#forms):
```ocaml ```ocaml
@ -49,8 +49,6 @@ let () =
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./form.exe</b></code></pre> <b>$ dune exec --root . ./form.exe</b></code></pre>
Try it in the [playground](http://dream.as/d-form).
<br> <br>
The template adds a CSRF token to the form using The template adds a CSRF token to the form using
@ -102,14 +100,14 @@ important on login forms and other sensitive pages.
However, this server is so simple that it doesn't store the data anywhere, and However, this server is so simple that it doesn't store the data anywhere, and
the data is not sensitive, so we took a shortcut. See the data is not sensitive, so we took a shortcut. See
[**`h-sql`**](../h-sql#files) for an example with a proper redirection. [**`h-sql`**](../h-sql#folders-and-files) for an example with a proper redirection.
<br> <br>
**Next steps:** **Next steps:**
- [**`e-json`**](../e-json#files) receives and sends JSON. - [**`e-json`**](../e-json#folders-and-files) receives and sends JSON.
- [**`f-static`**](../f-static#files) serves static files from a local - [**`f-static`**](../f-static#folders-and-files) serves static files from a local
directory. directory.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -49,7 +49,7 @@ To get this working, we have to add `ppx_yojson_conv` to our
</code></pre> </code></pre>
and to and to
[`json.opam`](https://github.com/aantron/dream/blob/master/example/e-json/json.opam): [`json.opam`](https://github.com/aantron/dream/blob/master/example/e-json/e-json.opam):
<pre><code>depends: [ <pre><code>depends: [
"ocaml" {>= "4.08.0"} "ocaml" {>= "4.08.0"}
@ -65,8 +65,6 @@ The build commands, as always, are:
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./json.exe</b></code></pre> <b>$ dune exec --root . ./json.exe</b></code></pre>
You can try this example in the [playground](http://dream.as/e-json).
<br> <br>
This example expects JSON of the form `{"message": "some-message"}`. Let's test This example expects JSON of the form `{"message": "some-message"}`. Let's test
@ -114,9 +112,9 @@ requests!
**Next steps:** **Next steps:**
- [**`f-static`**](../f-static#files) serves static files from the local - [**`f-static`**](../f-static#folders-and-files) serves static files from the local
file system. file system.
- [**`g-upload`**](../g-upload#files) receives files from an upload form. - [**`g-upload`**](../g-upload#folders-and-files) receives files from an upload form.
<br> <br>

View File

@ -6,3 +6,10 @@ depends: [
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
"ppx_yojson_conv" "ppx_yojson_conv"
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -56,7 +56,7 @@ You can replace the file loading behavior of
[crunch](https://github.com/mirage/ocaml-crunch) to compile a directory right [crunch](https://github.com/mirage/ocaml-crunch) to compile a directory right
into your Web app binary, and then serve that directory from memory with into your Web app binary, and then serve that directory from memory with
[`Dream.static`](https://aantron.github.io/dream/#val-static)! See example [`Dream.static`](https://aantron.github.io/dream/#val-static)! See example
[**`w-one-binary`**](../w-one-binary#files). [**`w-one-binary`**](../w-one-binary#folders-and-files).
You can also use `~loader` to set arbitrary headers on the response. You can also use `~loader` to set arbitrary headers on the response.
@ -64,9 +64,9 @@ You can also use `~loader` to set arbitrary headers on the response.
**Next steps:** **Next steps:**
- [**`g-upload`**](../g-upload#files) receives files instead of serving them. - [**`g-upload`**](../g-upload#folders-and-files) receives files instead of serving them.
- [**`h-sql`**](../h-sql#files) runs SQL queries against a database. - [**`h-sql`**](../h-sql#folders-and-files) runs SQL queries against a database.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
self-contained binary. self-contained binary.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -56,8 +56,7 @@ let () =
<br> <br>
The page shown after uploading looks like this The page shown after uploading looks like this:
[[playground](http://dream.as/g-upload)]:
``` ```
foo.png, 663959 bytes foo.png, 663959 bytes
@ -75,7 +74,7 @@ However, this is only good for rare, small uploads, such as user avatars, or for
prototyping. prototyping.
For more heavy usage, see For more heavy usage, see
[`Dream.upload`](https://aantron.github.io/dream/#type-upload_event) for [`Dream.upload`](https://aantron.github.io/dream/#val-upload) for
streaming file uploads. streaming file uploads.
<br> <br>
@ -85,7 +84,7 @@ streaming file uploads.
[`Dream.multipart`](https://aantron.github.io/dream/#val-multipart) behaves just [`Dream.multipart`](https://aantron.github.io/dream/#val-multipart) behaves just
like [`Dream.form`](https://aantron.github.io/dream/#val-form) when it comes to like [`Dream.form`](https://aantron.github.io/dream/#val-form) when it comes to
[CSRF protection](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html). [CSRF protection](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
See example [**`d-form`**](../d-form#files). We use See example [**`d-form`**](../d-form#folders-and-files). We use
[`Dream.csrf_tag`](https://aantron.github.io/dream/#val-csrf_tag) to generate [`Dream.csrf_tag`](https://aantron.github.io/dream/#val-csrf_tag) to generate
the CSRF token in the template, and pass the `enctype="multipart/form-data"` the CSRF token in the template, and pass the `enctype="multipart/form-data"`
attribute as needed for forms to upload files. The template output looks like attribute as needed for forms to upload files. The template output looks like
@ -110,17 +109,17 @@ for a checklist of additional security precautions.
**Next steps:** **Next steps:**
- [**`h-sql`**](../h-sql#files) runs SQL queries against a database. - [**`h-sql`**](../h-sql#folders-and-files) runs SQL queries against a database.
- [**`i-graphql`**](../i-graphql#files) handles GraphQL queries and serves - [**`i-graphql`**](../i-graphql#folders-and-files) handles GraphQL queries and serves
GraphiQL. GraphiQL.
<br> <br>
**See also:** **See also:**
- [**`w-upload-stream`**](../w-upload-stream#files) shows the streaming - [**`w-upload-stream`**](../w-upload-stream#folders-and-files) shows the streaming
interface for receiving file uploads. interface for receiving file uploads.
- [**`w-multipart-dump`**](../w-multipart-dump#files) shows the request body - [**`w-multipart-dump`**](../w-multipart-dump#folders-and-files) shows the request body
that is interpreted by that is interpreted by
[`Dream.multipart`](https://aantron.github.io/dream/#val-multipart). [`Dream.multipart`](https://aantron.github.io/dream/#val-multipart).

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -14,7 +14,7 @@ module T = Caqti_type
let list_comments = let list_comments =
let query = let query =
let open Caqti_request.Infix in let open Caqti_request.Infix in
(T.unit ->* T.(tup2 int string)) (T.unit ->* T.(t2 int string))
"SELECT id, text FROM comment" in "SELECT id, text FROM comment" in
fun (module Db : DB) -> fun (module Db : DB) ->
let%lwt comments_or_error = Db.collect_list query () in let%lwt comments_or_error = Db.collect_list query () in
@ -72,8 +72,8 @@ let () =
<br> <br>
Try visiting [http://localhost:8080](http://localhost:8080) Try visiting [http://localhost:8080](http://localhost:8080) and leaving some
[[playground](http://dream.as/h-sql)] and leaving some comments! comments!
![Comments](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/sql.png) ![Comments](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/sql.png)
@ -82,7 +82,7 @@ Try visiting [http://localhost:8080](http://localhost:8080)
We take the opportunity to try out We take the opportunity to try out
[`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions), which [`Dream.sql_sessions`](https://aantron.github.io/dream/#val-sql_sessions), which
stores session data persistently in `db.sqlite`. See example stores session data persistently in `db.sqlite`. See example
[**`b-session`**](../b-session#files) for an introduction to session management. [**`b-session`**](../b-session#folders-and-files) for an introduction to session management.
Both the comments and the sessions survive server restarts. Both the comments and the sessions survive server restarts.
<br> <br>
@ -132,7 +132,7 @@ We also had to make an addition to our
SQLite is good for small-to-medium sites and examples. For a larger site, SQLite is good for small-to-medium sites and examples. For a larger site,
microservices, or other needs, you can switch, for example, to PostgreSQL. See microservices, or other needs, you can switch, for example, to PostgreSQL. See
[**`w-postgres`**](../w-postgres#files). [**`w-postgres`**](../w-postgres#folders-and-files).
A good program for examining databases locally is A good program for examining databases locally is
[Beekeeper Studio](https://www.beekeeperstudio.io/). Dream might also integrate [Beekeeper Studio](https://www.beekeeperstudio.io/). Dream might also integrate
@ -156,9 +156,9 @@ See
**Next steps:** **Next steps:**
- [**`i-graphql`**](../i-graphql#files) handles GraphQL queries and serves - [**`i-graphql`**](../i-graphql#folders-and-files) handles GraphQL queries and serves
GraphiQL. GraphiQL.
- [**`j-stream`**](../j-stream#files) streams response bodies to clients. - [**`j-stream`**](../j-stream#folders-and-files) streams response bodies to clients.
<br> <br>

View File

@ -6,3 +6,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -63,8 +63,8 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) Visit [http://localhost:8080](http://localhost:8080), and you can interact with
[[playground](http://dream.as/i-graphql)], and you can interact with the schema: the schema:
![GraphiQL](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/graphiql.png) ![GraphiQL](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/graphiql.png)
@ -89,17 +89,17 @@ GraphiQL conditionally, only during development.
**Next steps:** **Next steps:**
- [**`j-stream`**](../j-stream#files) streams response bodies to clients. - [**`j-stream`**](../j-stream#folders-and-files) streams response bodies to clients.
- [**`k-websocket`**](../k-websocket#files) sends and receives messages over a - [**`k-websocket`**](../k-websocket#folders-and-files) sends and receives messages over a
WebSocket. WebSocket.
<br> <br>
**See also:** **See also:**
- [**`r-graphql`**](../r-graphql#files) is a version of this example in Reason - [**`r-graphql`**](../r-graphql#folders-and-files) is a version of this example in Reason
syntax. syntax.
- [**`w-graphql-subscription`**](../w-graphql-subscription#files) for GraphQL - [**`w-graphql-subscription`**](../w-graphql-subscription#folders-and-files) for GraphQL
subscriptions. subscriptions.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -2,7 +2,7 @@
<br> <br>
In example [**`6-echo`**](../6-echo#files), we echoed `POST` requests by reading In example [**`6-echo`**](../6-echo#folders-and-files), we echoed `POST` requests by reading
their whole bodies into memory, and then writing them. Here, we echo request their whole bodies into memory, and then writing them. Here, we echo request
bodies chunk by chunk: bodies chunk by chunk:
@ -36,8 +36,6 @@ let () =
<b>$ opam install --deps-only --yes .</b> <b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./stream.exe</b></code></pre> <b>$ dune exec --root . ./stream.exe</b></code></pre>
Try running it in the [playground](http://dream.as/j-stream).
<br> <br>
You can test it by running You can test it by running
@ -62,9 +60,9 @@ See [*Streams*](https://aantron.github.io/dream/#streams) in the API docs.
**Next steps:** **Next steps:**
- [**`k-websocket`**](../k-websocket#files) sends and receives messages over a - [**`k-websocket`**](../k-websocket#folders-and-files) sends and receives messages over a
WebSocket. WebSocket.
- [**`l-https`**](../l-https#files) enables HTTPS, which is very easy with - [**`l-https`**](../l-https#folders-and-files) enables HTTPS, which is very easy with
Dream. Dream.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -54,8 +54,8 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) Visit [http://localhost:8080](http://localhost:8080) to get the whole exchange
[[playground](http://dream.as/k-websocket)] to get the whole exchange started! started!
![WebSocket alert](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/websocket.png) ![WebSocket alert](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/websocket.png)
@ -78,14 +78,14 @@ See [*WebSockets*](https://aantron.github.io/dream/#websockets) in the API docs.
**Last step:** **Last step:**
- [**`l-https`**](../l-https#files) enables HTTPS. - [**`l-https`**](../l-https#folders-and-files) enables HTTPS.
<br> <br>
**See also:** **See also:**
- [**`w-chat`**](../w-chat#files) is a simple WebSocket-based chat application. - [**`w-chat`**](../w-chat#folders-and-files) is a simple WebSocket-based chat application.
- [**`w-live-reload`**](../w-live-reload#files) uses WebSockets to implement - [**`w-live-reload`**](../w-live-reload#folders-and-files) uses WebSockets to implement
live reloading. live reloading.
- [**`w-graphql-subscription`**](../w-graphql-subscription) does not show a - [**`w-graphql-subscription`**](../w-graphql-subscription) does not show a
WebSocket directly, but shows GraphQL subscriptions, which are implemented WebSocket directly, but shows GraphQL subscriptions, which are implemented

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -42,7 +42,7 @@ cd $DIRECTORY
echo echo
echo -e "\e[0m✅ Fetching example files using git\e[0m" echo -e "\e[0m✅ Fetching example files using git\e[0m"
echo -e "\e[0m Source: $REPO/tree/$REF/example/$EXAMPLE#files\e[0m" echo -e "\e[0m Source: $REPO/tree/$REF/example/$EXAMPLE#folders-and-files\e[0m"
mkdir clone mkdir clone
cd clone cd clone
git init --quiet git init --quiet
@ -81,7 +81,7 @@ echo " dune exec ./$EXE --watch"
echo echo
echo -e "\e[0m✅ See\e[0m" echo -e "\e[0m✅ See\e[0m"
echo echo
echo " - This example:" $REPO/tree/$REF/example/$EXAMPLE#files echo " - This example:" $REPO/tree/$REF/example/$EXAMPLE#folders-and-files
echo " - Tutorial: " $REPO/tree/$REF/example#tutorial echo " - Tutorial: " $REPO/tree/$REF/example#tutorial
echo echo
echo 💲 dune exec ./$EXE echo 💲 dune exec ./$EXE

View File

@ -87,12 +87,12 @@ example in OCaml syntax.
**See also:** **See also:**
- [**`w-watch`**](../w-fswatch#files) sets up a development watcher. - [**`w-watch`**](../w-fswatch#folders-and-files) sets up a development watcher.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
self-contained binary. self-contained binary.
- [**`7-template`**](../7-template#files) discusses the templater, including - [**`7-template`**](../7-template#folders-and-files) discusses the templater, including
security. The example is in OCaml syntax. security. The example is in OCaml syntax.
- [**`r-template`**](../r-template#files) the code of the template example in - [**`r-template`**](../r-template#folders-and-files) the code of the template example in
Reason syntax. Reason syntax.
<br> <br>

View File

@ -8,3 +8,10 @@ depends: [
"melange-webapi" "melange-webapi"
"reason" {>= "3.10.0"} "reason" {>= "3.10.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -74,8 +74,8 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) Visit [http://localhost:8080](http://localhost:8080), and you can interact with
[[playground](http://dream.as/r-graphql)], and you can interact with the schema: the schema:
![GraphiQL](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/graphiql.png) ![GraphiQL](https://raw.githubusercontent.com/aantron/dream/master/docs/asset/graphiql.png)
@ -83,9 +83,9 @@ Visit [http://localhost:8080](http://localhost:8080)
**See also:** **See also:**
- [**`i-graphql`**](../i-graphql#files), the OCaml version of this example, for - [**`i-graphql`**](../i-graphql#folders-and-files), the OCaml version of this example, for
some more discussion. some more discussion.
- [**`w-graphql-subscription`**](../w-graphql-subscription#files) for GraphQL - [**`w-graphql-subscription`**](../w-graphql-subscription#folders-and-files) for GraphQL
subscriptions. subscriptions.
<br> <br>

View File

@ -19,9 +19,8 @@ let () =
<br> <br>
After starting it, visit [http://localhost:8080](http://localhost:8080), or use After starting it, visit [http://localhost:8080](http://localhost:8080), and it
the [playground](http://dream.as/r-hello), and it will respond with its friendly will respond with its friendly greeting!
greeting!
<br> <br>
@ -38,7 +37,7 @@ Note that we had to make an addition to
**See also:** **See also:**
- [**`r-template`**](../r-template#files) shows templates with Reason syntax. - [**`r-template`**](../r-template#folders-and-files) shows templates with Reason syntax.
- [**`2-middleware`**](../2-middleware) introduces the *logger*, the most - [**`2-middleware`**](../2-middleware) introduces the *logger*, the most
commonly used Dream middleware. The example is in OCaml syntax. commonly used Dream middleware. The example is in OCaml syntax.

View File

@ -0,0 +1,67 @@
# `r-html_of_jsx`
<br>
[html_of_jsx](https://github.com/davesnx/html_of_jsx/) can be used together with Reason's built-in JSX syntax for generating HTML on the server:
```reason
let greet = (~who, ()) =>
<html>
<head><title>"Home"</title></head>
<body>
<h1>{Jsx.txt("Good morning, " ++ who ++ "!")}</h1>
</body>
</html>;
let () =
Dream.run
@@ Dream.logger
@@ Dream.router([
Dream.get("/",
(_ => Dream.html(Jsx.render(<greet who="world" />))))),
]);
```
<pre><code><b>$ cd example/r-tyxml</b>
<b>$ npm install esy && npx esy</b>
<b>$ npx esy start</b></code></pre>
<br>
To get this, we depend on package `html_of_jsx` in
[`esy.json`](https://github.com/aantron/dream/blob/master/example/r-html_of_jsx/esy.json):
<pre><code>{
"dependencies": {
"@opam/dream": "1.0.0~alpha4",
"@opam/dune": "^2.0",
"@opam/reason": "^3.8.0",
<b>"@opam/html_of_jsx": "*",</b>
"ocaml": "4.14.x"
},
"scripts": {
"start": "dune exec --root . ./html_of_jsx.exe"
}
}
</code></pre>
and add `html_of_jsx.ppx` to our preprocessor list in
[`dune`](https://github.com/aantron/dream/blob/master/example/r-html_of_jsx/dune):
<pre><code>(executable
(name html_of_jsx)
(libraries dream html_of_jsx)
<b>(preprocess (pps lwt_ppx html_of_jsx.ppx)))</b>
</code></pre>
<br>
**See also:**
- [**`html_of_jsx`](https://github.com/davesnx/html_of_jsx/)
<br>
[Up to the example index](../#reason)

View File

@ -0,0 +1,6 @@
(executable
(name html_of_jsx)
(libraries dream html_of_jsx)
(preprocess (pps lwt_ppx html_of_jsx.ppx)))
(data_only_dirs _esy esy.lock lib node_modules)

View File

@ -0,0 +1 @@
(lang dune 2.0)

View File

@ -0,0 +1,20 @@
{
"dependencies": {
"@opam/conf-libssl": "3",
"@opam/dream": "1.0.0~alpha5",
"@opam/dune": "^3.0",
"@opam/reason": "^3.8.0",
"@opam/html_of_jsx": "0.0.4",
"ocaml": "^4.14.0"
},
"devDependencies": {
"@opam/ocaml-lsp-server": "*"
},
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829",
"esy-openssl": "esy-packages/esy-openssl#619ae2d46ca981ec26ab3287487ad98b157a01d1"
},
"scripts": {
"start": "dune exec --root . ./html_of_jsx.exe"
}
}

View File

@ -0,0 +1,17 @@
let greet = (~who, ()) =>
<html>
<head><title>"Home"</title></head>
<body>
<h1>{JSX.string("Good morning, " ++ who ++ "!")}</h1>
</body>
</html>;
let () =
Dream.run
@@ Dream.logger
@@ Dream.router([
Dream.get("/",
(_ => Dream.html(JSX.render(<greet who="world" />)))),
]);

View File

@ -3,7 +3,7 @@
<br> <br>
This example splits the code of the basic template example, This example splits the code of the basic template example,
[**`r-template`**](../r-template#files), into two files. The first is the [**`r-template`**](../r-template#folders-and-files), into two files. The first is the
template, in template, in
[`template.eml.html`](https://github.com/aantron/dream/blob/master/example/r-template-files/template.eml.html). We use the `.html` extension because it is [`template.eml.html`](https://github.com/aantron/dream/blob/master/example/r-template-files/template.eml.html). We use the `.html` extension because it is
mostly HTML, and to prevent `refmt` from trying to format the file: mostly HTML, and to prevent `refmt` from trying to format the file:
@ -57,8 +57,8 @@ file:
**See also:** **See also:**
- [**`r-template`**](../r-template#files) for the one-file version. - [**`r-template`**](../r-template#folders-and-files) for the one-file version.
- [**`7-template`**](../7-template#files) for comments on [security - [**`7-template`**](../7-template#folders-and-files) for comments on [security
information](../7-template#security). information](../7-template#security).
- [**`w-template-files`**](../w-template-files) for the OCaml version of this - [**`w-template-files`**](../w-template-files) for the OCaml version of this
example. example.

View File

@ -70,14 +70,12 @@ let () =
<b>$ npm install esy && npx esy</b> <b>$ npm install esy && npx esy</b>
<b>$ npx esy start</b></code></pre> <b>$ npx esy start</b></code></pre>
Try it in the [playground](http://dream.as/r-template-logic).
<br> <br>
**See also:** **See also:**
- [**`7-template`**](../7-template#files) for basic information about templates. - [**`7-template`**](../7-template#folders-and-files) for basic information about templates.
- [**`w-template-logic`**](../w-template-logic#files) for the OCaml version - [**`w-template-logic`**](../w-template-logic#folders-and-files) for the OCaml version
of this example. of this example.
<br> <br>

View File

@ -35,8 +35,7 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) Visit [http://localhost:8080](http://localhost:8080) to see it in action.
[[playground](http://dream.as/r-template-stream)] to see it in action.
The important differences with regular usage of templates are: The important differences with regular usage of templates are:
@ -50,7 +49,7 @@ The important differences with regular usage of templates are:
name `response`. name `response`.
- We use the promise library [Lwt](https://github.com/ocsigen/lwt) inside the - We use the promise library [Lwt](https://github.com/ocsigen/lwt) inside the
template for asynchronous control flow. See example template for asynchronous control flow. See example
[**`5-promise`**](../5-promise#files) for an introduction to Lwt. [**`5-promise`**](../5-promise#folders-and-files) for an introduction to Lwt.
The call to [`Dream.flush`](https://aantron.github.io/dream/#val-flush) isn't The call to [`Dream.flush`](https://aantron.github.io/dream/#val-flush) isn't
necessary in most real-world cases &mdash; Dream's HTTP layer automatically necessary in most real-world cases &mdash; Dream's HTTP layer automatically
@ -61,11 +60,11 @@ interactive, so we force writing of all output after generating each `<p>` tag.
**See also:** **See also:**
- [**`r-template`**](../r-template#files) for the simpler way to do templates, - [**`r-template`**](../r-template#folders-and-files) for the simpler way to do templates,
building up entire bodies as strings. building up entire bodies as strings.
- [**`7-template`**](../7-template#security) section *Security* for XSS - [**`7-template`**](../7-template#security) section *Security* for XSS
prevention considerations. prevention considerations.
- [**`w-template-stream`**](../w-template-stream#files) is the OCaml version of - [**`w-template-stream`**](../w-template-stream#folders-and-files) is the OCaml version of
this example. this example.
<br> <br>

View File

@ -30,8 +30,6 @@ let () =
<b>$ npm install esy && npx esy</b> <b>$ npm install esy && npx esy</b>
<b>$ npx esy start</b></code></pre> <b>$ npx esy start</b></code></pre>
Try it in the [playground](http://dream.as/r-template).
<br> <br>
To use the templater, we need to add a stanza to our To use the templater, we need to add a stanza to our
@ -61,11 +59,11 @@ same.
**See also:** **See also:**
- [**`r-template-files`**](../r-template-files#files) puts the template into a - [**`r-template-files`**](../r-template-files#folders-and-files) puts the template into a
separate `.eml.html` file, which can help with editor problems. separate `.eml.html` file, which can help with editor problems.
- [**`r-template-stream`**](../r-template-stream#files) streams a template to a - [**`r-template-stream`**](../r-template-stream#folders-and-files) streams a template to a
response. response.
- [**`9-error`**](../9-error#files) sets up a central error template. The - [**`9-error`**](../9-error#folders-and-files) sets up a central error template. The
example is in OCaml syntax. example is in OCaml syntax.
<br> <br>

View File

@ -2,9 +2,8 @@
<br> <br>
[TyXML](https://github.com/ocsigen/tyxml) can be used [TyXML](https://github.com/ocsigen/tyxml) can be used together with Reason's
[[playground](http://dream.as/r-tyxml)] together with Reason's built-in JSX built-in JSX syntax for generating HTML on the server:
syntax for generating HTML on the server:
```reason ```reason
open Tyxml open Tyxml
@ -77,7 +76,7 @@ Error: Unbound value html
**See also:** **See also:**
- [**`w-tyxml`**](../w-tyxml#files) for an introduction to TyXML. - [**`w-tyxml`**](../w-tyxml#folders-and-files) for an introduction to TyXML.
- [**`7-template`**](../7-template#security) section *Security* on output - [**`7-template`**](../7-template#security) section *Security* on output
security. TyXML escapes strings by default, just as the built-in templater security. TyXML escapes strings by default, just as the built-in templater
does. does.

View File

@ -34,10 +34,7 @@ The rest of the code hooks up the client's message form to the WebSocket.
<br> <br>
Open [http://localhost:8080](http://localhost:8080) in two tabs to get the Open [http://localhost:8080](http://localhost:8080) in two tabs to get the
whole exchange started! You can also try it in the whole exchange started!
[playground](http://dream.as/w-chat). To connect a second tab, copy out the
address from the playground's location bar, and paste it into a new tab in your
browser.
<br> <br>
@ -48,7 +45,7 @@ scheme, rather than `ws://`, on the client.
**See also:** **See also:**
- [**k-websocket**](../k-websocket#files) for an introduction to WebSockets. - [**k-websocket**](../k-websocket#folders-and-files) for an introduction to WebSockets.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -49,10 +49,9 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) Visit [http://localhost:8080](http://localhost:8080), and your browser should
[[playground](http://dream.as/w-content-security-policy)], and your browser refuse to show `/nested` inside the frame on the home page. In addition, the
should refuse to show `/nested` inside the frame on the home page. In addition, server log will show something like
the server log will show something like
``` ```
09.06.21 09:54:35.971 ERROR REQ 3 { 09.06.21 09:54:35.971 ERROR REQ 3 {

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -0,0 +1,67 @@
# `w-dream-html`
<br>
[Dream-html](https://github.com/yawaramin/dream-html) can be used with Dream for
generating HTML. Dream-html is a library that offers functions for generating
HTML, SVG, and MathML, as well as out-of-the-box support for
[htmx](https://htmx.org/) attributes. It is closely integrated with Dream for
convenience.
```ocaml
let greet who =
let open Dream_html in
let open HTML in
html [lang "en"] [
head [] [
title [] "Greeting";
];
comment "Embedded in the HTML";
body [] [
h1 [] [txt "Good morning, %s!" who];
];
]
let () =
Dream.run
@@ Dream.logger
@@ Dream.router [
Dream.get "/"
(fun _ -> Dream_html.respond (greet "world"));
]
```
<pre><code><b>$ cd example/w-dream-html</b>
<b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./main.exe</b></code></pre>
Try it in the [playground](https://dream.as/w-dream-html).
Some notes:
- All text nodes and attributes are HTML-escaped by default for security, with
exceptions noted in the documentation
- All text nodes and attributes accept format strings for conveniently embedding
variables in the HTML
- Functions like `Dream_html.respond`, `Dream_html.send`, `Dream_html.csrf_tag`
provide convenient integration with Dream
- The `<!DOCTYPE html>` prefix is automatically rendered before the `<html>` tag
- The `SVG` and `MathML` modules provide their corresponding markup. The `Hx`
module provides htmx attributes.
<br>
<br>
**See also:**
- [**`7-template`**](../7-template#security) section *Security* on output
security. Dream-html escapes strings by default, just as the built-in templater
does.
- [**`w-tyxml`**](../w-tyxml#folders-and-files) is a similar library that also generates
HTML, with different design tradeoffs.
<br>
[Up to the example index](../#examples)

View File

@ -0,0 +1,3 @@
(executable
(name html)
(libraries dream-html))

View File

@ -0,0 +1 @@
(lang dune 2.0)

View File

@ -0,0 +1,23 @@
let greet who =
let open Dream_html in
let open HTML in
html [lang "en"] [
head [] [
title [] "Greeting";
];
comment "Embedded in the HTML";
body [] [
h1 [] [txt "Good morning, %s!" who];
];
]
let () =
Dream.run
@@ Dream.logger
@@ Dream.router [
Dream.get "/"
(fun _ -> Dream_html.respond (greet "world"));
]

View File

@ -0,0 +1,14 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream-html" {>= "3.3.1"}
"dune" {>= "2.0.0"}
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -55,7 +55,7 @@ You can then use the `esy` command without the `npx` prefix.
If you need to run multiple build steps before `dune exec`, use If you need to run multiple build steps before `dune exec`, use
[`esy.build`](https://esy.sh/docs/en/configuration.html#esybuild). Here is an [`esy.build`](https://esy.sh/docs/en/configuration.html#esybuild). Here is an
example from [**`w-fullstack-jsoo`**](../w-fullstack-jsoo#files): example from [**`w-fullstack-jsoo`**](../w-fullstack-jsoo#folders-and-files):
```json ```json
"esy": { "esy": {
@ -124,12 +124,12 @@ See the examples linked below.
**See also:** **See also:**
- [**`w-fullstack-rescript`**](../w-fullstack-rescript#files) for full-stack - [**`w-fullstack-rescript`**](../w-fullstack-rescript#folders-and-files) for full-stack
development with ReScript. development with ReScript.
- [**`r-fullstack-melange`**](../r-fullstack-melange#files) for full-stack - [**`r-fullstack-melange`**](../r-fullstack-melange#folders-and-files) for full-stack
development with Melange and Reason syntax. development with Melange and Reason syntax.
- [**`w-fswatch`**](../w-fswatch#files) for a development watcher. - [**`w-fswatch`**](../w-fswatch#folders-and-files) for a development watcher.
- [**`w-one-binary`**](../w-one-binary#files) for bundling assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) for bundling assets into a
self-contained binary. self-contained binary.
<br> <br>

View File

@ -94,7 +94,7 @@ request, like this:
<br> <br>
After starting the server, visit [http://localhost:8080](http://localhost:8080) After starting the server, visit [http://localhost:8080](http://localhost:8080)
[[playground](http://dream.as/w-flash)] to start this little interaction! to start this little interaction!
<br> <br>
@ -107,7 +107,7 @@ blows up their original size by 4/3.
**See also:** **See also:**
- [**`c-cookie`**](../c-cookie#files) shows cookie handling, the mechanism that - [**`c-cookie`**](../c-cookie#folders-and-files) shows cookie handling, the mechanism that
flash messages are implemented over. flash messages are implemented over.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -70,7 +70,7 @@ Then visit [http://localhost:8080](http://localhost:8080), and you will see...
**See also:** **See also:**
- [**`w-one-binary`**](../w-one-binary#files) for bundling assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) for bundling assets into a
self-contained binary. self-contained binary.
<br> <br>

View File

@ -7,3 +7,10 @@ depends: [
"js_of_ocaml" "js_of_ocaml"
"js_of_ocaml-ppx" "js_of_ocaml-ppx"
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -85,12 +85,12 @@ client in `./static/client.js`. The example serves the bundled client using
**See also:** **See also:**
- [**`w-esy`**](../w-esy#files) details the server's [esy](https://esy.sh/) - [**`w-esy`**](../w-esy#folders-and-files) details the server's [esy](https://esy.sh/)
packaging. packaging.
- [**`w-fswatch`**](../w-fswatch#files) sets up a primitive development watcher. - [**`w-fswatch`**](../w-fswatch#folders-and-files) sets up a primitive development watcher.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a - [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
self-contained binary. self-contained binary.
- [**`f-static`**](../r-hello#files) presents - [**`f-static`**](../r-hello#folders-and-files) presents
[`Dream.static`](https://aantron.github.io/dream/#val-static). [`Dream.static`](https://aantron.github.io/dream/#val-static).
<br> <br>

View File

@ -56,8 +56,7 @@ let () =
<br> <br>
Visit [http://localhost:8080](http://localhost:8080) or the Visit [http://localhost:8080](http://localhost:8080), and run
[playground](http://dream.as/w-graphql-subscription), and run
```graphql ```graphql
subscription { subscription {
@ -80,8 +79,8 @@ similar.
**See also:** **See also:**
- [**`i-graphql`**](../i-graphql#files) for a basic GraphQL example. - [**`i-graphql`**](../i-graphql#folders-and-files) for a basic GraphQL example.
- [**`k-websocket`**](../k-websocket#files) for direct WebSocket usage. - [**`k-websocket`**](../k-websocket#folders-and-files) for direct WebSocket usage.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -50,7 +50,7 @@ Good morning, world! Random tag: jRak
<br> <br>
This example plays very well with [**`w-watch`**](../w-watch#files), which shows This example plays very well with [**`w-watch`**](../w-watch#folders-and-files), which shows
how to rebuild and restart a development server every time sources are modified how to rebuild and restart a development server every time sources are modified
in the file system. Combining the two examples, it is possible to propagate in the file system. Combining the two examples, it is possible to propagate
reloading all the way to the client, whenever any of the server's source code reloading all the way to the client, whenever any of the server's source code
@ -60,8 +60,8 @@ changes.
**See also:** **See also:**
- [**`k-websocket`**](../k-websocket#files) introduces WebSockets. - [**`k-websocket`**](../k-websocket#folders-and-files) introduces WebSockets.
- [**`w-watch`**](../w-watch#files) rebuilds and restarts a server each - [**`w-watch`**](../w-watch#folders-and-files) rebuilds and restarts a server each
time its source code changes. time its source code changes.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -3,7 +3,7 @@
<br> <br>
*Long polling* is a technique, largely made obsolete by *Long polling* is a technique, largely made obsolete by
[WebSockets](../k-websocket#files), where a client sends a request, but the [WebSockets](../k-websocket#folders-and-files), where a client sends a request, but the
server does not respond until some data is available. This delayed response server does not respond until some data is available. This delayed response
works as a sort of “push” from the client's point of view, because it comes at works as a sort of “push” from the client's point of view, because it comes at
a time of the server's choosing. a time of the server's choosing.
@ -42,13 +42,11 @@ the client immediately. If a client sends the next request before any more
messages are generated, the server waits to respond &mdash; hence, “long messages are generated, the server waits to respond &mdash; hence, “long
polling.” polling.”
Try it in the [playground](http://dream.as/w-long-polling).
<br> <br>
**See also:** **See also:**
- [**`k-websocket`**](../k-websocket#files) for a more modern way of achieving - [**`k-websocket`**](../k-websocket#folders-and-files) for a more modern way of achieving
asynchronous client-server communication. asynchronous client-server communication.
<br> <br>

View File

@ -5,3 +5,10 @@ depends: [
"dream" "dream"
"dune" {>= "2.0.0"} "dune" {>= "2.0.0"}
] ]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

View File

@ -45,7 +45,7 @@ end
<br> <br>
It's the basic example [**`2-middleware`**](../2-middleware#files) adapted to It's the basic example [**`2-middleware`**](../2-middleware#folders-and-files) adapted to
Mirage. To build and run, do Mirage. To build and run, do
<pre><code><b>$ cd example/w-mirage</b> <pre><code><b>$ cd example/w-mirage</b>

35
example/w-mlx/README.md Normal file
View File

@ -0,0 +1,35 @@
# `w-mlx`
<br>
[mlx](https://github.com/ocaml-mlx/mlx), an OCaml syntax dialect which adds JSX
expressions, can be used with Dream for generating HTML.
```ocaml
let greet ~who () =
<html>
<head>
<title>"Greeting"</title>
</head>
<body>
<h1>"Good morning, " (JSX.string who) "!"</h1>
</body>
</html>
let () =
Dream.run
@@ Dream.logger
@@ Dream.router [
Dream.get "/" (fun _ ->
let html = JSX.render <greet who="world" /> in
Dream.html html)
]
```
<pre><code><b>$ cd example/w-mlx</b>
<b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./mlx.exe</b></code></pre>
<br>
[Up to the example index](../#examples)

4
example/w-mlx/dune Normal file
View File

@ -0,0 +1,4 @@
(executable
(name mlx)
(libraries dream html_of_jsx)
(preprocess (pps html_of_jsx.ppx)))

View File

@ -0,0 +1,10 @@
(lang dune 3.16)
(dialect
(name mlx)
(implementation
(merlin_reader mlx)
(extension mlx)
(preprocess
(run mlx-pp %{input-file}))))

View File

18
example/w-mlx/mlx.mlx Normal file
View File

@ -0,0 +1,18 @@
let greet ~who () =
<html>
<head>
<title>"Greeting"</title>
</head>
<body>
<h1>"Good morning, " (JSX.string who) "!"</h1>
</body>
</html>
let () =
Dream.run
@@ Dream.logger
@@ Dream.router [
Dream.get "/" (fun _ ->
let html = JSX.render <greet who="world" /> in
Dream.html html)
]

16
example/w-mlx/w-mlx.opam Normal file
View File

@ -0,0 +1,16 @@
opam-version: "2.0"
depends: [
"ocaml" {>= "4.08.0"}
"dream"
"dune" {>= "3.16.0"}
"mlx"
"html_of_jsx"
]
synopsis: "One of the Dream examples"
homepage: "https://github.com/aantron/dream"
bug-reports: "https://github.com/aantron/dream/issues"
author: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"

Some files were not shown because too many files have changed in this diff Show More