A simple REST API built with Node.js, Express, and MySQL that supports user registration/login, admin course creation, student enrollment, and paginated course listing.
- Features
- Prerequisites
- Environment variables
- Setup & run
- Database schema
- Available scripts
- API Endpoints & examples
- Authentication
- Pagination
- Error handling
- Notes & recommendations
- User registration and login (passwords hashed with
bcrypt
, JWT auth) - Role-based access:
admin
andstudent
- Admins can create courses
- Students can enroll in courses (unique constraint prevents duplicates)
- Paginated course listing (
?page=&limit=
) - Secure, parameterized SQL queries using
mysql2/promise
pool
- Node.js v16+ (recommended v18+)
- MySQL server
npm
oryarn
Copy .env
and set values:
PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=yourpassword
DB_NAME=course_platform
JWT_SECRET=supersecretkey
JWT_EXPIRES_IN=1d
- Clone the repo and
cd
into it:
git clone <your-repo-url>
cd course-api
- Install dependencies:
npm install
- Create the database and tables:
- Open MySQL and run
schema.sql
, or:
mysql -u root -p < schema.sql
- Copy
.env
to your.env
and edit values:
cp .env .env
- Start the server (development):
npm run dev
or production:
npm start
- Health check:
GET http://localhost:3000/health
Primary tables in schema.sql
:
-
users
—id, name, email (unique), password_hash, role('student'|'admin'), created_at
-
courses
—id, title, description, price, created_by (fk users.id), created_at
-
enrollments
—id, user_id, course_id, enrolled_at, status, UNIQUE(user_id, course_id)
Indexes:
-
idx_courses_created_at
on courses(created_at) -
idx_enrollments_course_id
,idx_enrollments_user_id
npm run dev
— start withnodemon
(development)npm start
— run production server
- Register:
POST /api/auth/register
Body:
{
"name": "Alice",
"email": "alice@example.com",
"password": "s3cret",
"role": "student"
}
Response:
{
"user": {
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"role": "student"
},
"token": "<jwt>"
}
- Login:
POST /api/auth/login
Body:
{ "email": "alice@example.com", "password": "s3cret" }
Response:
{
"user": {
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"role": "student"
},
"token": "<jwt>"
}
- Create course (admin only):
POST /api/courses
Headers: Authorization: Bearer <token>
(token from an admin user)
Body:
{ "title": "Node.js Basics", "description": "Intro to Node", "price": 9.99 }
- List courses (with pagination):
GET /api/courses?page=1&limit=10
Response:
{
"data": [
/* array of courses */
],
"meta": { "page": 1, "limit": 10, "total": 45, "totalPages": 5 }
}
-
Course details:
GET /api/courses/:id
-
Enroll in a course (student only):
POST /api/courses/:id/enroll
Headers: Authorization: Bearer <STUDENT_TOKEN>
Response:
-
201
→{ "message": "Enrolled successfully" }
-
409
→{ "message": "Already enrolled" }
- JWT is issued at login/registration and must be sent as:
Authorization: Bearer <token>
- Token payload includes
id
androle
.
Use query parameters:
-
page
(default 1) -
limit
(default 10, max 100)
-
Centralized error middleware returns JSON errors.
-
Common responses:
-
400 — Bad Request
-
401 — Unauthorized
-
403 — Forbidden
-
404 — Not Found
-
409 — Conflict
-
500 — Internal Server Error
-
-
Add request validation (Joi / Zod)
-
Configure CORS, rate limiting, HTTPS for production
-
Use migrations instead of raw SQL
-
Add tests (unit + integration)