Skip to main content

Prerequisites

Before you begin, ensure you have the following installed:

Go 1.22+

Download from go.dev/dl

PostgreSQL 14+

Install from postgresql.org

Goose

Migration tool: go install github.com/pressly/goose/v3/cmd/goose@latest

42 Intra Account

Required for OAuth2 authentication at Hive Helsinki

Installation

1

Clone the repository

git clone https://github.com/IbnBaqqi/book-me.git
cd book-me
2

Install dependencies

go mod download
This downloads all required Go packages including:
  • github.com/golang-jwt/jwt/v5 for JWT authentication
  • github.com/lib/pq for PostgreSQL connection
  • golang.org/x/time/rate for rate limiting
3

Configure environment variables

Copy the example environment file and fill in your credentials:
cp .env.example .env
Edit .env with your configuration:
.env
# Server Configuration
PORT=8080
SERVER_READ_TIMEOUT=15s
SERVER_WRITE_TIMEOUT=15s
SERVER_IDLE_TIMEOUT=60s
LOG_LEVEL=info

# App Configuration
ENV=development
DB_URL=postgres://user:password@localhost:5432/bookme?sslmode=disable

# 42 Intra OAuth2
CLIENT_ID=your_42_client_id
SECRET=your_42_secret
REDIRECT_URI=http://localhost:8080/oauth/callback
OAUTH_AUTH_URI=https://api.intra.42.fr/oauth/authorize
OAUTH_TOKEN_URI=https://api.intra.42.fr/oauth/token
USER_INFO_URL=https://api.intra.42.fr/v2/me

# JWT Configuration
JWT_SECRET=your_jwt_secret_here

# Email Configuration (Optional)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=your_app_password
FROM_EMAIL=[email protected]
FROM_NAME=BookMe
SMTP_USE_TLS=true

# Google Calendar (Optional - Staff only)
GOOGLE_CREDENTIALS_FILE=./assets/book-me-service-account.json
GOOGLE_CALENDAR_SCOPE=https://www.googleapis.com/auth/calendar
GOOGLE_CALENDAR_ID=[email protected]
Never commit your .env file to version control. The .gitignore file is already configured to exclude it.
4

Set up the database

Create a PostgreSQL database:
createdb bookme
Run migrations to create tables:
goose -dir sql/schema postgres "postgres://user:password@localhost:5432/bookme?sslmode=disable" up
This creates three tables:
  • users - Stores user accounts from 42 Intra
  • rooms - Contains available meeting rooms (big, small)
  • reservations - Tracks all bookings
The migration automatically populates two rooms: “big” and “small”. These are the meeting rooms at Hive Helsinki.
5

Start the server

Run the development server:
make run
Or with hot reload (requires Air):
make dev
You should see output like:
2024-03-03T10:30:00Z INFO starting book-me server port=8080 log_level=info
2024-03-03T10:30:00Z INFO Server listening address=:8080

Make Your First API Call

1

Check server health

Verify the server is running:
curl http://localhost:8080/api/v1/health
Expected response:
{
  "status": "ok"
}
2

Authenticate with 42 Intra

Open your browser and navigate to:
http://localhost:8080/oauth/login
This redirects you to 42 Intra for authentication. After successful login, you’ll be redirected back with a JWT token in the response.
The JWT token is valid for 1 hour. After expiration, you’ll need to re-authenticate.
3

Create a reservation

Use your JWT token to create a reservation:
curl -X POST http://localhost:8080/api/v1/reservations \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "roomId": 1,
    "startTime": "2024-03-04T10:00:00Z",
    "endTime": "2024-03-04T11:00:00Z"
  }'
Successful response:
{
  "Id": 1,
  "roomId": 1,
  "startTime": "2024-03-04T10:00:00Z",
  "endTime": "2024-03-04T11:00:00Z",
  "createdBy": {
    "Id": 42,
    "name": "John Doe"
  }
}
Times must be in UTC format and fall within school hours. The API validates both constraints automatically.
4

View reservations

Get all unavailable time slots for a date range:
curl -X GET "http://localhost:8080/api/v1/reservations?start=2024-03-01&end=2024-03-31" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response format:
[
  {
    "roomId": 1,
    "roomName": "big",
    "slots": [
      {
        "id": 1,
        "startTime": "2024-03-04T10:00:00Z",
        "endTime": "2024-03-04T11:00:00Z",
        "bookedBy": "John Doe"
      }
    ]
  }
]
The bookedBy field is only visible to staff members. Students see null for privacy.
5

Cancel a reservation

Delete a reservation by ID:
curl -X DELETE http://localhost:8080/api/v1/reservations/1 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Success returns HTTP 204 No Content.
Students can only cancel their own reservations. Staff can cancel any reservation.

Code Examples

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type CreateReservationRequest struct {
	RoomID    int64     `json:"roomId"`
	StartTime time.Time `json:"startTime"`
	EndTime   time.Time `json:"endTime"`
}

func createReservation(token string) error {
	req := CreateReservationRequest{
		RoomID:    1,
		StartTime: time.Now().Add(24 * time.Hour).UTC(),
		EndTime:   time.Now().Add(25 * time.Hour).UTC(),
	}

	body, _ := json.Marshal(req)
	httpReq, _ := http.NewRequest(
		"POST",
		"http://localhost:8080/api/v1/reservations",
		bytes.NewBuffer(body),
	)

	httpReq.Header.Set("Authorization", "Bearer "+token)
	httpReq.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(httpReq)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	responseBody, _ := io.ReadAll(resp.Body)
	fmt.Println(string(responseBody))
	return nil
}

Rate Limiting

BookMe implements rate limiting to prevent abuse:
  • OAuth endpoints (/oauth/*): 5 requests per 12 seconds
  • API endpoints (/api/v1/*): 30 requests per 2 seconds
Exceeding these limits returns HTTP 429 Too Many Requests.
Rate limits are per-IP address and reset automatically after the time window.

Development Commands

Useful Make commands for development:
# Run the server
make run

# Run with hot reload
make dev

# Build binary
make build

# Run tests
make test

# Run tests with coverage
make test-coverage

# Format code
make fmt

# Generate SQLC code after modifying SQL
make sqlc

# Clean build artifacts
make clean

Project Structure

Understanding the codebase:
book-me/
├── cmd/server/main.go          # Application entry point (cmd/server/main.go:22)
├── internal/
│   ├── api/                    # HTTP server setup
│   │   ├── api.go             # Service initialization
│   │   └── routes.go          # Route definitions (internal/api/routes.go:14)
│   ├── handler/               # HTTP handlers
│   │   ├── handler_reservations.go  # Reservation endpoints (internal/handler/handler_reservations.go:18)
│   │   └── handler_oauth.go   # OAuth flow
│   ├── service/               # Business logic
│   ├── database/              # SQLC generated code
│   ├── auth/                  # JWT authentication (internal/auth/auth.go:76)
│   └── middleware/            # HTTP middleware
└── sql/                       # Database migrations

Next Steps

Authentication Guide

Deep dive into 42 Intra OAuth2 and JWT authentication

API Reference

Explore all endpoints with detailed examples

Error Handling

Learn about error codes and how to handle them

Core Concepts

Learn about BookMe’s architecture and design
Having issues? Check the GitHub Issues or open a new one.

Build docs developers (and LLMs) love