npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@refactorthis/funcy

v0.0.4

Published

**funcy** provides a simple, strongly typed, and comprehensive toolkit for AWS lambda.

Downloads

6

Readme

NOTE funcy is in pre-release. We will attempt to keep the API as-is, however there may be breaking changes during this period.

funcy

Introduction

funcy provides a TypeScript-first (fully typed), best practice & simple functional interface for AWS lambda functions. The perfect complement to serverless frameworks such as the serverless, SST, SAM, etc.

Features:

  • Strongly typed request and response models (inferred or explicit)
  • Best practices pipeline with sensible defaults for CORS, security headers, encoding, error handling, metrics, logging, and profiling out of the box.
  • A fully-configurable and batteries-included interface; everything you need is an ctrl+space away.

If you prefer lightweight lambda functions and don't want a full-blown framework (like NestJS), then this is for you.

Preview

The example below shows parsing, validating and inferring a strongly-typed model for both request and response.

import { api, res } from '@refactorthis/funcy'
import { CreateCustomerRequest, CreateCustomerResponse } from './dtos'

// create customer handler
export const create = api({
  parser: {
    request: CreateCustomerRequest, // zod or yup schema
    response: CreateCustomerResponse, // zod or yup schema
  },
  handler: async ({ request }) = {
    const response = await Customer.create(request)
    return res.ok(response)
  }
})

You'll notice that the handler itself does not contain any parsing, validation or error handling logic, we adhere to the single-responsibility-principle here and handle all other aspects in middleware, configurable at either api or handler level.

example image

As you can see above, the TypeScript type is inferred at compile time, allowing strong typing of all request and response parameters to your API, almost by magic.

funcy also has a full middleware pipeline, allowing you to control things like CORS, content negotiation, encoding, security header best practices, etc. all out of the box. All you need to do is ctrl+space to see the options. Options can either be set as default for the whole api, or overridden for each handler

example image

Getting Started

Installation

pnpm add @refactorthis/funcy
#bun add @refactorthis/funcy
#yarn add @refactorthis/funcy
#npm install --save @refactorthis/funcy

If you haven't already installed your validation framework, add one to your package.

pnpm add zod
# or
# pnpm add yup

Writing funcy Functions

To get started let's create a simple API Gateway Proxy (HTTP or REST) lambda handler. This will validate the request and the response with our predefined zod schemas.

import { api, res } from '@refactorthis/funcy'
import { MyRequest, MyResponse } from './dtos'

export const handler = api({
  parser: {
    request: MyRequest, // zod or yup schema
    response: MyResponse, // zod or yup schema
  },
  handler: async({ request }) = {
    // request is the strongly typed request body
    // response is also validated and strongly typed
    return res.ok(response)
  }
})

You can create your own api handlers using api-level defaults. For instance, let's use a custom authorizer context, with strongly typed claims, for use across all of our api.

// my-api.ts
import { createApi } from '@refactorthis/funcy'

// my authorizer struct
interface AuthorizerType {
  jwt: { claims: { tenantId: 'string' } }
}

// Create this once for your API and share it
// We will set the authorizer to use, and allow a cross-origin domain
export const api = createApi<AuthorizerType>({
  http: { cors: { origin: 'web.mydomain.com' } },
})
// customers-create.ts
import { res } from '@refactorthis/funcy'
import { api } from './my-api'

export const handler = api({
  parser: {
    request: MyRequestSchema,
    response: MyResponseSchema,
    path: PathSchema,
    query: QueryStringSchema,
  },
  handler: async({ request, path, query, authorizer }) = {
    // request is the strongly typed request body
    // path is the strongly typed url path
    // query is the strongly typed query string
    // authorizer is the strongly typed authorizer context as specified in my-api.ts
    // responseType is the strongly typed response type
    return res.ok(responseType)
  }
})

All handlers using this api will return the appropriate CORS headers, as specified.

Examples

Let's create CRUD handlers for the "Customer" domain, with request validation.

import { api, res } from '@refactorthis/funcy'

// create
export const handler = api({
  parser: {
    request: CreateCustomerRequest,
    response: CreateCustomerResponse,
  },
  handler: async ({ request }) = {
    const response = await Customers.create(request)
    return res.created(response)
  }
})

// get
export const handler = api({
  parser: {
    path: GetResourcePath,
    response: GetCustomerResponse,
  },
  handler: async ({ request, path }) = {
    const response = await Customers.get(path.id)
    return res.ok(response)
  }
})

// list
export const handler = api({
  parser: {
    query: ListQueryStringValidator,
  },
  handler: async ({ request, query }) = {
    const { skip, take } = query
    const items = await Customers.list(skip, take)
    return res.ok({ items, skip, take })
  }
})

// update
export const handler = api({
  parser: {
    request: UpdateCustomerRequest,
    response: UpdateCustomerResponse,
    path: GetResourcePath,
  },
  handler: async ({ request, path }) = {
    const response = await Customers.update(path.id, request)
    return res.ok(response)
  }
})

Schema Parsing Support

funcy is built to be agnostic of schema library. At this time funcy supports:

Performance Comparisons

funcy Nest.js Express Koa

Roadmap

  • Support for other schema libraries
  • Verify support for legacy API Gateway proxy integration (< v2)
  • Performance test comparison with nest.js, raw lambda, etc.
  • Other lambda integrations (s3, dynamo, etc)
  • hateoas middleware
  • router middleware for proxy+ calls

See Also

Complementary Packages

Working with zod:

  • zod - a great Typescript-first validation framework, which can infer your DTO types automatically
  • zod-to-openapi - generate your Open API definition code-first from zod schemas.
  • openapi-zod-client - alternatively, generate your code from your design-first Open API definition

Working with yup:

Acknowledgements

  • middy.js - powers the funcy pipeline with it's extensible middleware framework.
  • TypeScript - strong-typing is critical for maintainability and reducing bugs.