Avoiding The Needless Multiplication Of Forms
Implementing interactive featuresDr Andrew Moss
Part 1: How comments should work
After implementing OAuth2 last week I have authenticated access to pages on this server. Everything is sitting behind an nginx front-end server to handle TSL, so I can assume that the contents of pages (and the requests that fetch them) are confidential. This makes adding interactive features substantially easier. A rough conceptual overview of what I wanted to achieve looks like this:
Requests and responses are handled by the server fetching content from static and dynamic storage, splicing it together and delivering pages to the user. The easiest way to implement this is by writing handlers for the GET and the POST and creating a system that looks like this:
This is functional, but clunky. It behaves like most forums or comments have since those hooks were CGI scripts. It lacks interactivity - the only point of interaction is when the user presses submit. At this point they are commited to what they've already typed. They won't get to see what it looks like until after the comment has been commited to storage and the page has been reloaded.
This is problematic for two reasons:
- People typically see errors when what they have written changes form. This is because we do not really read what we've written again (without deliberate effort) - we simply scan it and remember what we intended to write.
- Supplying a richer text format (e.g. Markdown) means the user is reading/writing raw source, not the styled output, so it is difficult to parse and then project onto what it will look like after it is styled.
Both of these problems can be solved by providing a live preview of the comment: take the raw source as it is typed and regenerate the styled output. This is the modern type of interface that we see on a site such as stackoverflow. In order to convert the Markdown source into styled text we need to implement a parser and rendered. There are different options for how to structure this:
- Implement both in Go and run them on the server, using a websocket to transport source and result.
The system looks something like this:
When a user logs in we create a session to store their credentials. Each GET from the user passes back a login cookie that identifies the session (it decodes to the key) so that we can associate requests with the user that made them. This is the only cookie that we need to store in the user's browser, and it is one that we do not need consent to store
When the user starts typing (we only show the comment editor form to logged in users) a websocket is opened to the server and the login cookie is sent to identify the connection. We use a simple protocol over this connection, which is implemented by encoding the messages as JSON and using a label field to identify the kind of message:
| preview || To server || Markdown source for rendering |
| post || To server || Markdown for finished post, add to storage |
| Preview || To client || HTML of comment for display |
| Update || To client || HTML of all comments on page |
| Posted || To client || Confirmation that comment is stored |
Next time I'll show the pieces of code and walk through how they work...
Sign in at the top of the page to leave a comment