This review discusses how to write a web application using the Echo HTTP Framework and GORM ORM. The application is designed to store information about students and their courses in a SQLite database. The relationship between the courses and students is many-to-many, meaning that students can take multiple courses, and each course can have multiple students.
To ensure code simplicity and maintainability, best practices were used. The code structure is compatible with the popular project-layout.
The application uses two models, Student
and Course
, for in-application communication.
The models use request/responses to serialize data over HTTP and store structures to serialize data from/to the database.
To generate a student ID, a random number is assigned to each student.
There is no authentication over the APIs, and anyone can use CRUD over students and courses.
GraphQL can improve the structure of your APIs, in case of having lots of data using it can reduce the duplicate codes. Here, I am going to implement it using 99designs/gqlgen.
However, using SQLite has its limitations. GORM cannot easily switch to PostgreSQL, and implementing this change would require a complete structure overhaul. Changing the connection is not enough, and running the migration on store creation is not recommended.
You can open GraphiQL in your browser and then sending your queries and mutations.
Following mutation creates a student:
mutation {
createStudent(name: "Elahe Dastan") {
name
}
}
Then you retrieve them by name:
query {
studentsByName(name: "Elahe Dastan") {
name
id
}
}
{
"data": {
"studentsByName": [
{
"name": "Elahe Dastan",
"id": "10368677"
},
{
"name": "Elahe Dastan",
"id": "34092594"
}
]
}
}
Build and run the students' server:
go build
./students
Student creation request:
curl 127.0.0.1:1373/v1/students -X POST -H 'Content-Type: application/json' -d '{ "name": "Parham Alvani" }'
{ "name": "Parham Alvani", "id": "89846857", "courses": null }
Student list request:
curl 127.0.0.1:1373/v1/students
[{ "name": "Parham Alvani", "id": "89846857", "courses": [] }]
Course creation request:
curl 127.0.0.1:1373/v1/courses -X POST -H 'Content-Type: application/json' -d '{ "name": "Internet Engineering" }'
{ "Name": "Internet Engineering", "ID": "00000007" }
Register student into a course:
curl 127.0.0.1:1373/v1/students/89846857/register/00000007
null
And then we have the course into the student course list:
curl 127.0.0.1:1373/v1/students/89846857
{
"name": "Parham Alvani",
"id": "89846857",
"courses": [{ "Name": "Internet Engineering", "ID": "00000007" }]
}
Then we can even add new course and register our student into that course too:
curl 127.0.0.1:1373/v1/courses -X POST -H 'Content-Type: application/json' -d '{ "name": "C Programming" }'
{ "Name": "C Programming", "ID": "00000000" }
curl 127.0.0.1:1373/v1/students/89846857/register/00000000
null
curl 127.0.0.1:1373/v1/students/89846857
{
"name": "Parham Alvani",
"id": "89846857",
"courses": [
{ "Name": "C Programming", "ID": "00000000" },
{ "Name": "Internet Engineering", "ID": "00000007" }
]
}
When you have a relation in your database, you can use gorm.Preload
to fetch the related information within your
query, under the hood GORM run N+1
queries as follows:
2024/09/22 04:09:21 /Users/parham/Documents/Git/parham/1995parham-teaching/students-fall-2022/internal/store/student/sql.go:102
[0.081ms] [rows:0] SELECT * FROM `students_courses` WHERE `students_courses`.`sql_item_id` = "27849651"
2024/09/22 04:09:21 /Users/parham/Documents/Git/parham/1995parham-teaching/students-fall-2022/internal/store/student/sql.go:102
[0.691ms] [rows:1] SELECT * FROM `students` WHERE `students`.`id` = "27849651" LIMIT 1