0.2.0 • Published 9 months ago

funclify v0.2.0

Weekly downloads
-
License
ISC
Repository
-
Last release
9 months ago

Funclify 🤖

Funclify is an opinionated framework for building APIs on Netlify Functions. It's fast, it's powerful and most importantly focused around a great developer experience.

Currently, this is a TypeScript-only framework. This reflects the current focus of the project, being a type-safe and DX focused package, and in the future it may be updated to compile to support ESM. It's early days, so please forgive the narrow-focus.

⚠️ Just one thing!

Funclify is very early on in it's development. It may be abandoned, it may be completely up-ended and rewriten in Rust 👀, so as much as I'd love to say use this in production, bear those things in mind.

Install

# pnpm
pnpm add funclify

# npm
npm install funclify

Basic Use

Funclify includes an API class which is the entry point for both defining handlers and also processing requests.

// netlify/functions/api.ts
import { Api } from 'funclify';

const api = new Api();

api.get("/", async (_, res) => {
    return res.withJSON({ message: "Hello World!" });
});

export const handler = api.baseHandler;

Typed Route Parameters

Funclify is focused on being a strongly-typed framework. This extends to route parameters. Making heavy use of infer, we can create a strongly-typed params property that lives on the req argument passed to your route handler.

api.get("/users/:user_id/orders/:order_id", async({ params }, res) => {
    // params: { user_id: string, order_id: string }
    const { user_id, order_id } = params;

    const order = await fetchOrder(user_id, order_id);

    return res.withJSON(order);
})

Testing

Funclify comes bundled with a test harness to make it simple to run integration tests against your API.

Although you could adopt a more "unit" approach, the framework is built to encourage testing to the boundary of your application for each and every API route.

An example below utilising Vitest

import { describe, it, beforeEach, expect } from "vitest";
import { ApiTestHarness } from "funclify";
import { api } from "../functions/api";

describe("API", () => {
  let test: ApiTestHarness<typeof api>;

  beforeEach(() => {
    // This could be set once rather than in before-each, as
    // in theory an API should be idempotent. However, for flexibility
    // atomicity can be guaranteed by initialising in the beforeEach
    test = new ApiTestHarness(api);
  });

  it("should return a user object", async () => {
    // Perform the request. Under the hood, this
    // emulates the `event` and `context` fed in
    // from a Netlify Function
    const response = await test.get("/user/123");

    expect(response.statusCode).toBe(200);

    // Regardless of your application output, the response
    // from a Netlify Function will be a string, so we need
    // to parse into JSON to assert on the returned objects
    expect(response.body).toBeTypeOf("string");

    const body = JSON.parse(response.body!);
    expect(body).toContain({
      id: "123",
      name: "Ed",
    });
  });
});
0.2.0

9 months ago

0.1.8

12 months ago

0.1.7

12 months ago

0.1.6

1 year ago

0.1.5

1 year ago

0.1.4

1 year ago

0.1.3

1 year ago

0.1.2

1 year ago

0.1.0

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago