Martini App with Ajax, JSON, and User Sessions
Previously, I have created a really simple web app with Go Lang and Martini that communicated with MySQL to retrieve a list of posts, an individual post, and allowed creation of a post. Now, we are going to handle updates and deletion, transform responses to use JSON for client side Ajax requests, and implement the user relation: user login, logout, managing sessions and authentication, as well as, retrieving posts by user. Supporting PUT (update) and delete requests with Ajax and JSON was pretty trivial (thanks to Martini) but evolving the app to handle users properly with good validation was much more work then I originally expected. Still, Go does make the code easy to understand and Martini contributed utilities have been a great help. Lets start.
GoLang and Martini Web Application
Ajax and JSON with Go Lang and Martini
HTML forms can only make POST and GET requests so our application needs to communicate with the backend via Ajax to provide update and delete functionality. On the client side, jQuery is loaded, and I listen for click events on HTML markup to initiate the XMLHttpRequest or XHR requests to the backend. Here’s how I setup the PUT and DELETE functions with Martini routes and JSON response via render:
Since ID comes in as a string but is stored as int64, I first make that conversion. The gist above only shows the user resource but we need to set these up for both the user and post resource as a user might want to modify their post. This right away makes me think about authentication as you want to make sure that only the users that own the posts can modify and remove these posts or make changes to their user account. I have attached a UserId field to the posts MySQL schema to connect the user table to the post table.
Now, I need to confirm that the manipulation request (CREATE, UPDATE, and DELETE) verifies the owner of the resource. This needs to happen on the server side and on the client side (do not show delete or update buttons/functions to users that do not own a resource). Before I dig into all of these, we need to authenticate and validate a current user so lets build the registration, login pages, and functionality.
Authentication and User Sessions
Registration is pretty trivial as it is just a form that creates a user in the system or the database. I am going to skip the ‘mail confirmation” and “forgot your password” features. If you register or successfully login, the app needs to remember the user credentials on subsequent pages and for that we need sessions. Martini has a great session handler but the sessionauth package takes it a step further and provides a simple solution to make routes require login and authenticate these logins with the session. The auth example even shows how to handle redirection with improper credentials or actions.
So, I included sessionauth in my code and added the sessionauth.User to most of my routes for validation. This means that when a request is made to the server, I first check the session to see who is the user making the request and only allow the action to proceed if it satisfies the appropriate permissions. I decided to allow all to read or GET a resource but if you want to change a post, I first check who you are and if the post you want to modify belongs to you. This error checking has added a bunch of code to my main file but I wanted to show all the conditions and handle them accordingly. For example, take a look at all these if/else statements in the new post PUT call (updating a post):
The client side also needs some logic so that we don’t even allow a user to modify a post that is not owned by the user (you could force Ajax requests but this is why we check the user session on the server side as well). There are a few ways to do this: it could be different template files, template logic in one template file, or fancy JavaScript and HTML markup logic. Since the Go 1.2 update included template if statements with equality checking, I decided to use that:
The if statement in the Go Lang template checks if the authenticated user is equal to the user shown in the requested user page, and as a result, it only shows the “Delete My Account” button if the logged in user is viewing their own account. Some people argue that templates should be logic-less and you could handle this in the route and use different template files, but I think the solution depends on how much logic you drop into the template.
The last thing I want to do is some Go Lang URL rewriting or creating pretty urls for SEO. I think there are a few ways to do this and I chose to automatically create and store pretty urls from the title field with some string conversion and regex. Title is a required field for a post so when that object is created, I added some GoLang code that automatically creates a nice URL from the title:
Finally, the main file is much bigger now so a good next step would be some Go Code Organization. Here is the the Martini and Go Lang App with Users, Posts, and Ajax. Check it out to see how it all works.
External:
Gorilla vs Pat vs Routes: A Mux Showdown
Fear and Loathing With Golang and AngularJS
Building an API with Golang, RethinkDB and wercker
How did you learn how to code in Go?
A Go Redirection Service
interface{} – golang’s type god