the full stack && how it all comes together
Tags: ruby, sinatra, webdev, tutorial
Published: 2022-01-26 22:12:28


**So, back end + front end = full stack ...right?**

It's not as simple as that. A quick google search got this as the definition of full stack:

> In technology development, full stack refers to an entire computer system or application from the front end to the back end and the code that connects the two. The back end of a computer system encompasses “behind-the-scenes” technologies such as the database and operating system.

Ok, so let's break this down together.

There is a great analogy of a restaurant that helps in understanding the concept of front and back ends in development. As a former industry member, this one is fun for me to talk about! In a restaurant, the kitchen is considered the back of house and the dining area is the front of house, and so those who work in the kitchen work in back of house positions, and those who work in the dining area work in front of house positions. The whole restaurant in this situation would be our full stack application. In the restaurant, a server is going to take the order of the guest and send it to the kitchen, then receive the food when it is ready, and bring it back to the guest. In the same way, our front end, or our client, is the guest. Our back end is the kitchen. Our restaurant server is the middleware, or the code that connects the two ends. So from this we can see why back end + front end = full stack isn't so simple. We have lots of other moving parts as we get further into what each end fully encompasses.

The code on the front end, or the client side, handles what users interact with. Front end languages include HTML, CSS, and JavaScript and there are even more frameworks to go along with them.

The back end is everything that is not visible to the client. The server and the database are two separate pieces of the back end. Some popular back end languages are Python, Ruby and PHP, as well as corresponding frameworks. Popular databases include MySQL, PostgreSQL, and MongoDB. 

It can be a bit daunting to just get started with so many options and so many different pieces to fit together. Today we are going to go over a quick and easy way to get a full stack application up and running using JavaScript and React.js for the front end, and SQLite for our database. For the back end we are going to use Ruby, and the Sinatra library. 

# front end

Let's get started! The front end seems like a good place to start, it has a little bit less going on. So first, in your terminal you will want to run `$ npx create-react-app <my-app-name-here>`. _Note: Make sure you use npx and not npm to make sure that you are getting the latest version._ This command will install packages and create a new folder with a basic file structure to help you get started. `$ cd <my-app-name-here>` and run `$ npm start`. 

You should see success messages in the terminal, and if you open `http://localhost:3000` your app should be up and running with the initial files provided by React.

React has robust [documentation here](https://reactjs.org/), as well as a great guide to [quickly getting started](https://create-react-app.dev/docs/getting-started).

After the creation of the project the file structure should look like this:

```
my-app-name-here/
  README.md
  node_modules/
  package.json
  public/
    index.html
    favicon.ico
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg
```

With the exception of `public/index.html` and `src/index.js`, the rest is ours to change, edit, build, add to! Make sure to run `$ npm install` to install any dependencies in the package.json file, and again anytime you add new ones. Once you have built out the front end some more, added components, used some hooks...it's time to get the back end up and running. 

# back end

Let's take a look at the file structure first.

![code file structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcdula95mmn3wlszffy0.png)

> `app/controllers` is where we store the code for writing the web server
`app/models` is where we store the models, which are responsible for accessing and updating data in the database
`config` folder will hold our environment setup, is where we require files and gems, and establish a connection to the database
`config/database.yml` is where we will establish a connection to the database
`db/migrate` is where our database migrations are stored, of which are responsible for creating and altering the structure of the database
`db/schema.rb` is auto-generated by the current state of the database and gives an overview of the structure of the database
`db/seed.rb` lets us easily add sample data to the database while it is being developed and tested
`config.ru` is the file that runs the code for writing the web server that is stored in the controllers 
`Gemfile` is where we list all the gems our application depends on
`Rakefile` is where we can store code for common tasks so we can easily run them from the command line

To get started, in a `Gemfile`, we are using the following gems:
> sinatra, thin, rack-contrib, rack-cors, activerecord, sinatra-activerecord, rake, sqlite3, and require_all

Run `$ bundle install` to install all the dependencies. Anytime we add a gem we will need to rerun that command.

In the `config` folder we will need an `environment.rb` which will require all of our files and gems and ensure that everything is connected properly.

```ruby
# config/environment.rb

require 'bundler/setup'
Bundler.require(:default, ENV['RACK_ENV'])

# Requires in all files in 'app' directory
require_all 'app'
```

## database

The `database.yml` file is where we will give Active Record, one of our gems, all the details it needs to establish a connection to the database. We are using SQLite for this demo but Active Record also has support for other databases.

```ruby
# config/database.yml

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

test:
  <<: *default
  database: db/test.sqlite3

production:
  <<: *default
  database: db/production.sqlite3
```

Once we have established a connection to the database, we can begin to create migrations that will create and alter the structure of our database. Rake will help run our migrations when we run `$ bundle exec rake db:create_migration NAME="<table-name>`. A new file will appear in the `db/migrate` folder. The names of the files should not be modified because they are created with a timestamp so that Active Record knows the proper order to run the migrations in. Once we have created our migration file we will need to add the necessary information to create the actual table and then we can run `$ bundle exec rake db:migrate` to migrate those changes to the database. 

`db/seeds.rb` is where we will create dummy data to populate the database during development. It will be helpful for us to have this information to test out our models next.

`app/models` will hold one file for each table in the database. In here we will define the class that will represent the model, and it will inherit from `ActiveRecord::Base` to gain all of the methods the gem gives us. We can also add custom methods and associations to other tables.

```ruby
# app/models/Item.rb

class Item < ActiveRecord::Base
  belongs_to :location
end
```

## server

The `config.ru` will require the environment file, and will run our application controllers and write our server, which you can see above next to the file structure overview. 

Using Sinatra for this is quick and easy, as we did above, adding the `gem "sinatra", "~> 2.1"` to our Gemfile. Then we can start defining our routes in `app/controllers`. It is convention to separate the `application_controller` routes into a single controller file for each model. So if there was a model named `Item` in a table `items`, the corresponding controller file would be `items_controller.rb`. 


![app controller file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo80gb3hi3ct8adg4dc8.png)

In this file, when defining the class for the controller, it is convention to use the capital case version of the file name; it will inherit from `Sinatra::Base` so that we can use all of the methods included in the gem. As we can see, there are a few examples of CRUD actions using our new routes.

The `Rakefile` is where we can define processes that are repetitive during development, but we do not want to have to do manually each time. Currently in this file there is a server command and a console command.

![rakefile](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wvacyc4quz00w3hwhxv.png)

Now we get to connect everything with the front end. Once we have our back end server running, on the front end, in our React components we can define a quick get request to an endpoint on our back end which will get the list of all items that we defined in our controller file.

```javascript
fetch(`http://localhost:9292/items`)
.then(res => res.json())
.then(console.log)
```

We have success! A list of items is returned back to our front end. Now we can build out more endpoints on the back end, so that our front end can request more data, can request more organized, sorted, up to date data. So many possibilities!

As you can see, the full stack is a lot more complex than just 1 + 1 = 2. This tutorial was made to provide a quick, straightforward way to get the bare bones of a full stack application up and running. **Happy coding :)**