Docs
Tutorial

Tutorial

Let's build a REST-like API that provides CRUD operations for task management using Websi.

Starting point

This is one of the most basic web servers that can be built with Websi. Let's use it as a starting point for our API.

main.ts
import { Server } from 'websi';
import { GET } from 'websi/route';
import * as Response from 'websi/response';
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!'))
]
 
const server = Server(routes)
export default server;

Implementing CRUD

Getting all tasks

Let's start by defining the type for our data along with in-memory list of tasks.

Then, we can add the /tasks route that responds to GET requests. In Websi passing a JavaScript object directly to Response.* aliases automatically serializes it to the JSON format.

main.ts
import { Server } from 'websi';
import { GET } from 'websi/route';
import * as Response from 'websi/response';
 
type Task = {
  name: string
  done: boolean
}
 
const tasks: Task[] = [
  { name: 'Recite 30 digits of Pi', done: false },
  { name: 'Balance a spoon on my nose', done: false },
  { name: 'Juggle with 4 apples', done: false }
]
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!')),
  GET('/tasks', () => Response.OK(tasks)),
]
 
const server = Server(routes)
export default server;

Send a request to the /tasks route using HTTPie

http :4000/tasks

or open http://localhost:4000/tasks (opens in a new tab) in your browser

Getting a single task

main.ts
import { Server } from 'websi';
import { GET } from 'websi/route';
import * as Response from 'websi/response';
 
type Task = {
  id: number
  name: string
  done: boolean
}
 
const byID = (id: string) => (element: Task) => element.id === id;
const randomInt = (max: number) => Math.floor(Math.random() * max);
 
const tasks = [
  { id: 1, name: 'Recite 30 digits of Pi', done: false },
  { id: 2, name: 'Balance a spoon on my nose', done: false },
  { id: 3, name: 'Juggle with 4 apples', done: false }
]
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!')),
  GET('/tasks', () => Response.OK(tasks)),
  GET('/tasks/:id', ({ params }) => {
    const { id } = params;
 
    const found = tasks.find(byID(id as string));
 
    return found ? Response.OK(found) : Response.NotFound();
  }),
]
 
const server = Server(routes)
export default server;

Adding new task

main.ts
import { Server } from 'websi';
import { GET, POST } from 'websi/route';
import * as Response from 'websi/response';
 
type Task = {
  id: number
  name: string
  done: boolean
}
 
const byID = (id: string) => (element: Task) => element.id === id;
const randomInt = (max: number) => Math.floor(Math.random() * max);
 
const tasks = [
  { id: 1, name: 'Recite 30 digits of Pi', done: false },
  { id: 2, name: 'Balance a spoon on my nose', done: false },
  { id: 3, name: 'Juggle with 4 apples', done: false }
]
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!')),
  GET('/tasks', () => Response.OK(tasks)),
  GET('/tasks/:id', ({ params }) => {
    const { id } = params;
 
    const found = tasks.find(byID(id as string));
 
    return found ? Response.OK(found) : Response.NotFound();
  }),
  POST('/tasks', async ({ params: { name } }) => {
    const { name } = params;
 
    tasks.push({
      id: randomInt(100).toString(),
      name: name as string,
      done: false
    })
 
    return Response.Created();
  })
]
 
const server = Server(routes)
export default server;

Updating a task

import { Server } from 'websi';
import { GET, POST, PATCH, DELETE } from 'websi/route';
import * as Response from 'websi/response';
 
type Task = {
  id: string;
  name: string
  done: boolean
}
 
const byID = (id: string) => (element: Task) => element.id === id;
const randomInt = (max: number) => Math.floor(Math.random() * max);
 
const tasks: Task[] = [
  { id: 1, name: 'Recite 30 digits of Pi', done: false },
  { id: 2, name: 'Balance a spoon on my nose', done: false },
  { id: 3, name: 'Juggle with 4 apples', done: false }
]
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!')),
  GET('/tasks', () => Response.OK(tasks)),
  GET('/tasks/:id', ({ params }) => {
    const { id } = params;
 
    const found = tasks.find(byID(id as string));
 
    return found ? Response.OK(found) : Response.NotFound();
  }),
  POST('/tasks', async ({ params }) => {
    const { name } = params;
 
    tasks.push({
      id: randomInt(100).toString(),
      name: name as string,
      done: false
    })
 
    return Response.Created();
  }),
  PATCH('/tasks/:id', ({ params }) => {
    const { name, id } = params;
 
    const found = tasks.find(byID(id as string));
 
    if (found) {
      found.name = name as string;
    }
 
    return Response.Accepted();
  })
]
 
const server = Server(routes)
export default server;

Deleting a task

import { Server } from 'websi';
import { GET, POST, PATCH, DELETE } from 'websi/route';
import * as Response from 'websi/response';
 
type Task = {
  id: string;
  name: string
  done: boolean
}
 
const randomInt = (max: number) => Math.floor(Math.random() * max);
const byID = (id: string) => (element: Task) => element.id === id;
 
const tasks: Task[] = [
  { id: 1, name: 'Recite 30 digits of Pi', done: false },
  { id: 2, name: 'Balance a spoon on my nose', done: false },
  { id: 3, name: 'Juggle with 4 apples', done: false }
]
 
const routes = [
  GET('/', () => Response.OK('Hello, Websi!')),
  GET('/tasks', () => Response.OK(tasks)),
  GET('/tasks/:id', ({ params }) => {
    const { id } = params;
 
    const found = tasks.find(byID(id as string));
 
    return found ? Response.OK(found) : Response.NotFound();
  }),
  POST('/tasks', async ({ params }) => {
    const { name } = params;
 
    tasks.push({
      id: randomInt(100).toString(),
      name: name as string,
      done: false
    })
 
    return Response.Created();
  }),
  PATCH('/tasks/:id', ({ params }) => {
    const { name, id } = params;
 
    const found = tasks.find(byID(id as string));
 
    if (found) {
      found.name = name as string;
    }
 
    return Response.Accepted();
  }),
  DELETE('/tasks/:id', ({ params }) => {
    const { id } = params;
 
    const found = tasks.findIndex(byID(id as string))
    tasks.splice(found, 1);
 
    return found > 0 ? Response.Accepted() : Response.NotFound();
  })
]
 
const server = Server(routes)
export default server;