Teapot: Web Programming Made Easy

On the heels of my recently published Smalltalk tutorial, I wanted to write yet another web tutorial, this time highlighting a wonderful micro web framework in Pharo. (If you’ve not followed the original tutorial, I suggest you at least read Chapters 2, 3, and 4. Note that it’s not necessary to use the Raspberry Pi for this tutorial; any PC will do. Install Pharo from here.)

Teapot is a nice, simple, easy-to-use framework for creating web services and web applications. It’s much like Python’s Flask and Ruby’s Sinatra and Java/Kotlin’s Spark.

(Teapot is based on the Zinc HTTP Components framework for which Sven Van Caekenberghe has written an excellent tutorial.)

Our first Teapot application will be a fairly extensive login management front end. For this, we need four things:

  1. a password encryption mechanism (use Pierce Ng’s PasswordCrypt)
  2. a database store for login credentials (use MongoDB and VoyageMongo)
  3. a send email mechanism (use Zodiac’s #ZdcSecureSMTPClient)
  4. a method of generating UUID (use #UUIDGenerator)

To install Teapot, perform this in Playground:

We will use PBKDF2 for password encryption. We will use FFI to call into a C library for this purpose because the C code is much faster. If your website needs to handle dozens of logins per minute, performance will be a real issue.

We will need the OpenSSL C libraries:

The C library for PasswordCrypt has to be compiled. Use the supplied Makefile. (Depending on your development system, you may or may not be able to use the ‘-m32’ flag. If not, just remove the flag.) With the C files in the same folder, just execute:

Place the library file into the Pharo folder (or wherever the Pharo VM is).

To load PasswordCrypt into Pharo:

We will use the popular MongoDB for our database store. To setup MongoDB in Debian Linux,

Voyage is an object persistence abstraction layer which you can use with Mongo. Install VoyageMongo from the Catalog Browser (click on the green check mark to install the stable version). Here is some introductory material about VoyageMongo.

To notify Voyage about Mongo, perform this in Playground:

Our database is called ‘NCTDB’ and the database model is represented by the #NCTUser class. We create the model thus:

As well, we want to create all the “accessors” for the instance variables.

We want the following pieces of information stored in the database “collection” (consisting of “documents,” to use Mongo parlance):

  • name — the full name of the user (optional)
  • user — this is the email address of the user, guaranteed to be unique
  • pwdHash and pwdSalt — the encrypted password along with its associated salt
  • uuid — a UUID is a 128-bit number used to (almost) uniquely identify something or someone (in our case, the user)
  • creationDate — the date when the user registered; potentially useful for auditing purposes or account expiry
  • accessDate — the date when the user last logged in; potentially useful for determining how “stale” the account is

Creating a document for a new user is as simple as:

To use #ZdcSecureSMTPClient, you must turn on ‘Allow less secure apps’ for the Gmail account that you’re using to send emails. This is used for email verification of user accounts.

Tea Horse Road

Teapot is based on the idea of routes. A route consists of three parts: 1) HTTP method; 2) URL pattern; 3) Action — it can be a block or a message send or an object. A list of routes basically comprises your web application.

For example, if you visit the login page (for a fictitious URL) in your web browser…

…you will see a web form for logging in with your username and password. This activates the route:

The method #loginPage:user:pwd: presents HTML code to render the web page. When you submit the form information to the web server, this activates the route…

…where #verifyLogin: processes the form information and, upon successful verification, you are taken to the main web page:

The method #mainPage: presents HTML code to render the Welcome page.

A similar process applies to the registration page (‘/register’) and “Forgot your password?” page (‘/forgot’) and user profile page (‘/profile’).

Some routes don’t present a web page, for example, ‘/logout’ which simply logs you out and redirects you to the login page.

The argument ‘req’ is the HTTP request associated with the HTTP method. It contains a ‘session’ which can be used to store “global” information. In our case, we will store ‘user’ (or email address) in order to determine when a user has logged in. We will also store ‘uuid’ because it’s fun!

The route #before: is a filter that is evaluated before the GET: request immediately following. The filter is used to ensure that a user is logged in before they can access the webpage.

