Eleni Papanicolas
Posted on January 26, 2022
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, as well as a great guide to quickly 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.
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.
# 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.
# 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.
# 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
.
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.
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.
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 :)
Posted on January 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.