Skip to content

Hello World

The hello world of realtime applications is a chatroom. Let's make one using Synapse.

  1. In the resources directory, create a file called Message.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;
      }
    }
    
  2. 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
    

  3. 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 });
    };
    

  4. 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.