Hello World
The hello world of realtime applications is a chatroom. Let's make one using Synapse.
-
In the
resources
directory, create a file calledMessage.ts
with the following Resource class definition:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
import { Resource, State, fields, decorators } from '@synapsejs/synapse'; const { Id, Text, Integer } = fields; const { field, endpoint, schema, uses } = decorators; const pageSize = 10; const ledger = []; export default class Message extends Resource { @field(new Id()) id: string; @field(new Text()) text: string; @endpoint('GET ./last') @uses('/') static last() { if (!ledger[ledger.length - 1]) { return State.NOT_FOUND(); } return Message.restore(ledger[ledger.length - 1]); } @endpoint('GET ./:id') @schema(Message.schema.select('id')) static find({ id }) { if (!ledger[id]) { return State.NOT_FOUND(); } return Message.restore(ledger[id]); } @endpoint('GET ./page/:index') @schema({ index: new Integer() }) @uses('/') static list({ index }) { const start = ledger.length - pageSize * index; return Message.collection(ledger.slice(start, start + pageSize)); } @endpoint('POST ./') @schema(Message.schema.select('text')) static async post({ text }) { const message = await Message.create({ id: `${ledger.length}`, text }); ledger.push(message.export()); return message; } }
-
Start your Express server and, using a tool such as Postman, make the following HTTP requests to verify that your Synapse installation is functioning properly:
POST http://localhost:3000/api/message { "text": "hello" }
POST http://localhost:3000/api/message { "text": "world!" }
GET http://localhost:3000/api/message/0
GET http://localhost:3000/api/message/page/1
GET http://localhost:3000/api/message/last
-
Since Synapse creates a layer of abstraction between your application's business logic and the network protocols used to access it, we can now create a real-time client application without making any alterations to our server.
index.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<!DOCTYPE html> <html> <head> <script type='module' src='index.js'></script> </head> <body> <div id='messages'></div> <input id='text' /> <button onclick="post();">post</button> </body> </html>
index.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
// import the websocket client from the browser version of Synapse import Client from 'https://unpkg.com/@synapsejs/synapse@1.0.7/build/lib.browser/client/Client.js'; // this variable will hold our connection to the server let api = null; // helper function which adds messages to the DOM const render = (messages) => { for (const msg of messages) { document.getElementById('messages').innerHTML += ` <div><b>${msg.id}:</b> ${msg.text}</div> `; } }; // connect to the server via WebSockets Client.connect('ws://localhost:3000/api').then(async (client) => { api = client; // store the connection // request the first page of messages and render them api.get('/message/page/1').then((res) => render(res.payload)); // then subscribe to the last message api.subscribe('/message/last', {}, (message) => { // whenever a change occurs, we will receive the new state and render it render([message]); }); }); // uses the server connection to post a new message window.post = () => { api.post('/message', { text: document.getElementById('text').value }); };
-
Open the application in multiple browser windows to verify that the message list updates in real-time!
The following sections will discuss in greater detail the many features of the Synapse library.