Masonite Framework Tutorial Series Part 2 - Routing
Tags: python, framework, masonite, tutorials
Published: 2018-07-04 12:14:44

---
title: Masonite Framework Tutorial Series Part 2 - Routing
published: true
description: Masonite framework tutorial on routing
tags: python, framework, masonite, tutorials
---

<img src="https://thepracticaldev.s3.amazonaws.com/i/90b7vhkjoxgu022q7vwd.png">

# Introduction

Now that we have our installation done and our [Masonite](http://github.com/masoniteframework/masonite) application is running, let's work on adding a few routes to our application.

Again we won't be building a specific application in this tutorial. We will only be going through each part of a route in detail and talking us through it, explaining caveats, showing different options etc. 

At the end of this series I'll make a video tutorial using these text based tutorials as a transcript. If you don't want to miss that or the next tutorial part then give a follow!

So, a simple route needs 3 basic parts: a request method, a URI and a controller. We will get into controllers in a later tutorial series but let's focus on digging really deep into specifically routes and then we can tie this knowledge in with controllers.

# Creating our Route

All routes are located in `routes/web.py`. All applications have a few different concepts of routes. We might have API routes, HTTP routes, resource routes, internal routes. Because of this, Masonite breaks up all normal front facing HTTP routes and suggests putting it in this file inside a ROUTES constant.

Inside this file we will see some code that looks like:

```python
from masonite.routes import Get, Post

ROUTES = [
    Get().route('/', 'WelcomeController@show').name('welcome')
]
```

In it's simplest form this is what you'll be using to create routes. Let's break it down a little more.

We have a `Get()` class which tells this specific route that it is a .. you guessed it .. and GET route. This class takes 2 parameters, the URI (starting with a `/`) and, in this case, a string that by default points a class called `WelcomeController` in `app.http.controllers.WelcomeController`. Not all of your controllers need to in this directory but that's what it is by default. We will talk about how to change this in a later part.

Lastly we have a `name()` method which takes a simple string. This string can be anything you want, some people may do things like:

```python
..().name('welcome')
..().name('welcome.home')
..().name('welcome:message')
```

The syntax if really up to you and what works best for you and your team. It's simply just a string used to identify that route later if we plan to fetch it or redirect to it.

# HTTP Methods

We are not just limited to GET and POST. We can use any request method:

```python
from masonite.routes import Get, Post, Put, Patch, Delete

ROUTES = [
    Get().route('/', 'WelcomeController@show').name('welcome')
    Post().route('/create', 'WelcomeController@create').name('welcome.create')
    Put().route('/update', 'WelcomeController@update').name('welcome.update')
    Patch().route('/update', 'WelcomeController@update').name('welcome.patch')
    Delete().route('/delete', 'WelcomeController@delete').name('welcome.delete')
]
```

If you are building an API endpoint, feel free to use any of these. You may also look into the [Masonite Entry](http://entry.masoniteproject.com) package as well if you are interesting in building API's with Masonite.

# Middleware

Like any framework, Masonite has 2 concepts of Middleware. The first concept is Route Middleware and the other is HTTP Middleware. Since this is a route tutorial we will just talk about the Route Middleware but will go into much more detail in a middleware tutorial.

All middleware is defined in `config/middleware.py` and can be used in our route above like so:

```python
..().name('welcome').middleware('auth', 'another', 'more')
```

You can specify middleware to be ran in succession by simply passing them as arguments.

# Lists

When Masonite loads these routes into the container, it flattens them. This adds support for nesting lists inside of the `ROUTES` list like so:

```python
ROUTES = [
    Get('/', 'WelcomeController@show').name('welcome'),
    [
        Get.route('/another', 'AnotherController@show').name('another'),
    ]
]
```

This isn't very useful at all but what we can do with this is have a class method that returns a list like so:

```python
# inside somefile.py

class AwesomeRoutes:

    def routes(self):
        return [
            Get().route('/another', 'AnotherController@show').name('another'),
        ]
```

and then import it and use it in this route list:

```python
from somfile import AwesomeRoutes
ROUTES = [
    Get().route('/', 'WelcomeController@show').name('welcome'),
    AwesomeRoutes().routes(),
]
```

This is very useful for breaking up your routes into multiple files or creating a Masonite package that requires routes to be added to an application.

# Route Helpers

I personally don't use the classes because I don't like how it looks. I instead use the route helpers that are a simple shorthand to the class based approach and can be used like so:

```python
from masonite.helpers.routes import get, post

ROUTES = [
    get('/', 'WelcomeController@show').name('welcome')
]
```

Just a bit of shorthand but I think it's much cleaner. If you like the capitalized class based approach and want a little bit of both we can do something like:

```python
from masonite.helpers.routes import get as Get

ROUTES = [
    Get('/', 'WelcomeController@show').name('welcome')
]
```

## Route Groups

We can also specify route groups which is simply a list of routes that can be used that can be .. grouped. This is useful if you have a bunch of similar routes and want to make your routes more DRY.

Take this example:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('/dashboard/user', ...)
    get('/dashboard/user/edit', ...)
    get('/dashboard/user/create', ...)
    get('/dashboard/profile', ...)
]
```

Notice here that all the routes look very similar. In this instance, we should make a route group:

```python
from masonite.helpers.routes import get, group

ROUTES = [
    group('/dashboard', [
        get('/user', ...),
        get('/user/edit'),
        get('/user/create'),
        get('/user/profile'),
    ])
]
```

# Parameters

This routes feature wouldn't be useful if we weren't able to dynamically fetch parts of the URI. In order to do this we just need to put in an `@` symbol next to the variable name we will want to use later. A great example would be:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('dashboard/user/@id/edit', ...),
]
```

Notice here we have an `@id` inside our route list. We will now be able to use the `id` key to fetch whatever that value is. We will talk about fetching this value in the next tutorial when we talk about controllers.

This will match pretty much anything you throw in there to include digits, letters and alphanumerics. In this case we probably just want to match integers so let's specify that:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('dashboard/user/@id:int/edit', ...),
]
```

This `@id:int` will tell Masonite to not match this route if the `id` is anything other than an integer. This will match `/dashboard/user/1/edit` but not `/dashboard/user/joe/edit`

We can do the same for an alphanumeric string:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('dashboard/user/@id:string/edit', ...),
]
```

