Quick Start

Build your first JustScale application in 5 minutes

Create a New Project

Bash
mkdir my-app && cd my-app
pnpm init -y
pnpm add @justscale/core @justscale/http @justscale/cluster
pnpm add --save-dev typescript @types/node

Create Your First Service

Services contain your business logic. Create src/services/greeting.ts:

Files
src/services/greeting.tsTypeScript
import { createService } from '@justscale/core'

export const GreetingService = createService({
  inject: {},
  factory: () => ({
    greet: (name: string) => `Hello, ${name}!`,
    farewell: (name: string) => `Goodbye, ${name}!`,
  }),
})

Create a Controller

Controllers group related routes. Create src/controllers/greeting.ts:

Files
src/controllers/greeting.tsTypeScript
import { createController } from '@justscale/core'
import { Get } from '@justscale/http'
import { z } from 'zod'
import { GreetingService } from '../services/greeting'

// Response schema for type safety & OpenAPI generation
const MessageResponse = z.object({
  message: z.string(),
})

export const GreetingController = createController('/greet', {
  inject: { greeting: GreetingService },

  routes: (services) => ({
    hello: Get('/:name')
      .returns(MessageResponse)
      .handle(({ params, res }) => {
        const message = services.greeting.greet(params.name)
        res.json({ message })
      }),

    goodbye: Get('/bye/:name')
      .returns(MessageResponse)
      .handle(({ params, res }) => {
        const message = services.greeting.farewell(params.name)
        res.json({ message })
      }),
  }),
})

Create the Application

Wire everything together in src/index.ts:

Files
src/index.tsTypeScript
import { createClusterBuilder, wrapWithCluster } from '@justscale/cluster'
import { GreetingController } from './controllers/greeting'
import { GreetingService } from './services/greeting'

const built = createClusterBuilder()
  .add(GreetingService)
  .add(GreetingController)
  .build()

const cluster = wrapWithCluster(built.compile())
await cluster.serve({ http: 3000 })
console.log('Server running on http://localhost:3000')

Run It

Bash
npx tsx src/index.ts

Test your API:

Bash
curl http://localhost:3000/greet/World
# {"message":"Hello, World!"}

curl http://localhost:3000/greet/bye/World
# {"message":"Goodbye, World!"}

What's Next?

Add Validation

Use Zod schemas to validate request body and declare response types:

users-controller.tsTypeScript
import { createController } from '@justscale/core';
import { Post } from '@justscale/http';
import { body } from '@justscale/http/builder';
import { z } from 'zod';
import { UserService } from './user-service';

// Request body schema
const CreateUserBody = z.object({
  email: z.string().email(),
  name: z.string().min(2),
});

// Response schemas
const UserResponse = z.object({
  user: z.object({
    id: z.string(),
    email: z.string(),
    name: z.string(),
  }),
});
const ErrorResponse = z.object({ error: z.string() });

const UsersController = createController('/users', {
  inject: { users: UserService },

  routes: (services) => ({
    create: Post('/')
      .apply(body(CreateUserBody))
      .returns(UserResponse, 201)
      .returns(ErrorResponse, 400)
      .handle(async ({ body, res }) => {
        // body is typed as { email: string; name: string }
        const user = await services.users.create(body);
        res.status(201).json({ user });
      }),
  }),
});

Add Features

Use Features for production-ready functionality like pub/sub channels, interactive shell, and more.

Add Database

Use the Repository Pattern for database access.