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;