@nerding_it/espresso

1.3.8 • Public • Published

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.

Readme

Keywords

none

Package Sidebar

Install

npm i @nerding_it/espresso

Weekly Downloads

41

Version

1.3.8

License

WTF

Unpacked Size

39.3 kB

Total Files

5

Last publish

Collaborators

  • nerding_it