What the user sees

The various webpages represent the public-facing view of our application. It consists of a “stylesheet” (which contains CSS instructions) and a whole bunch of HTML code. The following is the Login page:

Here is the Registration page:

The pages for Profile and “Forgot your password?” are similar. Regarding #bitAnd:, it’s a bitwise operator that treats numbers as sequences of binary digits. For each corresponding bit pair from the operands, an ‘and’ (or ‘&’) operator produces the following results:

  • 0 & 0 -> 0
  • 0 & 1 -> 0
  • 1 & 0 -> 0
  • 1 & 1 -> 1

There are similar operators for ‘or’ (or ‘|’), ‘xor’ (or ‘^’), and ‘not’ (or ‘~’).

Note, however, that Smalltalk numbers the bits from 1 to 16, not 0 to 15! (This is analogous to arrays where Smalltalk starts with element 1, not element 0.) By the way, in Smalltalk, integers are not limited to 32 nor 64 bits, so these bitwise operators can be used with very large numbers!

The variable ‘code’ is a convenient way to encode multiple error messages.

Here is the stylesheet:

HTML and CSS are beyond the scope of this tutorial, but there are plenty of online learning resources for them.

Handling POSTs and special requests

The most important function of a web application is to handle or process HTTP requests beyond merely presenting webpages. Our application has several types of requests that need to be handled:

  • Login — the user has submitted username and password
  • Logout — the user wants to terminate their login session
  • Registration — a potential user has submitted username and password
  • Account verification — a potential user has clicked on a verification link sent to them via email
  • User profile update — the user wants to change the password
  • Recovering from a forgotten password — the user needs a temporary password sent to them via email

Here, for example, is the handler for user login:

The basic pseudocode is:

The basic pseudocode for Registration is similar:

Here is the Registration handler:


We use regular expressions for validating passwords and email addresses. For example,

Here, we want to ensure that the password has at least 8 characters, has at least one uppercase character and at least one lowercase character and at least one numeric character.

We also have a method for generating a “salt”:

This allocates a new String object of size 16, and for each character in the string, we insert a character chosen at random from a string of digits and letters.

See NCTDB in action

After you’ve written the web application, you can run it to see what it looks like. From Playground, do this instruction:

Then from your local web browser, enter this URL:

You can make your web app available for your friends and family to play with by port-forwarding ‘localhost:1701’ in your LAN router (if your computer is behind a router). Just log into your router, find the port forwarding page, and add an HTTP entry (which includes your internal IP address, say, for example,, and a private port number of 1701).

Then, when your friends visit your router’s IP address ‘http://aaa.bbb.ccc.ddd/login’, they’ll see the NCTDB login page!

In a production setting, you’ll want a dedicated server machine for your web application and use something like Apache or Nginx with Linux, or IIS with Windows. This is beyond the scope of this tutorial.

As you can see, Teapot is a nice, simple way to write a web application. There really isn’t much to our tutorial app from the Pharo end (except you still have to learn HTML, CSS, a smidgen of JavaScript, and how to use MongoDB!).

Our Teapot application is a fairly common login management front end that can be used for just about any web application. Feel free to adapt it, modify it, expand on it for your own purposes.

You may want to take this opportunity to write an ‘admin’ module for it, a simple CRUD facility for browsing, adding, modifying, and removing users from the database. This function can be done securely over the Internet (make sure the administrator uses a very strong password).

Speaking of security, your Teapot application can be served over HTTPS by obtaining a SSL certificate and doing something like this (this is a Raspberry Pi Linux example):

This code creates a secure server based on HTTPS and SSL. It then configures Teapot to use the secure server instead of the regular HTTP server. The optional #logToTranscript message lets you trace all server activity in the Transcript for diagnostic purposes. (Be sure that you change the verification link in the registration handler to use ‘https:’ instead of ‘http:’.)

I hope you found this tutorial useful.

Source code

This zip file contains the Pharo code for ‘FileIn’ with the System Browser. Unzip first. Then drag-and-drop the file into the Pharo window. FileIn the entire file.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store