Skip to content
By Leonard Garvey

URL design in Web Applications

or; Using CRUD as an abstraction

When thinking about a new web application I like to try to think about the URLs that my application has. The URLs are the bits that expose my application to the outside world, they define what my application can do, so thinking about them early on means that I'm focusing on one of the most important parts of my system.

As I develop complex web systems I've found that creating an organised, consistent URL system has significant benefits to my codebase overall, and makes my systems easier to create and maintain. At the same time I notice that beginning developers often create overly complicated and disorganised URL structures for their applications.

While this post is primarily focused on Rails, the main lessons here apply to any web application.

Consistency of Routing

We want to be able to get an idea of what a URL route does just by looking at it. We'd also like it if new developers could understand what is happening without much learning. For example:

GET /blogs/new - is the page where the form for a new blog is created. In the same app: GET /products/new is the page where the form for a new product is located. These routes should NOT be: GET /newblog or GET /addproduct.

In Rails these consistent routes are called "resourceful" routes. The important lessons here are that the naming structure is easy to understand, and that HTTP methods are often used to distinguish different things. For instance if you are performing an action which will save a record to the database, the POST HTTP Method is the appropriate method to use. If you're updating an existing record then use either PUT or PATCH.

The Rails routing guide has an excellent example of these types of routes.

HTTP Verb Path Controller#Action Used for
GET /photos photos#index display a list of all photos
GET /photos/new photos#new return an HTML form for creating a new photo
POST /photos photos#create create a new photo
GET /photos/:id photos#show display a specific photo
GET /photos/:id/edit photos#edit return an HTML form for editing a photo
PATCH/PUT /photos/:id photos#update update a specific photo
DELETE /photos/:id photos#destroy delete a specific photo

We can easily come up with some anti-patterns, or examples of "bad" routes:

HTTP Verb Path Used for Notes
GET /addphoto return an HTML form for creating a new photo is inconsistent
POST /photos/:id?update=true update a specific photo doesn't nest controllers appropriately
GET /photos/:id?delete=true delete a specific photo uses GET to destroy a resource

Non-Resourceful Routes

Rails also lets a developer add a "non-resourceful" route to a controller. In my opinion these are a serious code-smell and should never be used by beginning programmers. An example of this might be:

GET /users/search   UsersController#search

While this type of route may seem easier than creating a new controller just to handle searching, in the near future it becomes very unwieldy to mix the concerns of searching with the concerns of the user controller. Some parts of the users controller might need to be heavily authenticated, while we might allow searching to be done by guests. As we add this logic to our applications and add extra "non-standard" actions to our controllers our apps become more difficult to document, modify and maintain.

Another example of this might be:

POST /jobs/restart   JobsController#restart

In this example we're restarting some sort of job. This is simply being added to the JobsController which is now in danger of becoming overburdened with functionality to do with the scheduling and control of our jobs. Also it seems likely that a job restart action might need some additional auditing and logging, which would further complicate our JobsController. Instead of this what we're actually doing is CREATING a JobRestart. By thinking about this functionality in terms of CRUD we're easily able to see that there is a new resource here which needs a new controller. This should be rewritten as:

POST /jobs/:id/restarts   JobRestartsController#create

My preference is to never write non-resourceful routes and my recommendation to starting developers is to never use them either.

This rule has some additional benefits that might not be readily apparent. By forcing us to use "resourceful" routes we begin to think about all of our application in terms of create, read, update and delete or CRUD. This puts us in familiar teritory. I'll run through some examples:

1.) You are building a SaaS application and want to allow a user to invite another user into the system. You might be tempted to add an invite route to the UsersController but instead you should create an InvitesController and use the create method. This requirement is to create an invite so it's very appropriate to follow this pattern.

2.) You're building a song playlist management application and your boss wants you to make a "vote to skip" functionality. You could add SongsController#skip, but it's far more consistent to add a new controller which handles the creation of the SkipVote model. You might call this SkipVotesController#create. If you had simply added the #skip method to the SongsController you'd be stuck if your boss later asked you to allow users (or an admin) to view the votes to skip various songs.

In some rare circumstances it will be difficult to think about your problem domain in terms of CRUD, but I believe it pays off in the long run. Naming things can be difficult, but working with legacy code where no care was made to name URLs and routes is a far worse position to be in.

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email