Compare commits

..

No commits in common. "master" and "1.0.0-alpha6" have entirely different histories.

158 changed files with 1263 additions and 2184 deletions

View File

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

View File

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

View File

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

View File

@ -7,98 +7,101 @@ jobs:
fail-fast: false
matrix:
os:
# Until https://github.com/ocaml/setup-ocaml/issues/872.
# When fixing, search for other instances of this string in this file.
- ubuntu-22.04
- ubuntu-latest
ocaml:
- 5.2.x
- 5.0.x
- 4.14.x
- 4.13.x
- 4.12.x
- 4.11.x
- 4.10.x
- 4.09.x
- 4.08.x
include:
- os: macos-latest
ocaml: 4.14.x
ocaml: 4.12.x
- os: windows-latest
ocaml: 4.14.x
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: ocaml/setup-ocaml@v3
- uses: avsm/setup-ocaml@v2
if: runner.os != 'Windows'
with:
ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
# 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
- uses: avsm/setup-ocaml@v2
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 exec -- make deps
- 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
- run: opam depext --yes conf-sqlite3
- run: opam depext --yes conf-postgresql
- run: opam depext --yes conf-libev
if: runner.os != 'Windows'
- run: opam lint --recursive example
- name: Build examples
if: runner.os != 'Windows'
# The tests require ppx_expect. The latest versions of it introduced changes
# 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.
- shell: bash
run: |
set -e
set -x
EXCLUDED_EXAMPLES='w-mirage*|r-tyxml|w-dream-html'
EXAMPLES=$(find example -maxdepth 1 -type d | grep -Ev $EXCLUDED_EXAMPLES | grep -v "^example/0" | grep -v "^example$" | sort)
shopt -s nullglob
for EXAMPLE in $EXAMPLES
do
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
WITH_TEST=--with-test
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
for EXAMPLE in $EXAMPLES
do
FILE=$(ls $EXAMPLE/*.ml $EXAMPLE/*.re $EXAMPLE/server/*.ml $EXAMPLE/server/*.re)
EXE=$(echo $FILE | sed 's/\..*$/.exe/g')
echo dune build $EXE
opam exec -- dune build $EXE
$OPAM exec -- dune build $EXE
done
fi
quickstart:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
ocaml:
- 5.2.x
- 4.14.x
include:
- os: macos-latest
ocaml: 4.14.x
- ubuntu-latest
- macos-latest
runs-on: ${{matrix.os}}
steps:
- uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{matrix.ocaml}}
dune-cache: true
- name: Run quickstart.sh
shell: bash
- name: Quick start
run: |
set -x
touch output
@ -114,29 +117,25 @@ jobs:
fi
mirage:
if: false
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- run: mkdir ../repo-copy
- run: cp -r * ../repo-copy/
- uses: ocaml/setup-ocaml@v3
- uses: avsm/setup-ocaml@v2
with:
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 mirage mirage-clock-unix mirage-crypto-rng-mirage
- run: opam install --yes mirage mirage-clock-unix
- 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 && opam exec -- mirage configure -t unix
- run: cd example/w-mirage && opam exec -- make depends
- run: cd example/w-mirage && ls duniverse
- 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 digestif eqaf mirage-crypto mirage-runtime
- 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 && 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 && mv dune.build.2 dune.build

16
.gitmodules vendored Normal file
View File

@ -0,0 +1,16 @@
[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-2024, Anton Bachin
Copyright (c) 2021-2023, Anton Bachin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

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

View File

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

View File

@ -1,4 +1,4 @@
ROOT := ../..
ROOT := ../..
ODOC := odoc/default/_doc/_html
.PHONY : build

View File

@ -1,7 +1,7 @@
(executable
(executable
(name index)
(modules index)
(libraries common lambdasoup str))
(libraries common lambdasoup))
(library
(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;
}
header a[href*=example], .spec-doc a[href*=example] {
a[href*=example] {
font-weight: bold;
}
header a[href^=http]::after, .spec-doc a[href^=http]::after {
a[href^=http]::after {
content: "\f35d";
font-family: FontAwesome;
font-size: 10px;
@ -434,6 +434,7 @@ p + .odoc-spec {
#val-origin_referrer_check + .spec-doc li + li,
#val-form + .spec-doc li + li,
#type-part + .spec-doc li + li,
#type-upload_event + .spec-doc li + li,
#val-upload + .spec-doc li + li,
#val-static + .spec-doc li + li,
#val-from_path + .spec-doc li + li {

View File

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

View File

@ -15,18 +15,31 @@ maintainer: "Anton Bachin <antonbachin@yahoo.com>"
depends: [
"dream-pure"
"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_ppx" {>= "1.2.2"}
"lwt_ssl"
"ocaml" {>= "4.08.0"}
"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: [

View File

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

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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
bigger handlers that do a little bit more. This example takes the handler from
[**`1-hello`**](../1-hello#folders-and-files) and wraps it in one of the most useful
[**`1-hello`**](../1-hello#files) and wraps it in one of the most useful
middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger):
```ocaml
@ -33,14 +33,15 @@ let () =
<br>
When you run this server and visit
[http://localhost:8080](http://localhost:8080), you get much more interesting
[http://localhost:8080](http://localhost:8080)
[[playground](http://dream.as/2-middleware)], you get much more interesting
(and colorful!) output:
![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
[`Dream.log`](https://aantron.github.io/dream/#val-log). See example
[**`a-log`**](../a-log#folders-and-files) for more logging options. Now that we have the
[**`a-log`**](../a-log#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
necessary &mdash; it just makes it much easier to see what is going on.
@ -48,14 +49,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
from handlers to handlers, so you can create them anywhere. Example
[**`4-counter`**](../4-counter#folders-and-files) already shows a simple custom middleware.
[**`4-counter`**](../4-counter#files) already shows a simple custom middleware.
<!--
There are also more complicated middlewares defined in
- [**`m-locals`**](../m-locals#folders-and-files),
- [**`w-auto-reload`**](../w-auto-reload#folders-and-files), and
- [**`w-index-html`**](../w-index-html#folders-and-files).
- [**`m-locals`**](../m-locals/#files),
- [**`w-auto-reload`**](../w-auto-reload/#files), and
- [**`w-index-html`**](../w-index-html/#files).
-->
<!-- TODO Fill out this list; probably a-promise belongs here. -->
@ -64,10 +65,10 @@ There are also more complicated middlewares defined in
**Next steps:**
- The next example, [**`3-router`**](../3-router#folders-and-files), shows
- The next example, [**`3-router`**](../3-router#files), shows
[*routes*](https://aantron.github.io/dream/#routing), the other way to build
up handlers in Dream.
- [**`4-counter`**](../4-counter#folders-and-files) builds the first custom middleware.
- [**`4-counter`**](../4-counter#files) builds the first custom middleware.
<br>

View File

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

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
[**`4-counter`**](../4-counter#folders-and-files) was limited to counting requests *before*
[**`4-counter`**](../4-counter#files) was limited to counting requests *before*
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
*after*. In this example, we separately count requests that were handled
@ -44,6 +44,8 @@ let () =
<b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./promise.exe</b></code></pre>
Try it in the [playground](http://dream.as/5-promise).
<br>
As you can see, the
@ -91,8 +93,8 @@ We will stick to `let%lwt` in the examples and keep things tidy.
**Next steps:**
- [**`6-echo`**](../6-echo#folders-and-files) uses Dream and Lwt to read a request body.
- [**`7-template`**](../7-template#folders-and-files) shows how to interleave HTML and
- [**`6-echo`**](../6-echo#files) uses Dream and Lwt to read a request body.
- [**`7-template`**](../7-template#files) shows how to interleave HTML and
OCaml.
<br>

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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,11 +84,15 @@ 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
this tiny Web app! First, go to
[`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. Then, visit
change the substitution to `<%s! param %>`, and restart the app. You can also
make the edit in the [playground](http://dream.as/7-template/foo). Then,
visit
this highly questionable URL:
[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
developers, did not intend!
@ -125,31 +129,27 @@ and not supported by Dream.
**Next steps:**
- [**`8-debug`**](../8-debug#folders-and-files) shows how to turn on debug responses, and
- [**`8-debug`**](../8-debug#files) shows how to turn on debug responses, and
get more info about errors.
- [**`9-error`**](../9-error#folders-and-files) sets up a central error template for all
- [**`9-error`**](../9-error#files) sets up a central error template for all
errors.
- [**`r-template`**](../r-template#folders-and-files) is a Reason syntax version of this
- [**`r-template`**](../r-template#files) is a Reason syntax version of this
example.
<br>
**See also:**
- [**`w-template-files`**](../w-template-files#folders-and-files) moves the template into a
- [**`w-template-files`**](../w-template-files#files) moves the template into a
separate `.eml.html` to avoid problems with editor support.
- [**`w-template-logic`**](../w-template-logic#folders-and-files) shows how to put control
- [**`w-template-logic`**](../w-template-logic#files) shows how to put control
flow into templates.
- [**`w-tyxml`**](../w-tyxml#folders-and-files) shows how to use
- [**`w-tyxml`**](../w-tyxml#files) shows how to use
[TyXML](https://github.com/ocsigen/tyxml), a different templater that uses
OCaml's type system to prevent emitting many kinds of invalid HTML.
- [**`r-tyxml`**](../r-tyxml#folders-and-files) if you are using Reason. You can use TyXML
- [**`r-tyxml`**](../r-tyxml#files) if you are using Reason. You can use TyXML
with JSX syntax server-side!
- [**`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
- [**`w-template-stream`**](../w-template-stream#files) streams templates to
responses, instead of building up complete response strings.
<br>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
With the session middleware from example [**`b-session`**](../b-session#folders-and-files),
With the session middleware from example [**`b-session`**](../b-session#files),
we can build a [secure form](https://aantron.github.io/dream/#forms):
```ocaml
@ -49,6 +49,8 @@ let () =
<b>$ opam install --deps-only --yes .</b>
<b>$ dune exec --root . ./form.exe</b></code></pre>
Try it in the [playground](http://dream.as/d-form).
<br>
The template adds a CSRF token to the form using
@ -100,14 +102,14 @@ important on login forms and other sensitive pages.
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
[**`h-sql`**](../h-sql#folders-and-files) for an example with a proper redirection.
[**`h-sql`**](../h-sql#files) for an example with a proper redirection.
<br>
**Next steps:**
- [**`e-json`**](../e-json#folders-and-files) receives and sends JSON.
- [**`f-static`**](../f-static#folders-and-files) serves static files from a local
- [**`e-json`**](../e-json#files) receives and sends JSON.
- [**`f-static`**](../f-static#files) serves static files from a local
directory.
<br>

View File

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

View File

@ -6,10 +6,3 @@ depends: [
"dune" {>= "2.0.0"}
"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
into your Web app binary, and then serve that directory from memory with
[`Dream.static`](https://aantron.github.io/dream/#val-static)! See example
[**`w-one-binary`**](../w-one-binary#folders-and-files).
[**`w-one-binary`**](../w-one-binary#files).
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:**
- [**`g-upload`**](../g-upload#folders-and-files) receives files instead of serving them.
- [**`h-sql`**](../h-sql#folders-and-files) runs SQL queries against a database.
- [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
- [**`g-upload`**](../g-upload#files) receives files instead of serving them.
- [**`h-sql`**](../h-sql#files) runs SQL queries against a database.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a
self-contained binary.
<br>

View File

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

View File

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

View File

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

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
Visit [http://localhost:8080](http://localhost:8080) to get the whole exchange
started!
Visit [http://localhost:8080](http://localhost:8080)
[[playground](http://dream.as/k-websocket)] to get the whole exchange started!
![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:**
- [**`l-https`**](../l-https#folders-and-files) enables HTTPS.
- [**`l-https`**](../l-https#files) enables HTTPS.
<br>
**See also:**
- [**`w-chat`**](../w-chat#folders-and-files) is a simple WebSocket-based chat application.
- [**`w-live-reload`**](../w-live-reload#folders-and-files) uses WebSockets to implement
- [**`w-chat`**](../w-chat#files) is a simple WebSocket-based chat application.
- [**`w-live-reload`**](../w-live-reload#files) uses WebSockets to implement
live reloading.
- [**`w-graphql-subscription`**](../w-graphql-subscription) does not show a
WebSocket directly, but shows GraphQL subscriptions, which are implemented

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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,10 +5,3 @@ depends: [
"dream"
"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 -e "\e[0m✅ Fetching example files using git\e[0m"
echo -e "\e[0m Source: $REPO/tree/$REF/example/$EXAMPLE#folders-and-files\e[0m"
echo -e "\e[0m Source: $REPO/tree/$REF/example/$EXAMPLE#files\e[0m"
mkdir clone
cd clone
git init --quiet
@ -81,7 +81,7 @@ echo " dune exec ./$EXE --watch"
echo
echo -e "\e[0m✅ See\e[0m"
echo
echo " - This example:" $REPO/tree/$REF/example/$EXAMPLE#folders-and-files
echo " - This example:" $REPO/tree/$REF/example/$EXAMPLE#files
echo " - Tutorial: " $REPO/tree/$REF/example#tutorial
echo
echo 💲 dune exec ./$EXE

View File

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

View File

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

View File

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

View File

@ -1,67 +0,0 @@
# `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

@ -1,6 +0,0 @@
(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

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

View File

@ -1,20 +0,0 @@
{
"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

@ -1,17 +0,0 @@
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>
This example splits the code of the basic template example,
[**`r-template`**](../r-template#folders-and-files), into two files. The first is the
[**`r-template`**](../r-template#files), into two files. The first is the
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
mostly HTML, and to prevent `refmt` from trying to format the file:
@ -57,8 +57,8 @@ file:
**See also:**
- [**`r-template`**](../r-template#folders-and-files) for the one-file version.
- [**`7-template`**](../7-template#folders-and-files) for comments on [security
- [**`r-template`**](../r-template#files) for the one-file version.
- [**`7-template`**](../7-template#files) for comments on [security
information](../7-template#security).
- [**`w-template-files`**](../w-template-files) for the OCaml version of this
example.

View File

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

View File

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

View File

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

View File

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

View File

@ -34,7 +34,10 @@ The rest of the code hooks up the client's message form to the WebSocket.
<br>
Open [http://localhost:8080](http://localhost:8080) in two tabs to get the
whole exchange started!
whole exchange started! You can also try it in the
[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>
@ -45,7 +48,7 @@ scheme, rather than `ws://`, on the client.
**See also:**
- [**k-websocket**](../k-websocket#folders-and-files) for an introduction to WebSockets.
- [**k-websocket**](../k-websocket#files) for an introduction to WebSockets.
<br>

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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

@ -1,67 +0,0 @@
# `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

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

View File

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

View File

@ -1,23 +0,0 @@
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

@ -1,14 +0,0 @@
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
[`esy.build`](https://esy.sh/docs/en/configuration.html#esybuild). Here is an
example from [**`w-fullstack-jsoo`**](../w-fullstack-jsoo#folders-and-files):
example from [**`w-fullstack-jsoo`**](../w-fullstack-jsoo#files):
```json
"esy": {
@ -124,12 +124,12 @@ See the examples linked below.
**See also:**
- [**`w-fullstack-rescript`**](../w-fullstack-rescript#folders-and-files) for full-stack
- [**`w-fullstack-rescript`**](../w-fullstack-rescript#files) for full-stack
development with ReScript.
- [**`r-fullstack-melange`**](../r-fullstack-melange#folders-and-files) for full-stack
- [**`r-fullstack-melange`**](../r-fullstack-melange#files) for full-stack
development with Melange and Reason syntax.
- [**`w-fswatch`**](../w-fswatch#folders-and-files) for a development watcher.
- [**`w-one-binary`**](../w-one-binary#folders-and-files) for bundling assets into a
- [**`w-fswatch`**](../w-fswatch#files) for a development watcher.
- [**`w-one-binary`**](../w-one-binary#files) for bundling assets into a
self-contained binary.
<br>

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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:**
- [**`w-one-binary`**](../w-one-binary#folders-and-files) for bundling assets into a
- [**`w-one-binary`**](../w-one-binary#files) for bundling assets into a
self-contained binary.
<br>

View File

@ -7,10 +7,3 @@ depends: [
"js_of_ocaml"
"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:**
- [**`w-esy`**](../w-esy#folders-and-files) details the server's [esy](https://esy.sh/)
- [**`w-esy`**](../w-esy#files) details the server's [esy](https://esy.sh/)
packaging.
- [**`w-fswatch`**](../w-fswatch#folders-and-files) sets up a primitive development watcher.
- [**`w-one-binary`**](../w-one-binary#folders-and-files) bundles assets into a
- [**`w-fswatch`**](../w-fswatch#files) sets up a primitive development watcher.
- [**`w-one-binary`**](../w-one-binary#files) bundles assets into a
self-contained binary.
- [**`f-static`**](../r-hello#folders-and-files) presents
- [**`f-static`**](../r-hello#files) presents
[`Dream.static`](https://aantron.github.io/dream/#val-static).
<br>

View File

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

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
This example plays very well with [**`w-watch`**](../w-watch#folders-and-files), which shows
This example plays very well with [**`w-watch`**](../w-watch#files), which shows
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
reloading all the way to the client, whenever any of the server's source code
@ -60,8 +60,8 @@ changes.
**See also:**
- [**`k-websocket`**](../k-websocket#folders-and-files) introduces WebSockets.
- [**`w-watch`**](../w-watch#folders-and-files) rebuilds and restarts a server each
- [**`k-websocket`**](../k-websocket#files) introduces WebSockets.
- [**`w-watch`**](../w-watch#files) rebuilds and restarts a server each
time its source code changes.
<br>

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
*Long polling* is a technique, largely made obsolete by
[WebSockets](../k-websocket#folders-and-files), where a client sends a request, but the
[WebSockets](../k-websocket#files), where a client sends a request, but the
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
a time of the server's choosing.
@ -42,11 +42,13 @@ the client immediately. If a client sends the next request before any more
messages are generated, the server waits to respond &mdash; hence, “long
polling.”
Try it in the [playground](http://dream.as/w-long-polling).
<br>
**See also:**
- [**`k-websocket`**](../k-websocket#folders-and-files) for a more modern way of achieving
- [**`k-websocket`**](../k-websocket#files) for a more modern way of achieving
asynchronous client-server communication.
<br>

View File

@ -5,10 +5,3 @@ depends: [
"dream"
"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>
It's the basic example [**`2-middleware`**](../2-middleware#folders-and-files) adapted to
It's the basic example [**`2-middleware`**](../2-middleware#files) adapted to
Mirage. To build and run, do
<pre><code><b>$ cd example/w-mirage</b>

View File

@ -1,35 +0,0 @@
# `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)

View File

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

View File

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

View File

@ -1,18 +0,0 @@
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)
]

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