Do you love kittens? Yes, me too! So I've decided to write a little tutorial about it. In this article, we'll build a lightweight REST API to manage kitten data using modern tools:
- Bun as the runtime (a faster alternative to Node.js)
- ElysiaJS as the web framework
- mockup-storage for schema-based data persistence
By the way, the mockup-storage
library was developed by me, so donβt hesitate to use it, create issues, and request features if you need them! π±
Step 1: Project Setup
1. Install Bun
First, you'll need to install Bun. Follow the official installation guide for your operating system.
2. Initialize the Project
Create a folder for your project. I'll call it kittens-api
. Navigate to the folder and initialize the project:
mkdir kittens-api
cd kittens-api
npm init -y
bun add elysia mockup-storage
This will set up a new project and install the necessary dependencies: ElysiaJS for the web framework and mockup-storage for data persistence.
3. Create the Entry Point
Create an index.ts
file in the src
folder. This will be the entry point for our application.
mkdir src
touch src/index.ts
Step 2: Instantiate Storage
The mockup-storage
library allows you to define schemas for your data, providing built-in validation and schema enforcement. Here, we'll use its APIs to set up a kittens
collection.
Define the Kitten Schema
In src/index.ts
, start by importing the necessary modules and defining the schema for our kitten records:
import { MockStorage, MockRecordSchema } from "mockup-storage";
// Define the schema for kittens
const kittenSchema: MockRecordSchema = {
name: "string", // Kitten's name (string)
age: "number", // Kitten's age (number)
breed: "string", // Kitten's breed (string)
adoptedAt: "datetime" // Adoption date (datetime)
};
// Initialize the storage with the kitten schema
const storage = new MockStorage({
kittens: kittenSchema,
});
export default storage;
Step 3: Create the Server with ElysiaJS
With the storage initialized, letβs set up a server using ElysiaJS. This will act as the backend for our kittens API, exposing CRUD endpoints to manage the kittens
collection.
Initialize the Server
Add the following code to src/index.ts
to set up the Elysia server:
import { Elysia } from "elysia";
// Start the Elysia server
const app = new Elysia()
.listen(3000)
.get("/", () => "Welcome to the Kitten API! π±")
.onStart(async () => {
await storage.initialize(); // Initialize the storage
console.log("π± Server started on http://localhost:3000");
});
export default app;
Step 4: Implement CRUD Endpoints
Hereβs how to implement each endpoint using the MockCollection
APIs.
1. POST /kittens β Add a New Kitten
To add a new kitten, weβll use the add
method from the MockCollection
API:
app.post("/kittens", async ({ body }) => {
const kittens = await storage.collection("kittens");
try {
const newKitten = await kittens.add(body);
return new Response(JSON.stringify(newKitten), { status: 201 });
} catch (error) {
return new Response(`Validation error: ${error.message}`, { status: 400 });
}
});
2. GET /kittens β List All Kittens
Retrieve all kittens using the all
method:
app.get("/kittens", async () => {
const kittens = await storage.collection("kittens");
return await kittens.all();
});
3. GET /kittens/:id β Get a Single Kitten
Use the get
method to retrieve a kitten by its unique ID:
app.get("/kittens/:id", async ({ params: { id } }) => {
const kittens = await storage.collection("kittens");
const kitten = await kittens.get(id);
return kitten || new Response("Kitten not found", { status: 404 });
});
4. PUT /kittens/:id β Update a Kitten
Use the remove
and add
methods to replace a record:
app.put("/kittens/:id", async ({ params: { id }, body }) => {
const kittens = await storage.collection("kittens");
const exists = await kittens.get(id);
if (!exists) return new Response("Not found", { status: 404 });
await kittens.remove(id);
const updated = await kittens.add({ ...body, id }); // Re-add with updated data
return updated;
});
5. DELETE /kittens/:id β Remove a Kitten
Delete a kitten using the remove
method:
app.delete("/kittens/:id", async ({ params: { id } }) => {
const kittens = await storage.collection("kittens");
const success = await kittens.remove(id);
return success
? new Response(null, { status: 204 })
: new Response("Failed to delete", { status: 500 });
});
Step 5: Test the API
Create a Kitten
curl -X POST http://localhost:3000/kittens \
-H "Content-Type: application/json" \
-d '{"name": "Whiskers", "age": 2, "breed": "Tabby"}'
List All Kittens
curl http://localhost:3000/kittens
Get a Single Kitten
curl http://localhost:3000/kittens/123
Update a Kitten
curl -X PUT http://localhost:3000/kittens/123 \
-H "Content-Type: application/json" \
-d '{"age": 3}'
Delete a Kitten
curl -X DELETE http://localhost:3000/kittens/123
Next Steps
- Add pagination to
GET /kittens
. - Implement search by breed or age.
- Deploy the API to a Bun-compatible hosting platform.
Next time, we will add picture uploads β meanwhile, check out my library mockup-storage and its GitHub repository!
Let me know in the comments what youβd build next! π
Final Project Structure
kittens-api/
βββ src/
β βββ index.ts
βββ .mock/ # Auto-created data directory
βββ package.json
βββ bun.lockb
Happy coding! πΎ
Top comments (0)