API reference
Development

Development Setup

Prerequisites

  • Go: 1.24.6 or later
  • Docker: For containerization
  • minikube: Local Kubernetes development
  • Helm: Package management
  • Make: Build automation

Initial Setup

  1. Clone Repository


    git clone https://github.com/menloresearch/jan-server
    cd jan-server

  2. Install Development Tools


    cd apps/jan-api-gateway/application
    make install

  3. Generate Code


    make setup

  4. Start Development Environment


    # From project root
    ./scripts/run.sh

API Gateway Development

Project Structure


apps/jan-api-gateway/application/
├── cmd/server/ # Entry point and dependency injection
│ ├── server.go # Main server setup
│ ├── wire.go # DI configuration
│ └── wire_gen.go # Generated DI code
├── app/ # Core application logic
│ ├── domain/ # Business entities
│ ├── repository/ # Data access layer
│ ├── service/ # Business logic
│ └── handler/ # HTTP handlers
├── config/ # Configuration management
└── docs/ # Generated API documentation

Build Commands


# Install development dependencies
make install
# Generate API documentation
make doc
# Generate dependency injection code
make wire
# Complete setup (doc + wire)
make setup
# Build application
go build -o jan-api-gateway ./cmd/server

Code Generation

Jan Server uses code generation for several components:

Swagger Documentation:


# Generates docs/swagger.json and docs/swagger.yaml
swag init --parseDependency -g cmd/server/server.go -o docs

Dependency Injection:


# Generates wire_gen.go from wire.go providers
wire ./cmd/server

Database Models:


# Generate GORM models (when schema changes)
go run cmd/codegen/gorm/gorm.go

Local Development

Running API Gateway Locally


cd apps/jan-api-gateway/application
# Set environment variables
export JAN_INFERENCE_MODEL_URL=http://localhost:8101
export JWT_SECRET=your-jwt-secret
export DB_POSTGRESQL_WRITE_DSN="host=localhost user=jan-user password=jan-password dbname=jan port=5432 sslmode=disable"
# Run the server
go run ./cmd/server

Database Setup

For local development, you can run PostgreSQL directly:


# Using Docker
docker run -d \
--name jan-postgres \
-e POSTGRES_DB=jan \
-e POSTGRES_USER=jan-user \
-e POSTGRES_PASSWORD=jan-password \
-p 5432:5432 \
postgres:14

Testing

Running Tests


# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run specific test package
go test ./app/service/...

Test Structure


app/
├── service/
│ ├── auth_service.go
│ ├── auth_service_test.go
│ ├── conversation_service.go
│ └── conversation_service_test.go
└── handler/
├── auth_handler.go
├── auth_handler_test.go
├── chat_handler.go
└── chat_handler_test.go

Writing Tests

Example service test:


func TestAuthService_ValidateToken(t *testing.T) {
// Setup
service := NewAuthService(mockRepo, mockConfig)
// Test cases
tests := []struct {
name string
token string
expectValid bool
expectError bool
}{
{"valid token", "valid.jwt.token", true, false},
{"invalid token", "invalid.token", false, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
valid, err := service.ValidateToken(tt.token)
assert.Equal(t, tt.expectValid, valid)
assert.Equal(t, tt.expectError, err != nil)
})
}
}

Docker Development

Building Images


# Build API gateway
docker build -t jan-api-gateway:dev ./apps/jan-api-gateway
# Build inference model
docker build -t jan-inference-model:dev ./apps/jan-inference-model

Development Compose

For local development without Kubernetes:


# docker-compose.dev.yml
version: '3.8'
services:
postgres:
image: postgres:14
environment:
POSTGRES_DB: jan
POSTGRES_USER: jan-user
POSTGRES_PASSWORD: jan-password
ports:
- "5432:5432"
api-gateway:
build: ./apps/jan-api-gateway
ports:
- "8080:8080"
environment:
- JAN_INFERENCE_MODEL_URL=http://inference-model:8101
- DB_POSTGRESQL_WRITE_DSN=host=postgres user=jan-user password=jan-password dbname=jan port=5432 sslmode=disable
depends_on:
- postgres
inference-model:
build: ./apps/jan-inference-model
ports:
- "8101:8101"

Debugging

Go Debugging

For VS Code debugging, add to .vscode/launch.json:


{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Jan API Gateway",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/apps/jan-api-gateway/application/cmd/server",
"env": {
"JAN_INFERENCE_MODEL_URL": "http://localhost:8101",
"JWT_SECRET": "development-secret"
}
}
]
}

Application Logs


# View API gateway logs
kubectl logs deployment/jan-server-jan-api-gateway -f
# View inference model logs
kubectl logs deployment/jan-server-jan-inference-model -f
# View PostgreSQL logs
kubectl logs statefulset/jan-server-postgresql -f

Log Levels

Set log level via environment variable:


export LOG_LEVEL=debug # debug, info, warn, error

Code Style and Standards

Go Standards

API Standards

  • RESTful endpoint design
  • OpenAPI/Swagger annotations for all endpoints
  • Consistent error response format
  • Proper HTTP status codes

Git Workflow


# Create feature branch
git checkout -b feature/your-feature-name
# Make changes and commit
git add .
git commit -m "feat: add new authentication endpoint"
# Push and create PR
git push origin feature/your-feature-name

Commit Message Format

Follow conventional commits:


feat: add new feature
fix: resolve bug in authentication
docs: update API documentation
test: add unit tests for service layer
refactor: improve error handling

Performance Testing

Load Testing

Use k6 (opens in a new tab) for API load testing:


// load-test.js
import http from 'k6/http';
export default function () {
const response = http.post('http://localhost:8080/api/v1/chat/completions', {
model: 'jan-v1-4b',
messages: [
{ role: 'user', content: 'Hello!' }
]
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
}
});
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 5000ms': (r) => r.timings.duration < 5000,
});
}

Run load test:


k6 run --vus 10 --duration 30s load-test.js

Memory Profiling

Enable Go profiling endpoints:


import _ "net/http/pprof"
// In main.go
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()

Profile memory usage:


go tool pprof http://localhost:6060/debug/pprof/heap

Contributing

Pull Request Process

  1. Fork the repository
  2. Create feature branch from main
  3. Make changes following code standards
  4. Add tests for new functionality
  5. Update documentation if needed
  6. Submit pull request with clear description

Code Review Checklist

  • Code follows Go standards
  • Tests added for new features
  • Documentation updated
  • API endpoints have Swagger annotations
  • No breaking changes without version bump
  • Security considerations addressed

Issues and Bug Reports

When reporting bugs, include:

  • Environment: OS, Go version, minikube version
  • Steps to reproduce: Clear, minimal reproduction steps
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Logs: Relevant error messages or logs

For security issues, please report privately to the maintainers instead of creating public issues.

Release Process

Version Management

Jan Server uses semantic versioning (semver):

  • Major: Breaking changes
  • Minor: New features, backward compatible
  • Patch: Bug fixes, backward compatible

Building Releases


# Tag release
git tag -a v1.2.3 -m "Release v1.2.3"
# Build release images
docker build -t jan-api-gateway:v1.2.3 ./apps/jan-api-gateway
docker build -t jan-inference-model:v1.2.3 ./apps/jan-inference-model
# Push tags
git push origin v1.2.3

Deployment

Production deployments follow the same Helm chart structure:


# Deploy specific version
helm install jan-server ./charts/umbrella-chart \
--set jan-api-gateway.image.tag=v1.2.3 \
--set jan-inference-model.image.tag=v1.2.3