Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example with PostgreSQL and Docker Compose. #112

Merged
merged 3 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
with:
ocaml-version: ${{matrix.ocaml}}

- run: opam depext --yes conf-postgresql
- run: opam depext --yes conf-libev
- run: opam install --yes --deps-only --with-test .
- run: opam exec -- dune runtest
Expand Down
1 change: 1 addition & 0 deletions dream.opam
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ depends: [
# Testing, development.
"alcotest" {with-test}
"bisect_ppx" {with-test & >= "2.5.0"} # --instrument-with.
"caqti-driver-postgresql" {with-test}
"caqti-driver-sqlite3" {with-test}
"crunch" {with-test}
"lambdasoup" {with-test}
Expand Down
4 changes: 3 additions & 1 deletion example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ if something is missing!
 —  benchmarks sending WebSocket messages quickly.
- [**`w-multipart-dump`**](w-multipart-dump#files)  —  echoes
`multipart/form-data` bodies for debugging.
- [**`w-docker-postgres`**](w-docker-postgres#files)
 —  illustrates how to run Dream and
PostgreSQL in Docker containers using Docker Compose.
- [**`z-playground`**](z-playground#files)  —  source code of
the Dream playground.

Expand Down Expand Up @@ -187,7 +190,6 @@ Techniques:
- `w-graphql-sql`
- `w-graphql-mutation`
- `w-https-redirect`
- `w-postgres-docker`
- `w-sql-stream`
- `w-websocket-stream`

Expand Down
13 changes: 13 additions & 0 deletions example/w-docker-postgres/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# esy build environment
_esy/

# esy dependencies
node_modules/

# git
.git/
.gitignore

# Development
Dockerfile
docker-compose.yml
24 changes: 24 additions & 0 deletions example/w-docker-postgres/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM ocaml/opam:alpine as build

# Install system dependencies
RUN sudo apk add --update libev-dev openssl-dev libpq postgresql-dev

WORKDIR /home/opam

# Install dependencies
ADD app.opam app.opam
RUN opam install . --deps-only

# Build project
ADD . .
RUN opam exec -- dune build



FROM alpine:3.12 as run

RUN apk add --update libev libpq postgresql-dev

COPY --from=build /home/opam/_build/default/app.exe /bin/app

ENTRYPOINT /bin/app
83 changes: 83 additions & 0 deletions example/w-docker-postgres/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# `w-docker-postgres`

<br>

This example illustrates how to use
[Docker](https://en.wikipedia.org/wiki/Docker_(software)) and
[docker-compose](https://docs.docker.com/compose/) to manage a simple
web server with a Postgres database.

Running a database under docker can simplify the process of setting up
a development environment. This is especially true if your application
uses several databases or services and you want a convenient way to
manage them all with a single tool.

The example app allows users to see a list of existing comments and
post new comments. Take a look at this
[example](https://github.com/aantron/dream/tree/master/example/h-sql#files)
for more background information.

## Getting Set Up

Start your docker containers by running `docker-compose up -d`. It
will take some time to build the `web` container; subsequent rebuilds
are faster.

When both containers are available, you should see:
```
Creating network "w-docker-postgres_default" with the default driver
Creating w-docker-postgres_postgres_1 ... done
Creating w-docker-postgres_web_1 ... done
```

At this point the PostgreSQL database is ready but doesn't have any
tables. Fix that by running:

```
docker-compose exec postgres psql -U dream -c "$(cat schema.sql)"
```

This will create the `comment` and `dream_session` tables described in
`schema.sql`.

Finally, open your browser to
[`http://localhost:8080/`](http://localhost:8080/) to try the
application.


## Tips

If you modify `app.eml.ml`, you will need to run
```
docker-compose build && docker-compose up web
```
to rebuild the `web` container and see your changes.

To view the logs from the API container (rather than having them mixed
in with the logs from the database) run:
```
docker-compose logs web -f
```

The database container contains a copy of the `psql` client. Running

```
docker-compose exec postgres psql -U dream
```

will allow you to start the client and run queries interactively.

<br>

**See also:**

- [**`h-sql`**](../h-sql#files) this example contains essentially the
same application, but uses sqlite.
- [**`z-docker-esy`**](../z-docker-esy#files) describes how to deploy
with docker-compose and esy.
- [**`z-docker-opam`**](../z-docker-opam#files) describes how to deploy
with docker-compose and opam.

<br>

[Up to the example index](../#examples)
58 changes: 58 additions & 0 deletions example/w-docker-postgres/app.eml.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module type DB = Caqti_lwt.CONNECTION
module R = Caqti_request
module T = Caqti_type


let list_comments =
let query =
R.collect 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
Caqti_lwt.or_fail comments_or_error


let add_comment =
let query =
R.exec T.string
"INSERT INTO comment (text) VALUES ($1)" in
fun text (module Db : DB) ->
let%lwt unit_or_error = Db.exec query text in
Caqti_lwt.or_fail unit_or_error


let render comments request =
<html>
<body>
% comments |> List.iter (fun (_id, comment) ->
<p><%s comment %></p><% ); %>

<%s! Dream.form_tag ~action:"/" request %>
<input name="text" autofocus>
</form>

</body>
</html>


let () =
Dream.run ~interface:"0.0.0.0"
@@ Dream.logger
@@ Dream.sql_pool "postgresql://dream@postgres/dream"
@@ Dream.sql_sessions
@@ Dream.router [

Dream.get "/" (fun request ->
let%lwt comments = Dream.sql request list_comments in
Dream.html (render comments request));

Dream.post "/" (fun request ->
match%lwt Dream.form request with
| `Ok ["text", text] ->
let%lwt () = Dream.sql request (add_comment text) in
Dream.redirect request "/"
| _ ->
Dream.empty `Bad_Request);

]
@@ Dream.not_found
8 changes: 8 additions & 0 deletions example/w-docker-postgres/app.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
opam-version: "2.0"

depends: [
"ocaml" {>= "4.08.0"}
"dune" {>= "2.0.0"}
"dream"
"caqti-driver-postgresql"
]
20 changes: 20 additions & 0 deletions example/w-docker-postgres/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "3"

services:
postgres:
image: postgres
environment:
- POSTGRES_USER=dream
- POSTGRES_DB=dream

web:
build: .
expose:
- 8080
ports:
- "8080:8080"
links:
- postgres
restart: always
logging:
driver: ${LOGGING_DRIVER:-json-file}
12 changes: 12 additions & 0 deletions example/w-docker-postgres/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(executable
(name app)
(libraries caqti-driver-postgresql dream)
(preprocess (pps lwt_ppx))
)

(rule
(targets app.ml)
(deps app.eml.ml)
(action (run dream_eml %{deps} --workspace %{workspace_root})))

(data_only_dirs _esy esy.lock)
1 change: 1 addition & 0 deletions example/w-docker-postgres/dune-project
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(lang dune 2.0)
11 changes: 11 additions & 0 deletions example/w-docker-postgres/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE comment (
id SERIAL PRIMARY KEY,
text TEXT NOT NULL
);

CREATE TABLE dream_session (
id TEXT PRIMARY KEY,
label TEXT NOT NULL,
expires_at REAL NOT NULL,
payload TEXT NOT NULL
);