This will match `/dashboard/user/joe/edit` but not `/dashboard/user/1/edit`.

# Deeper Module Controller

A controller is basically just a class with some methods. If you are coming from Django then Masonite controllers is simply a class wrapped around function based views. Not all controllers are going to be located in `app.http.controllers` so you may move them to several places. What most people do is put them into their own categories where you have a structure like this:

```
app/
  http/
    controllers/
      Dashboard/
        SomeController.py
      Admin/
        SomeController.py
      Leagues/
        SomeController.py
      BaseController.py
```

This is completely fine and may be the way to go. In this instance we can simply just specify a module deeper in the controller structure:

```python
from masonite.helpers.routes import get

ROUTES = [
    get(..., 'Dashboard.SomeController'),
]
```

Notice the `.` notation here. That tells Masonite to check in the `app.http.controller` directory but also inside the `Dashboard` module instead of the base directory there.

# Global Controllers

There are two ways to specify controllers globally. If you want to get out of the `app.http.controller` directory all together and instead want to place your controllers into a structure like this:

```
app/
  http/
    controllers/
      BaseController.py
controllers
  Dashboard/
    SomeController.py
  Admin/
    SomeController.py
  Leagues/
    SomeController.py
```

then we can specify a "global" controller which bascially just looks for the controller as if you were importing the module:

```python
from masonite.helpers.routes import get

ROUTES = [
    get(..., '/controllers.Dashboard.SomeController'),
]
```

Notice the simple `/` prefix.

# Class Based Controllers

If you want to get out of the world of string based controllers completely which I sometimes do, especially when I am developing packages, we can simply import the class and specify it without strings:

```python
from masonite.helpers.routes import get
from app.http.controllers.WelcomeController import WelcomeController

ROUTES = [
    get(..., WelcomeController.show),
]
```

Notice he we didn't instantiate anything. Masonite will find the class, method and module on its own. I personally like this approach a lot better because it is much more explicit. We don't have to worry about the string being able to pick up the controller location implicitly.

# Subdomains

Subdomains are extremely useful for any application but we actually turned them off by default. This is because some deployment services like Heroku deploy to things like `meadow-fever-18273.herokuapp.com`. This sets a subdomain on the application and you wouldn't be able to show any of your routes until you setup a custom domain name.

## Activating Subdomains

In order to activate subdomains, we just need to open any of our Service Provider which has a `wsgi=False` class property and we can throw this in the boot method:

```python
def boot(self, Request):
    Request.activate_subdomains()
```

Once we activate subsdomains, we now have access to using them!

## Using Subdomains

We can now simply set the domain for each route but using the `domain()` method:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('/', 'WelcomeController@show').name('welcome'),
    get('/home', 'SomeController@show').domain('masonite').name('home'),
]
```

now only the `/home` route will be available to `masonite.website.com` and not `website.com`.

The more common use case is to specify a route on all domains and fetch the domain later in the codebase. For that we can use the asterisk wildcard which will catch all subdomains:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('/', 'WelcomeController@show').name('welcome'),
    get('/home', 'SomeController@show').domain('*').name('home'),
]
```

This will catch every subdomain but not anything on `website.com`.

Lastly we can specify a list of concrete subdomains we wan't to connect to:

```python
from masonite.helpers.routes import get

ROUTES = [
    get('/', 'WelcomeController@show').name('welcome'),
    get('/home', 'SomeController@show').domain(['api', 'slack']).name('home'),
]
```

This will be found on both `api.website.com` and `slack.website.com` but not any other subdomain or main domain. In the next part we will explain how to fetch these values inside a controller.

****

That's it for routes! Next we'll talk about the awesome world of controllers and how Masonite really shines from other Python web frameworks.

Be sure to give a follow so you don't miss that and be sure to check out [Masonite here](http://github.com/masoniteframework/masonite)! See you next time!