When Zulip is deployed in production, all requests go through nginx.
For the most part we don’t need to know how this works, except for when
it isn’t working. Nginx does the first level of routing–deciding which
application will serve the request (or deciding to serve the request
itself for static content).

In development, tools/run-dev.py fills the role of nginx. Static files
are in your git checkout under static, and are served unminified.

All our connected clients hold open long-polling connections so that
they can receive events (messages, presence notifications, and so on) in
real-time. Events are served by Zulip’s tornado application.

Nearly every other kind of request is served by the zerver Django
application.

With the exception of incoming webhooks (which we do not usually control the
format of), legacy endpoints, and logged-out endpoints, Zulip uses REST
for its API. This means that we use:

POST for creating something new where we don’t have a unique
ID. Also used as a catch-all if no other verb is appropriate.

PUT for creating something for which we have a unique ID.

DELETE for deleting something

PATCH for updating or editing attributes of something.

GET to get something (read-only)

HEAD to check the existence of something to GET, without getting it;
useful to check a link without downloading a potentially large link

OPTIONS (handled automatically, see more below)

Of these, PUT, DELETE, HEAD, OPTIONS, and GET are idempotent, which
means that we can send the request multiple times and get the same
state on the server. You might get a different response after the first
request, as we like to give our clients an error so they know that no
new change was made by the extra requests.

POST is not idempotent–if I send a message multiple times, Zulip will
show my message multiple times. PATCH is special–it can be
idempotent, and we like to write API endpoints in an idempotent fashion,
as much as possible.

This cookbook and
tutorial can be helpful if you are
new to REST web applications.

If you’re used to using PUT to update or modify resources, you might
find our convention a little strange.

We use PUT to create resources with unique identifiers, POST to create
resources without unique identifiers (like sending a message with the
same content multiple times), and PATCH to modify resources.

For requests that correspond to a REST url pattern, Zulip configures
its url patterns (see
zerver/lib/rest.py)
so that the action called is rest_dispatch. This method will
authenticate the user, either through a session token from a cookie,
or from an email:api-key string given via HTTP Basic Auth for API
clients.

It will then look up what HTTP verb was used (GET, POST, etc) to make
the request, and then figure out which view to show from that.

is supplied as an argument to rest_dispatch, along with the
HTTPRequest.
The request has the HTTP verb PUT, which rest_dispatch can use to
find the correct view to show:
zerver.views.users.create_user_backend.

The view will authorize the user, extract request variables, and validate them¶