Echo Server Example¶
An echo server is a simple server that echos any message it receives back to the client that sent it.
First install a copy of Chalice in a fresh environment, create a new project and cd into the directory:
$ pip install -U chalice
$ chalice new-project echo-server
$ cd echo-server
Our Chalice application will need boto3 as a dependency for both API Gateway
to send websocket messages. Let’s add a boto3 to the requirements.txt
file:
$ echo "boto3>=1.9.91" > requirements.txt
Now that the requirement has been added. Let’s install it locally since our next script will need it as well:
$ pip install -r requirements.txt
Next replace the contents of the app.py file with the code below.
 1from boto3.session import Session
 2
 3from chalice import Chalice
 4from chalice import WebsocketDisconnectedError
 5
 6app = Chalice(app_name="echo-server")
 7app.websocket_api.session = Session()
 8app.experimental_feature_flags.update([
 9    'WEBSOCKETS'
10])
11
12
13@app.on_ws_message()
14def message(event):
15    try:
16        app.websocket_api.send(
17            connection_id=event.connection_id,
18            message=event.body,
19        )
20    except WebsocketDisconnectedError as e:
21        pass  # Disconnected so we can't send the message back.
Stepping through this app line by line, the first thing to note is that we
need to import and instantiate a boto3 session. This session is manually
assigned to app.websocket_api.session.
This is needed because in order to send websocket responses to API Gateway we
need to construct a boto3 client. Chalice does not take a direct dependency
on boto3 or botocore, so we need to provide the Session ourselves.
from boto3.session import Session
app.websocket_api.session = Session()
Next we enable the experimental feature WEBSOCKETS. Websockets are an
experimental feature and are subject to API changes. This includes all aspects
of the Websocket API exposted in Chalice. Including any public members of
app.websocket_api, and the three decorators on_ws_connect,
on_ws_message, and on_ws_disconnect.
app.experimental_feature_flags.update([
    'WEBSOCKETS'
])
To register a websocket handler, and cause Chalice to deploy an
API Gateway Websocket API we use the app.on_ws_message() decorator.
The event parameter here is a wrapper object with some convenience
parameters attached. The most useful are event.connection_id and
event.body. The connection_id is an API Gateway specific identifier
that allows you to refer to the connection that sent the message. The body
is the content of the message.
@app.on_ws_message()
def message(event):
Since this is an echo server, the message handler simply reads the content it
received on the socket, and rewrites it back to the same socket. To send a
message to a socket we call app.websocket_api.send(connection_id, message).
In this case, we just use the same connection_id we got the message from,
and use the body we got from the event as the message to send.
app.websocket_api.send(
    connection_id=event.connection_id,
    message=event.body,
 )
Finally, we catch the exception WebsocketDisconnectedError which is raised
by app.websocket_api.send if the provided connection_id is not
connected anymore. In our case this doesn’t really matter since we don’t have
anything tracking our connections. The error has a connection_id property
that contains the offending connection id.
except WebsocketDisconnectedError as e:
    pass  # Disconnected so we can't send the message back.
Now that we understand the code, lets deploy it with chalice deploy:
$ chalice deploy
  Creating deployment package.
  Creating IAM role: echo-server-dev
  Creating lambda function: echo-server-dev-websocket_message
  Creating websocket api: echo-server-dev-websocket-api
  Resources deployed:
    - Lambda ARN: arn:aws:lambda:region:0123456789:function:echo-server-dev-websocket_message
    - Websocket API URL: wss://{websocket_api_id}.execute-api.region.amazonaws.com/api/
To test out the echo server we will use the  websocket-client package. You
install it from PyPI:
$ pip install websocket-client
After deploying the Chalice app the output will contain a URL for connecting
to the websocket API labeled: - Websocket API URL:. The
websocket-client package installs a command line tool called wsdump.py
which can be used to test websocket echo server:
$ wsdump wss://{websocket_api_id}.execute-api.region.amazonaws.com/api/
Press Ctrl+C to quit
> foo
< foo
> bar
< bar
> foo bar baz
< foo bar baz
>
Every message sent to the server (lines that start with >) result in a
message sent to us (lines that start with <) with the same content.
If something goes wrong, you can check the chalice error logs using the following command:
$ chalice logs -n websocket_message
Note
If you encounter an Internal Server Error here it is likely that you forgot
to include boto3>=1.9.91 in the requirements.txt file.
To tear down the example. Just run:
$ chalice delete
  Deleting Websocket API: {websocket_api_id}
  Deleting function: arn:aws:lambda:us-west-2:0123456789:function:echo-server-dev-websocket_message
  Deleting IAM role: echo-server-dev
Next Steps¶
In this tutorial, we created an echo server with websockets. If you’d like to try something more ambitious, you can follow our tutorial for creating a sample Chat application with websocket.
