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

micro-azure-functions

v0.1.1

Published

<img src='https://github.com/Albert-Gao/micro-azure-functions/blob/master/logo.png?raw=true' maxWidth="100%" height='auto' />

Downloads

6

Readme

Micro Azure Functions

Intro

  • Decouple business logic into reusable functions
  • Written in Typescript
  • Zero runtime dependencies
  • Tiny: 5KB after minified
  • Rapid middlewares
    • simple reasoning, just running one by one
    • early exit with just throw httpError() or anything or context.done()
    • pass values among middlewares
  • Easy debug:
    • log request or any error by just turning one config

Why do you build this lib

Azure functions is making it a flash to creating an API endpoint. But that's just the infrastructure part. It doesn't mean your business logic can be simplified.

  • I need a middleware setup to decouple my business logic without installing a lib that has many dependencies and result in a bigger bundle size as well.
  • I want to deal with a simple interface, where the order is just one by one. I don't want to deal with a mental model where a middleware will be invoked twice for both stages, and handle both the before and after stage in one function.

What problems does it solve

Middleware is for decoupling logic. I learned the value of beforeHooks and afterHooks after adopting Feathers.JS. Which has a beautiful concept of 3 layers for every endpoint, and I found myself start the declarative programming for the backend. No more code for the repeating work. In micro-azure-functions's context, it is just an array of Middleware.

Let's say a simple return-a-user endpoint, what does it look like when you are using micro-azure-functions

import { azureFunctions } from 'micro-azure-functions';

const handler = azureFunctions([
  validateRequestBody(GetUserSchema),
  isStillEmployed,
  verifyPaymentStatus,
  justReturnUserObjectDirectlyFromDB,
  removeFieldsFromResponse('password', 'address'),
  combineUserNames,
  transformResponseToClientSideStructure,
]);

Ideally, you can just compose your future Azure functions without writing any code except for an integration test. The logic will be declarative. Every middleware here can be fully tested and ready to reuse.

Usage

1. Install

npm install micro-azure-functions

2. Quick start

import { azureFunctions } from 'micro-azure-functions';

const handler = azureFunctions([
  context => {
    context.res = { status: 200, body: { message: 'it works' } };
  },
]);

// call the API, you will get json response: { message: "it works" }

3. The type of the middleware

export type Middleware<PassDownObjType = any> = (
  context: MiddlewareContext<PassDownObjType>,
  ...args: any[]
) => Promise<void> | void;

This is 99.999% identical with the AzureFunctions type from @azure/functions, but one thing, it appends a new property to Context named passDownObj, which is used to shared value among middlewares.

4. Two minutes master

  • How to control the flow?

    • context.done will STOP the execution
    • throw will STOP the execution
    • otherwise, the array of Middleware will just be executed one by one
  • How can I return

    • You just use the Azure way, setup context.res
    • we have some handy method for you like success(), badRequest(), internalRequest(), so you can do context.res = success(), just setup the statusCode for you
    • or a success() (just a httpResponse() with status code set to 200, you can still change it)
  • What can you throw

    • an httpError()
    • an badRequest()
    • an internalError()
    • or anything else
    • any un-caught exception will be caught at the very top level, and return with 500
  • How to check what will be returned as the Http response

    • just check the context.res
  • How to change the response

    • you just update context.res
  • How to pass something down the chain,

    • use context.passDownObj
    • attach your value to it: context.passDownObj.myValue = 123, myValue could be any name

5. About the built-in responses

There are 2 types of response:

Built in

  • httpError() for throw
  • httpResponse() for return
  • success()
  • badRequest()
  • internalRequest()

Plain JS type

  • throw a plain object | string | number === (400) response
  • custom status code by adding statusCode property

The built-in one has some shortcuts to use.

All parameters are customizable.

import { httpError, httpResponse } from 'micro-azure-functions';

// It gives you an instance of HttpError, which extends from Error
const error = httpError({
  // default status code is 400 if not set
  status: 401,
  body: {
    message: 'test',
  },
  headers: {
    'x-http-header': 'fake-header',
  },
});

// It gives you a plain JS object.
const response = httpResponse({
  // default status code is 200 if not set
  status: 200,
  body: {
    message: 'test',
  },
  headers: {
    'x-http-header': 'fake-header',
  },
});

The commons headers are:

  • 'Access-Control-Allow-Origin': '*',
  • 'Access-Control-Allow-Credentials': true,
  • 'Content-Type': 'application/json',

5.1. Shortcuts

Compare to the above methods, the only difference is the shortcuts just sets the status code, you can still modify them if you want.

  • httpError:
    • badRequest(): 400
    • internalRequest(): 500
  • httpResponse:
    • success(): 200

6. Config

6.1 logError

It will context.log any error caught at the very top level

azureFunctions([], { logError: true });

6.2 logRequest

It will context.log context.req:

azureFunctions([], { logRequest: true });

7. Examples

7.1 Validation

In the following case, if the request name is 'albert', only validateRequest will be called.

import { badRequest, Middleware } from 'micro-azure-functions';

const validateRequest: Middleware = (context, req) => {
  if (req.body.name === 'albert') {
    throw badRequest({
      message: 'bad user, bye bye',
    });
  }
};

// it will return a 400 error { message: 'bad user, bye bye' }

Or if you like me, you can write a simple validating middleware with the yup schema, you can then reuse from the client side.

import { Schema } from 'yup';
import { azureFunctions, Middleware, badRequest } from 'micro-azure-functions';

const validateBodyWithYupSchema = (schema: Schema): Middleware => async ({
  event,
}) => {
  if (!schema.isValid(event.body)) {
    throw badRequest('bad request');
  }
};

const handler = azureFunctions([validateBodyWithYupSchema(myYupSchema)]);

7.2 processing Response

import { badRequest } from 'micro-azure-functions';

const removeFieldsFromResponse = (fieldsToRemove: string[]): Middleware = (context) => {
    const newResponse = Object.assign({}, response);

    fieldsToRemove.forEach(field => {
      if (context.res[field] != null) {
        delete context.res[field]
      }
    })

    return newResponse;
};

const testHandler = azureFunctions(
  [
    (context) => {
      context.res = {
        status: 200,
        body: {
          name: 'albert',
          password: '123qwe',
          address: 'somewhere on earth'
        }
      }
    },
    removeFieldsFromResponse(['password', 'address'])
   ],
);

// response will be  { name: 'albert' }

Credits

  • The initial version is heavily inspired by my favourite REST framework: Feathers.JS
  • This project was bootstrapped with TSDX.