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

@nerding_it/espresso

v1.3.8

Published

The minimal router for cloudflare workers

Downloads

46

Readme

Espresso

Espresso is a minimal and lightweight router for cloudflare workers without any dependency. It utilizes URLPattern to perform routing. It provides two methods before and after for applying middleware both before and after processing the request (i.e. The request processing from handler). It implements all http methods described here MDN HTTP Methods (i.e head, get, post, put, patch, delete, connect, trace, options) are supported.

Along with routing, this library provides a optional feature to execute callback for a cron expression. For example say one have use case to execute a task every hour and another task which requires to be executed on start of month. Since cloudflare ScheduleEvent provides a property called cron which will have the source of event trigger. This gives a flexibility to perform dynamic operation with respect to cron expressions

Why Espresso

  • 🛫 Easy to get started
  • 🧳 Zero dependency, it doesn't use any external library
  • 🍔 Easy to customize and extend
  • 🕐 Bind callbacks for different cron expressions

Usage

import espresso, { ServerError } from '@nerding_it/espresso';

const logger = (message) => {
  console.log(message)
}

espresso
  .cors({})
  .setDebug()                   // NOTE: For development purpose
  .before(async (request) => {
    logger('Request URL logging middleware')
    logger(`Requested URL: ${request.url}`)
  })
  .before(async (request, env) => {
    logger('Log environment variable middleware')
    logger(`Environment variables ${JSON.stringify(env)}`)
  })
  // Auth middle warey
  .before( async () => {
    // Throw error like this with custom http status, Say if user is not authorized to access
    // throw new ServerError('Invalid authorization', 401)
  })
  .after((response) => {
    logger('Response status code logging middleware')
    logger(`Response status: ${response.status}`)
  })
  .after((response, env, context) => {
    logger('Caching middleware')
  })
  .after((response, env, context) => {
    logger('Cleanup middleware')
  })
  .head('/', async () => {
    return {
      status: 200,
      body: {message: 'I am head'}
    }     
  })
  .get('/', async () => {
    return {
      status: 200,
      body: {message: 'I am get'}
    }     
  })
  .post('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am post'}
    }
  })
  .put('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am put'}
    }
  })
  .patch('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am patch'}
    }
  })
  .delete('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am delete'}
    }
  })
  .options('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am options'}
    }
  })
  .connect('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am connect'}
    }
  })
  .trace('/', async (request) => {
    return {
      status: 200,
      body: { message: 'I am trace'}
    }
  })
  .get('/:name', async (request) => {
    return {
      status: 200,
      body: {message: `Hello ${request.params.get('name')}`}
    }
  })
  // When you pass query params in the url like ?query=How are you
  // Pass headers in the response
  .get('/:name/:country', async (request) => {
    return {
      status: 200,
      body: {message: `Hello ${request.params.get('name')} from ${request.params.get('country')}, your query is ${request.query.get('query')}`},
      headers: {
        'Cache-Control': 'no-cache'
      }
    }    
  })
  .patch('/:id', async (request) => {
    // Throw an error
    throw new ServerError('Bad request', 400)
  })
  .schedule('* * * * *', async (env) => {
    // Run some task every minutes
  })
  .schedule('*/30 * * * *', async (env) => {
    // Run some task every 30 minutes
  })
  .brew()

Running app locally or publish to cloudflare

You have to use cloudflare wrangler to run application locally, Just invoke wrangler dev to start local instance of the application, Or use wrangler publish to publish into cloudflare edge servers

Reference

  • cors Enable cors, Optionally pass parameters to override default values for cors header. Below is the example

    const config = {
      allowOrigin: 'http://localhost:3000, http://localhost:3001',
      allowMethods: 'GET, POST',
      allowHeaders: 'Authorization, Content-Type'
    }
    espresso.cors(config)
  • head Register a handler for http head method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .head('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        return {
          status: 200,
          body: {message: 'I am http head method'}
        }     
      })
  • options Register a handler for http options method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .options('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        return {
          status: 200,
          body: {message: 'I am http options method'}
        }     
      })
  • get Register a handler for http get method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .get('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        return {
          status: 200,
          body: {message: 'I am http get method'}
        }     
      })
  • post Register a handler for http post method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .post('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        // Use request.body to use post body
        return {
          status: 200,
          body: {message: 'I am http post method'}
        }     
      })
  • put Register a handler for http put method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .put('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        // Use request.body to use put body
        return {
          status: 200,
          body: {message: 'I am http put method'}
        }     
      })
  • patch Register a handler for http patch method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .patch('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        // Use request.body to use patch body
        return {
          status: 200,
          body: {message: 'I am http patch method'}
        }     
      })
  • delete Register a handler for http delete method, Below is the example

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .delete('/', async (request, env) => {
        // Do something with request
        // Use environment variables
        // Return the status code and body
        return {
          status: 200,
          body: {message: 'I am http delete method'}
        }     
      })
  • before Register a response middleware, Below is the example which transforms request body

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .before('/', async (request, env) => {
        if (request.headers.get('content-type').toLowerCase() === 'application/json' || request.headers.get('content-type').toLowerCase() === 'application/json;utf-8') {
          request.body = await request.json()
        }
      })
  • after Register a response middleware, Below is the example which writes data into KV

    import espresso from '@nerding_it/espresso';
    
    espresso()
      .after('/', async (response, env, context) => {
        const clone = response.clone()
        // Write response url and response status to KV
        context.waitUntil(env.KV.put(clone.url, clone.status))
      })
  • schedule Register a schedule event handler, It takes cron expression and a call back. Below is a example which register a callback for cron expression * * * * * (i.e. Every minute). And another callback which calls when cron expression is */2 * * * * (i.e. Every two minute). In this way you can perform different operations for different cron triggers. Read more about Cron Triggers. To make it work you need to configure cron triggers with respected expression for your worker

    import espresso from '@nerding_it/espresso';
    
      espresso()
      .schedule('* * * * *', async (env) => {
        console.debug('I write message to console every minute')
      })
      .schedule('*/2 * * * *', async (env) => {
        console.debug('I write message to console every two minute')
      })
      .brew()
  • brew This wraps router instance inside FetchEvent and optionally ScheduleEvent (NOTE: It adds ScheduleEvent only if you call schedule). For example it adds ScheduleEvent for below code

    import espresso from '@nerding_it/espresso';
    
    espresso
      // If it's triggered by this cron string
      .schedule("* * * * *", async (env) => {
        // List keys
        const { keys } = await env.KV.list()
      })
      .brew()
  • setDebug Enable debugging (i.e. console messages)

    import espresso from '@nerding_it/espresso';
    
    espresso
      .setDebug()
      .brew()

Enable cors with custom settings

You have to pass custom parameters to cors method as mentioned below,

const config = {
  allowOrigin: '*',             // For example 'http://localhost:3000, https://localhost:3001'
  allowMethods: '*',            // For example 'GET, POST'
  allowHeaders: '*'             // For example 'Authorization, Content-Type'
}

// Then pass into cors
espresso.cors(config)
// Rest of the code

FAQ

How do I have to access path parameters, For example I have route like this /user/:id

request.params is a map with parameter name as key, Just use request.params.get('id') to access id

How do I have to access query parameters, For example I have route like this /user?text=web

request.query is a map with parameter name as key, Just use request.query.get('text') to access text

How to perform non blocking task in after middleware?

Middlewares get context object, It'll have waitUntil method. Utilize it to perform operations async. This is useful for caching etc.