diff --git a/examples/server/notes_public/index.html b/examples/server/notes_public/index.html
new file mode 100644
index 0000000..a81d83d
--- /dev/null
+++ b/examples/server/notes_public/index.html
@@ -0,0 +1,27 @@
+
+
+
+ Notes
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/server/notes_public/notes.js b/examples/server/notes_public/notes.js
new file mode 100644
index 0000000..dc53ddf
--- /dev/null
+++ b/examples/server/notes_public/notes.js
@@ -0,0 +1,33 @@
+const elNotes = document.querySelector('#notes');
+const elNoteTemplate = document.querySelector('templates ul[name="note"] li');
+
+function renderNote(note) {
+ const el = elNoteTemplate.cloneNode(true);
+ el.querySelector('h4').innerText = 'Note #' + note.id;
+ el.querySelector('p').innerText = note.content;
+ return el;
+}
+
+async function addNote() {
+ const inpEl = document.querySelector('.new-note input');
+ const content = inpEl.value;
+ const resp = await fetch('/notes/', {
+ method: "POST",
+ body: content
+ });
+ const note = await resp.json();
+ inpEl.value = '';
+ console.log(note);
+ elNotes.prepend(renderNote(note));
+}
+
+async function getNotes() {
+ const resp = await fetch("/notes");
+ const notes = await resp.json();
+ elNotes.innerHTML = '';
+ for (const note of notes) {
+ elNotes.prepend(renderNote(note));
+ }
+}
+
+getNotes();
\ No newline at end of file
diff --git a/examples/server/notes_public/styles.css b/examples/server/notes_public/styles.css
new file mode 100644
index 0000000..73f3547
--- /dev/null
+++ b/examples/server/notes_public/styles.css
@@ -0,0 +1,35 @@
+templates {
+ display: none;
+}
+
+#notes {
+ list-style-type: none;
+ padding: 0;
+}
+.note {
+ margin: 0;
+ padding: 0rem 0.3rem;
+}
+.note h4 {
+ margin: 0;
+}
+.note p {
+ color: #333;
+ margin-top: 0;
+}
+
+.new-note {
+ margin-bottom: 2rem;
+}
+.new-note input {
+ width: 15rem;
+ padding: 0.3rem;
+}
+.new-note button {
+ padding: 0.3rem 1rem;
+ background-color: #4caf50;
+ color: #fff;
+ border: none;
+ cursor: pointer;
+ font-size: 1rem;
+}
\ No newline at end of file
diff --git a/examples/server/server_spa.own b/examples/server/server_spa.own
new file mode 100644
index 0000000..16cb9be
--- /dev/null
+++ b/examples/server/server_spa.own
@@ -0,0 +1,37 @@
+use std, jdbc, server
+
+// curl -X POST http://localhost:8084/notes/ -d "New note 2"
+
+conn = getConnection("jdbc:sqlite::memory:")
+st = conn.createStatement()
+st.executeUpdate("CREATE TABLE IF NOT EXISTS notes(id integer primary key, content string)")
+stAddNote = conn.prepareStatement("INSERT INTO notes(content) VALUES(?)", RETURN_GENERATED_KEYS)
+stGetNote = conn.prepareStatement("SELECT id, content FROM notes WHERE id = ?")
+
+createNote("This is your first note.")
+
+def getNotes() {
+ notes = []
+ rs = st.executeQuery("SELECT id, content FROM notes")
+ while (rs.next()) {
+ notes += {"id": rs.getInt(1), "content": rs.getString(2)}
+ }
+ rs.close()
+ return notes
+}
+
+def createNote(content) {
+ stAddNote.setString(1, content)
+ stAddNote.executeUpdate()
+ rs = stAddNote.getGeneratedKeys()
+ rs.next()
+ return {"id": rs.getLong(1) ?? -1, "content": content}
+}
+
+newServer({"dev": true, "externalDirs": ["notes_public"]})
+ .get("/notes", def(ctx) = ctx.json( getNotes() ))
+ .post("/notes", def(ctx) {
+ ctx.status(201)
+ ctx.json( createNote(ctx.body()) )
+ })
+ .start(8084)
\ No newline at end of file
diff --git a/examples/server/server_spa_simple.own b/examples/server/server_spa_simple.own
new file mode 100644
index 0000000..8f1d3c8
--- /dev/null
+++ b/examples/server/server_spa_simple.own
@@ -0,0 +1,20 @@
+use std, jdbc, server
+
+// curl -X POST http://localhost:8084/notes/ -d "New note 2"
+
+notes = []
+createNote("This is your first note.")
+
+def createNote(content) {
+ note = {"id": notes.length + 1, "content": content};
+ notes += note
+ return note
+}
+
+newServer({"externalDirs": ["notes_public"]})
+ .get("/notes", def(ctx) = ctx.json(notes))
+ .post("/notes", def(ctx) {
+ ctx.status(201)
+ ctx.json( createNote(ctx.body()) )
+ })
+ .start(8084)
\ No newline at end of file