Skip to main content
Home

Built and signed on GitHub Actions

HTTP Framework inspired by Express, Fastify and Oak

This package works with DenoIt is unknown whether this package works with Cloudflare Workers, Node.js, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
It is unknown whether this package works with Node.js
This package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
100%
Published
10 months ago (0.6.10)

Planigale

Description

Minimalistic HTTP framework for Deno

Usage

Deno

Planigale is available on both deno.land/x and JSR. For deno.land/x use the following import:

import { Planigale } from 'https://deno.land/x/planigale/mod.ts';

For JSR use the following import:

import { Planigale } from 'jsr:@planigale/planigale';

or add it to your import maps:

deno add @planigale/planigale

NPM

Maybe in future

Basic example

import { Planigale } from 'jsr:@planigale/planigale';

const app = new Planigale();

// Simple logging middleware
app.use(async (req, next) => {
  const ts = new Date().toISOString();
  const log = ts + ': ' + req.method + ' ' + req.url;
  console.time(log);
  const res = await next();
  console.timeEnd(log);
  return res;
});

app.route({
  method: 'GET',
  url: '/users/:id',
  handler: async (req) => {
    const id = req.params.id;
    return Response.json({ id });
  },
});

app.serve({ port: 8000 });

Defining routes

Routes are meant to produce a response to a particular request. They are defined by the route method of the app object. The method takes an object with the following properties:

type RouteDefinition = {
  method: string;
  url: string;
  description?: string;
  schema?: object;
  handler: (req: Req) => Promise<Res | Response>;
};

Validation support

Planigale supports validation of request body and query parameters using ajv library. ajv is not native to Deno, so this can change in the future. For validation json schema is used.

app.route({
  method: 'GET',
  url: '/users/:id',
  schema: {
    params: {
      type: 'object',
      required: ['id'],
      properties: {
        id: { type: 'number' },
      },
    },
    headers: {
      type: 'object',
      required: ['authorization'],
      properties: {
        authorization: { type: 'string', pattern: 'Bearer .+' },
      },
    },
  },
  handler: async (req) => {
    const id = req.params.id;
    return Response.json({ id });
  },
});

const request: Request = new Request('http://localhost:3000/users/invalid_id', {
  method: 'GET',
  headers: {
    authorization: 'invalid_token',
  },
});

const response: Response = await app.handle(request);

assertEquals(response.status, 400);
assertEquals(await response.json(), [
  {
    block: 'params',
    instancePath: '/id',
    keyword: 'type',
    message: 'must be number',
    params: {
      type: 'number',
    },
    schemaPath: '#/properties/id/type',
  },
  {
    block: 'headers',
    instancePath: '/authorization',
    keyword: 'pattern',
    message: 'must match pattern "[Bb]earer .*"',
    params: {
      pattern: '[Bb]earer .*',
    },
    schemaPath: '#/properties/authorization/pattern',
  },
]);

Middleware

Middleware is a function that has access to the request object, the response object, and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

app.use(async (req, next) => {
    console.log("Before", req.url);
    const res = await next();
    console.log("After", req.url);
    return res;
});

## Testing

### Unit testing
Planigale is designed to be easily testable. You can test your handlers without running the server.
```typescript
import { Planigale } from "@planigale/planigale";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

const app = new Planigale();

const route = app.route({
  method: "GET",
  url: "/users/:id",
  handler: async (req) => {
    const id = req.params.id;
    const id = req.state.user.name;
    return Res.json({ id, name });
  },
})

Deno.test("Chaking endpoints output", async () => {
    const req = new Req("/users/1", {method: "GET", state: {user: {name: "John"}}});
    const res = await route.handler(req);
    assertEquals(res.status, 200);
    assertEquals(res.body, { id: "1", name: "john" });
})

Module testing

Whole app can be easlily tested using just one function that take Request object as an argument and return Response object.

import { Planigale } from 'https://deno.land/x/planigale/mod.ts';
import { assertEquals } from 'https://deno.land/std/testing/asserts.ts';

const app = new Planigale();

app.route({
  method: 'GET',
  url: '/users/:id',
  handler: async (req) => {
    const id = req.params.id;
    return Res.json({ id });
  },
});

Deno.test('Chaking endpoints output', async () => {
  const request: Request = new Request('http://localhost:3000/users/1', {
    method: 'GET',
  });

  const response: Response = await app.handle(request);

  assertEquals(response.status, 200);
  assertEquals(await response.json(), { id: '1' });
});

Integration testing

Deno.test('Chaking full app', async (t) => {
  const app = new Planigale();

  app.route({
    method: 'GET',
    url: '/users/:id',
    handler: async (req, res) => {
      const id = req.params.id;
      res.send({ id });
    },
  });

  t.step('start up', async () => {
    await app.serve(3000);
  });

  t.step('GET /users/1', async () => {
    const request: Request = new Request('http://localhost:3000/users/1', {
      method: 'GET',
    });

    const response: Response = await fetch(request);

    assertEquals(response.status, 200);
    assertEquals(await response.json(), { id: '1' });
  });

  t.step('tear down', async () => {
    await app.close();
  });
});

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Make your changes and add tests
  4. Run tests: deno task check
  5. Commit your changes: git commit -am 'feat: add some feature' // use conventional commits
  6. Push to the branch: git push origin my-new-feature
  7. Submit a pull request :D

License

MIT License

Copyright (c) 2024 Mateusz Russak

Built and signed on
GitHub Actions

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";
or

Import directly with a jsr specifier

import * as planigale from "jsr:@planigale/planigale";

Add Package

pnpm i jsr:@planigale/planigale
or (using pnpm 10.8 or older)
pnpm dlx jsr add @planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";

Add Package

yarn add jsr:@planigale/planigale
or (using Yarn 4.8 or older)
yarn dlx jsr add @planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";

Add Package

vlt install jsr:@planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";

Add Package

npx jsr add @planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";

Add Package

bunx jsr add @planigale/planigale

Import symbol

import * as planigale from "@planigale/planigale";