In today’s post I will teach you how to build an API in Rails from scratch with several features and implementing some development patterns that allow our API to expand without much code and that it becomes very easy to implement new features.
Requirements
First we need an operating system in this case we gonna use Debian 10, this installation tutorial is considering only the use of the terminal and the minimal system without a graphical interface, which can be used in a virtual machine or directly in the operating system installed in hardware, in addition, we need ruby and Rails already installed on the machine, in this post we will use ruby 3.2.2 and Rails 7.0.7.
Steps
- Defining the API scope
- Class diagram
- Rails commands
- Rails code
- Seeds and Rails console
- Conclusion
Defining the API scope
Our API is going to be very simple, basically we are going to make an API that receives information from users about their loans and we are going to calculate the interest rates of these loans, from that we are going to build a dashboard with some global information according to what was informed by the users.
Class diagram
classDiagram
class Bank {
integer bank_id
string bank_name
integer bank_fed_id
string bank_location
}
class Loans {
date loan_date
bool credit_needed
integer bank_id
integer user_id
decimal amount
bool early_payoff_penalty
integer term
decimal origination_fee
decimal late_fee
integer fico_score_at_date
}
class User {
integer user_id
string email
}
Bank <|-- Loans
User <|-- Loans
So, once we have defined how our classes are going to be we can start building our API in Rails, basically we have a Bank class that can have N Loans and a User class that can have N Loans also in rails we call this has_many relation :through that in this case the Loans class is born from an N to N relationship between Banks and Users with their due unique attributes of this relationship, not just a direct relationship of identity between the classes
Rails commads
Today we are basically going to use two rails commands to create our models and make them persist in the database.
This command creates a model that is an object representation of relational data.
1
rails g model model_name attributes
This command sends the migrations that were created with the previous command
1
rails db:migrate
Rails code
Let’s create our models, let’s create the Bank model first, we will need to run the following command:
1
rails g model Bank bank_name bank_fed_id:integer bank_location
Now we can run the migration:
1
rails migrate
After that we can create the User model with the following command:
1
rails g model User email
And again we can run the migration:
1
rails migrate
And now we can create the N to N relationship class between Banks and Users:
1
rails g model Loan loan_date:date credit_needed:boolean bank:references user:references amount:decimal early_payoff_penalty:boolean term:integer origination_fee:decimal late_fee:decimal fico_score_at_date:integer
Finally, we can run the migration to create the last table:
1
rails migrate
After that, we already have our tables created and ready to receive data, but first we need to inform the relationships and how they communicate in the model’s class files.
In the Bank model, we need to change the file so that it looks like this:
1
2
3
4
class Bank < ApplicationRecord
has_many :loans
has_many :users, through: :loans
end
In the User model, we need to change the file so that it looks like this:
1
2
3
4
class User < ApplicationRecord
has_many :loans
has_many :banks, through: :loans
end
Finally in the Loan model we have to have a code like this:
1
2
3
4
class Loan < ApplicationRecord
belongs_to :bank
belongs_to :user
end
After that we have our ORM (object relational mapping) complete. If you want to know more about this you can see more information here: https://www.freecodecamp.org/news/what-is-an-orm-the-meaning-of-object-relational-mapping-database-tools/
Seeds and Rails console
Now we can create data to test ourselves if our models are working correctly. For that we are going to use rails Seeds.rb
file that can be found in db/seeds.rb
to throw test data to our database.
We are going to create 5 Banks and 20 Users to test our relationships, each User will have between 1 and 5 Loans, Banks can have more than one Loan.
Our seeds file will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
5.times do |i|
Bank.create!(bank_name: 'bank ' + i.to_s, bank_fed_id: rand(0..16), bank_location: 'bank location ' + i.to_s)
end
20.times do |i|
User.create!(email: 'email ' + i.to_s)
end
User.all.map do |user|
rand(1..5).times do
user.loans.create!(loan_date: Date.today-rand(1000),
credit_needed:[true, false].sample,
bank: Bank.all.sample,
amount: rand(100.0..100000.0),
early_payoff_penalty: [true, false].sample,
term: rand(6..360),
origination_fee: rand(0.001..0.01),
late_fee: rand(0.001..0.02),
fico_score_at_date: rand(300..850))
end
end
Now we can run the command to insert this dummy data into our database so we can check if our relationships are correct:
1
rails db:seed
If it does not return any error, the console will just show a new line to insert a new command.
After that we can check in the Rails console if the information is persisted:
1
rails c
And then we can use User.all to check if user data is recorded, just like Bank.all and Loan.all.
1
User.all
You will see a result similar to this:
1
2
3
4
5
6
User Load (0.5ms) SELECT "users".* FROM "users"
=>
[#<User:0x00007f07dd573618 id: 161, email: "email 0", created_at: Sat, 19 Aug 2023 02:40:32.393240000 UTC +00:00, updated_at: Sat, 19 Aug 2023 02:40:32.393240000 UTC +00:00>,
#<User:0x00007f07dd5f1ae0 id: 162, email: "email 1", created_at: Sat, 19 Aug 2023 02:40:32.398077000 UTC +00:00, updated_at: Sat, 19 Aug 2023 02:40:32.398077000 UTC +00:00>,
#<User:0x00007f07dd5f1a40 id: 163, email: "email 2", created_at: Sat, 19 Aug 2023 02:40:32.402377000 UTC +00:00, updated_at: Sat, 19 Aug 2023 02:40:32.402377000 UTC +00:00>,
#<User:0x00007f07dd5f19a0 id: 164, email: "email 3", created_at: Sat, 19 Aug 2023 02:40:32.406591000 UTC +00:00, updated_at: Sat, 19 Aug 2023 02:40:32.406591000 UTC +00:00>]
And using the other commands you will get similar results.
You can also test the relationships using the following commands:
1
User.first.loans
1
User.first.banks
1
Bank.first.loans
1
Bank.first.users
Conclusion
With this first post I made an introduction of what our API will be like at least at the Model level, with this we can advance in the functionalities based on our data, in the next posts we will learn about model validations, model tests and other subjects more related to this.
I hope you like it, if you want and can you can share this text, I will be posting new content daily, favorite this blog to have access to new knowledge. Thanks to everyone who read this post.