DEV Community

Konstantin Podyganov
Konstantin Podyganov

Posted on

Creating a Simple REST API for Storing Kittens with ElysiaJS

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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 });
  }
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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 });
});
Enter fullscreen mode Exit fullscreen mode

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;
});
Enter fullscreen mode Exit fullscreen mode

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 });
});
Enter fullscreen mode Exit fullscreen mode

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"}'
Enter fullscreen mode Exit fullscreen mode

List All Kittens

curl http://localhost:3000/kittens
Enter fullscreen mode Exit fullscreen mode

Get a Single Kitten

curl http://localhost:3000/kittens/123
Enter fullscreen mode Exit fullscreen mode

Update a Kitten

curl -X PUT http://localhost:3000/kittens/123 \
  -H "Content-Type: application/json" \
  -d '{"age": 3}'
Enter fullscreen mode Exit fullscreen mode

Delete a Kitten

curl -X DELETE http://localhost:3000/kittens/123
Enter fullscreen mode Exit fullscreen mode

Next Steps

  1. Add pagination to GET /kittens.
  2. Implement search by breed or age.
  3. 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
Enter fullscreen mode Exit fullscreen mode

Happy coding! 🐾

Top comments (0)