REST API boilerplate built with Gin and GORM that demonstrates user authentication with JWT and CRUD operations for blog posts.
- JSON Web Token (JWT) authentication with cookie storage
- User registration and login with bcrypt password hashing
- Protected routes that hydrate the authenticated user from the token
- Blog post CRUD (create, read, update, soft delete, hard delete) backed by MySQL
- Database migrations via
gorm.DB.AutoMigrate
- Go 1.24
- Gin Web Framework
- GORM ORM
- MySQL (via
gorm.io/driver/mysql)
- godotenv: load environment variables from a
.envfile during development - Gin: high-performance HTTP web framework for Go
- GORM: developer-friendly ORM for Go with rich database features
- Ensure you have Go 1.24 installed:
go version - Clone the repository and enter the project folder:
git clone https://github.com/Algoritma-dan-Pemrograman-ITS/Framework-Programming-GIN-GORM.git
cd Framework-Programming-GIN-GORM- Pull core dependencies explicitly (optional when using
go mod tidy, but useful for first-time setup):
go get github.com/joho/godotenv
go get github.com/gin-gonic/gin
go get gorm.io/gorm
go get gorm.io/driver/mysql- Download remaining module requirements:
go mod tidy- Follow the sections below to configure environment variables, run migrations, and start the server.
- Go 1.24 or newer
- MySQL instance (local or remote)
Create a .env file in the project root with at least the following values:
DB_URL="user:password@tcp(localhost:3306)/dbname?parseTime=true"
JWT_SECRET="your-jwt-secret"
ENV="development"
JWT_SECRET is used to sign and verify JWT tokens. ENV is optional and only toggles the secure flag on cookies when set to production.
Ensure the database specified in DB_URL exists. Then run:
go run migrate/Migrate.goThis will auto-migrate the models.Blog and models.User schemas.
go run main.goBy default Gin listens on http://localhost:8080.
- Sign up a user via
POST /signupwithname,email, andpassword. - Sign in via
POST /signin. On success the JWT is set in an HttpOnly cookie namedtokenand also returned in the JSON body. The token expiry is currently configured for 5 seconds for demonstration purposes; adjust incontrollers/AuthController.goas needed. - Blog CRUD endpoints are public and do not require authentication. Only the example protected endpoints require authentication:
GET /protected/profileGET /profile2
| Method | Route | Auth | Description |
|---|---|---|---|
| POST | /signup |
No | Create a new user |
| POST | /signin |
No | Sign in, receive JWT cookie and token |
| POST | /blog |
No | Create a blog post |
| GET | /blogs |
No | List all blog posts |
| GET | /blogs/:id |
No | Get a blog post by ID |
| PUT | /blogs/:id |
No | Update a blog post |
| DELETE | /blogs/:id |
No | Soft delete a blog post |
| DELETE | /blogs/:id/hard |
No | Permanently delete a blog post |
| GET | /protected/profile |
Yes | Retrieve authenticated user profile |
| GET | /profile2 |
Yes | Profile example using AuthMiddleware2 |
Create blog post:
POST /blog
Content-Type: application/json
{
"title": "Hello Gin",
"content": "Building REST APIs with Gin and GORM."
}Responses follow a simple JSON structure on error:
{
"error": "message"
}- Database connection is configured in
initializers/ConnectToDB.gousing theDB_URLDSN. - Middleware in
middleware/AuthMiddleware.govalidates JWTs, loads themodels.User, and stores it in the Gin context under theuserkey. migrate/Migrate.gocan be extended with additional models as the domain grows.- Token lifetime defaults to 5 seconds in
controllers/AuthController.gofor easy expiration testing; adjusttime.Now().Add(5 * time.Second)for production use.
failed to connect to database: verifyDB_URLpoints to an accessible MySQL instance and that the database exists.Authorization cookie required: ensure you include thetokencookie returned from/signinwhen calling protected routes.
No license information has been provided. Add one if you plan to distribute or open-source this project.
Below are simple steps to test the API using Postman. You can either let Postman manage cookies (recommended) or use the JWT returned by /signin as a Bearer token.
-
Create an environment variable in Postman named
baseUrlwith valuehttp://localhost:8080(or your server URL). -
Sign up a new user
- Method: POST
- URL:
{{baseUrl}}/signup - Body (JSON):
{
"name": "Your Name",
"email": "you@example.com",
"password": "secret"
}- Sign in
- Method: POST
- URL:
{{baseUrl}}/signin - Body (JSON):
{
"email": "you@example.com",
"password": "secret"
}- Response: the server sets an HttpOnly cookie named
token(Postman will store this cookie automatically if you use the same domain) and returns the token in the JSON body astoken.
- Using cookies (recommended)
- After a successful
/signin, Postman stores thetokencookie forlocalhost. When you send subsequent requests to the same{{baseUrl}}, Postman will include the cookie automatically. If cookies are not being sent, open Postman's Cookies (Cookies Manager) and confirmtokenexists for thelocalhostdomain.
- Using the token as Authorization header (alternative)
- Copy the
tokenvalue from the/signinJSON response. - For protected requests (e.g.
GET {{baseUrl}}/protected/profile), add a header:
Authorization: Bearer <token>
- Note: The project prefers cookie-based auth. Authorization header support is only available if you modify the middleware to accept
Authorizationheader.
- Example: create a blog post (no auth required)
- Method: POST
- URL:
{{baseUrl}}/blog - Body (JSON):
{
"title": "Postman Test",
"content": "Testing the API with Postman"
}- Troubleshooting with Postman
- If you receive
Authorization cookie required, verify that Postman stored and is sending thetokencookie forlocalhost. - If you used the Bearer header and receive
Invalid token, ensure the token is exactly as returned by/signinand not wrapped or truncated.
If you'd like, I can generate a Postman collection (JSON) for these requests and add it to the repo so you can import it directly.