New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@wooksjs/event-http

Package Overview
Dependencies
Maintainers
1
Versions
97
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wooksjs/event-http

@wooksjs/event-http

  • 0.2.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
108
increased by40.26%
Maintainers
1
Weekly downloads
 
Created
Source

@wooksjs/event-http

!!! This is work-in-progress library, breaking changes are expected !!!


As a part of wooks event processing framework, @wooksjs/event-http implements http events and provides composables that let you:

  • parse urls search params
  • parse cookies
  • parse request body (json, url-encoded, form, ...)
  • serve files

The main ideas behind composable functions are:

  1. Never mutate request object (req). Accumulate a request context in a separate object(s) instead (wooks store);
  2. Never parse anything (cookies, body) before it is really requested by the request handler;
  3. Get rid of complex predefined data objects containing everything (cookies, headers, body, parsed body etc.) and use composable functions (hooks) instead;
  4. Get rid of tons of dependencies (middlewares) and implement everything that is needed for web app in a simple way.

Official Wooks HTTP composables:

Install

npm install wooks @wooksjs/event-http

Quick Start

import { useRouteParams } from 'wooks'
import { createHttpApp } from '@wooksjs/event-http'

const app = createHttpApp()

app.on('GET', 'hello/:name', () => `Hello ${ useRouteParams().get('name') }!`)

// shortcuts for some methods are supported:
// app.get('hello/:name', () => `Hello ${ useRouteParams().get('name') }!`)

app.listen(3000, () => { console.log('Wooks Server is up on port 3000') })

Get More Control on Server

You can create http(s) server manually and pass server callback from the wooks http app:

import { useRouteParams } from 'wooks'
import { createHttpApp } from '@wooksjs/event-http'
import http from 'http' // or https

const app = createHttpApp()

app.get('hello/:name', () => `Hello ${ useRouteParams().get('name') }!`)

const server = http.createServer(app.getServerCb())
server.listen(3000, () => { console.log('Wooks Server is up on port 3000') })

Quick Navigation





User Documentation

URL Parameters

To get access to URL parameters use composable function useRouteParams

import { useRouteParams } from 'wooks'
app.get('parametric/:param1/:param2/...', () => {
    const { params, get } = useRouteParams()
    // presume we had a request on `/parametric/value1/value2`
    console.log('param1=' + get('param1'))
    // prints "param1=value1"
    console.log('param2=' + get('param2'))
    // prints "param2=value2"
    console.log(params)
    // prints {
    //   param1: "value1",
    //   param2: "value2" 
    // }
})

Query Parameters

To get access to Query parameters use composable function useSearchParams

import { useSearchParams } from '@wooksjs/event-http'
app.get('with-query', () => {
    const { jsonSearchParams, urlSearchParams } = useSearchParams()
    // presume we had a request on `/with-query?param1=abc&param2=cde`
    console.log('param1=' + urlSearchParams('param1'))
    // prints "param1=abc"
    console.log('param2=' + urlSearchParams('param2'))
    // prints "param1=cde"
    console.log(jsonSearchParams)
    // prints {
    //   param1: "abc",
    //   param2: "cde"   
    // }
})

Request

To get a reference to the raw request instance use composable function useRequest

You probably don't need a rawRequest unless you are developing some new feature. All the base use-cases covered with other composable functions.

import { useRequest } from '@wooksjs/event-http'
app.get('test', () => {
    const { rawRequest } = useRequest()
})

Request Method and Headers

useRequest provides some more shortcuts for useful data

import { useRequest } from '@wooksjs/event-http'
app.get('test', async () => {
    const { 
        url,        // request url      (string) 
        method,     // request method   (string)
        headers,    // request headers  (object)
        rawBody,    // request body     ((): Promise<Buffer>)
    } = useRequest()

    const body = await rawBody() // body as a Buffer
})

Request Cookies

Cookies are not parsed unless requested. Composable function useCookies provides cookie getter and raw cookies string.

import { useCookies } from '@wooksjs/event-http'
app.get('test', async () => {
    const { 
        rawCookies, // "cookie" from headers (string | undefined)
        getCookie,  // cookie getter ((name): string | null)
    } = useCookies()

    console.log(getCookie('session'))
    // prints the value of the cookie with the name "session"
})

Request Authorization

useAuthorization function provides useful helpers for auth-headers:

import { useAuthorization } from '@wooksjs/event-http'
app.get('test', async () => {
    const {
        authorization,      // the raw value of "authorization" header : string
        authType,           // the auth type (Bearer/Basic) : string
        authRawCredentials, // the auth credentials that follow auth type : string
        isBasic,            // true if authType === 'Basic' : () => boolean
        isBearer,           // true if authType === 'Bearer' : () => boolean
        basicCredentials,   // parsed basic auth credentials : () => { username: string, password: string }
    } = useAuthorization()

    if (isBasic()) {
        const { username, password } = basicCredentials()
        console.log({ username, password })
    } else if (isBearer()) {
        const token = authRawCredentials
        console.log({ token })
    } else {
        // unknown or empty authorization header
    }
})

Request Body Parser

More details here

Response

The easiest way to respond to the request is to return some value from handler function like this:

app.get('string_response', () => {
    return 'hello world!'
    // responds with:
    // 200
    // Content-Length: ...
    // Content-Type: text/plain
    // hello world!
})

Whatever is returned from the handler is the response. Content-Type and Content-Length headers will be calculated accordingly.

If a handler returns a json object, it will be stringified and the header Content-Type will be set to application/json automatically:

app.get('json_response', () => {
    return { value: 'hello world!' }
    // responds with:
    // 200
    // Content-Length: ...
    // Content-Type: application/json
    // { "value": "hello world!" }
})

Supported response types:

  1. string (text/plain, text/html, application/xml - depending on the content)
  2. object/array (application/json)
  3. boolean (text/plain)
  4. readable stream (you must specify Content-Type and Content-Length headers yourself)
  5. fetch (native) response (streaming body to client response)

Raw Response: When it is needed to take the full control of the response, use composable function useResponse

When you get a raw response instance you take away the control of the response on yourself. The framework will not process the output of the handler in this case.

An example of using raw response instance:

import { useResponse } from '@wooksjs/event-http'
app.get('test', () => {
    const { rawResponse } = useResponse()
    const res = rawResponse()
    res.writeHead(200, {})
    res.end('ok')
})

If you don't want to take away a responsibility for the response but still need a raw response instance you can use { passthrough: true } as an argument. The next example does the same thing as the previous example using passthrough options:

import { useResponse } from '@wooksjs/event-http'
app.get('test', () => {
    const { rawResponse } = useResponse()
    const res = rawResponse({ passthrough: true })
    return 'ok'
})

Response Headers

A function useSetHeaders provides variety of response headers helpers:

import { useSetHeaders, contentTypes } from '@wooksjs/event-http'
app.get('test', async () => {
    const {
        setHeader,      //sets header: (name: string, value: string | number) => void;
        removeHeader,   //removes header: (name: string) => void;
        setContentType, //sets "Content-Type": (value: string) => void;
        headers,        //Object with response headers: Record<string, string>;
        enableCors,     //sets "Access-Control-Allow-Origin": (origin?: string) => void;
    } = useSetHeaders()

    setContentType(contentTypes.application.json)
    setHeader('server', 'myServer v1.0')
    enableCors()
    return '{ "value": "OK" }'
})

Another hook for set header

import { useSetHeader } from '@wooksjs/event-http'
app.get('test', async () => {
    const server = useSetHeader('server')
    server.value = 'myServer v1.0'
})

Response Cookies

A function useSetCookies provides variety of set-cookie helpers:

import { useSetCookies } from '@wooksjs/event-http'
app.get('test', async () => {
    const {
        setCookie,      // sets cookie : (name: string, value: string, attrs?) => void;
        removeCookie,   // removes cookie from setlist : (name: string) => void;
        clearCookies,   // removes all the cookies from setlist : () => void;
        cookies,        // returns a value of Set-Cookie header: () => string[];
    } = useSetCookies()

    setCookie('session', 'value', {
        expires: '2029-01-01',  // Date | string | number;
        maxAge:  '1h',          // number | TProstoTimeMultiString;
        domain:  'my-domain',   // string;
        path:    '/home',       // string;
        secure:   true,         // boolean;
        httpOnly: false,        // boolean;
        sameSite: true,         // boolean | 'Lax' | 'None' | 'Strict';
    })
})

Another hook for set-cookie

import { useSetCookie } from '@wooksjs/event-http'
app.get('test', async () => {
    const session = useSetCookie('session')
    session.value = 'value'
    session.attrs = {
        expires: '2029-01-01',  // Date | string | number;
        maxAge:  '1h',          // number | TProstoTimeMultiString;
        domain:  'my-domain',   // string;
        path:    '/home',       // string;
        secure:   true,         // boolean;
        httpOnly: false,        // boolean;
        sameSite: true,         // boolean | 'Lax' | 'None' | 'Strict';        
    }
})

Response Status

It's possible to control the response status via status function that is available in useResponse()

import { useResponse } from '@wooksjs/event-http'
app.get('test', async () => {
    const { status } = useResponse()

    // use function calls:
    status(201) // sets status 201 for the response

    console.log(status()) // when called with no argument returns the status

    // also possible to use value:
    // status.value = 201
    // console.log(status.value)

    return 'response with status 201'
})

Cache-Control

useSetCacheControl function provides helpers for headers responsible for cache control

import { useSetCacheControl } from '@wooksjs/event-http'
app.get('static/*', () => {
    const { 
        setAge,             // sets Age (v: number | TProstoTimeMultiString) => void
        setExpires,         // sets Expires (v: Date | string | number) => void
        setPragmaNoCache,   // sets Pragma: no-cache (v: boolean) => void
        setCacheControl,    // sets Cache-Control (data: TCacheControl) => void
    } = useSetCacheControl()

    setAge('2h 15m')
    setExpires('2022-05-05')
    setCacheControl({
        mustRevalidate: true,
        noCache: false,
        noStore: false,
        noTransform: true,
        public: true,
        private: 'field',
        proxyRevalidate: true,
        maxAge: '3h 30m 12s',
        sMaxage: '2h 27m 54s',
    })
})

Proxy Requests

More details here

Serve File

More details here

Create you own hooks

As an example we'll create a composable that resolves user profile

import { useAuthorization, useHttpContext } from '@wooksjs/event-http'

interface TUser {
    username: string
    age: number
    // ...
}

export function useUserProfile() {
    // 1. get custom-typed context
    const { store } = useHttpContext<{ user: TUser }>()
    const user = store('user')

    // 2. in this example will use basic credentials approach to get user name
    const { basicCredentials } = useAuthorization()

    // 3. get user name
    const username = basicCredentials()?.username

    // 4. user data async loader
    async function userProfile() {
        // first check if user data was already cached
        // for this request
        if (!user.value) {
            // no user data cached yet, try to read user
            // and return the result
            user.value = await readUser()
        }
        // return user profile from cache
        return user.value
    }

    // abstract readUser function
    function readUser(): Promise<TUser> {
        // return db.readUser(username)
    }    

    return {
        username, // we have user name syncronously
        userProfile, // and userProfile as (() => Promise<TUser>)
    }
}

// example of usage of our useUserProfile
app.get('/user', async () => {
    const { username, userProfile } = useUserProfile()
    console.log('username =', username)
    const data = await userProfile()
    return { user: data }
})

Example of custom set header hook

import { useSetHeaders } from '@wooksjs/event-http'
import { attachHook } from '@wooksjs/event-core'

function useHeaderHook(name: string) {
    const { setHeader, headers } = useSetHeaders()

    return attachHook({
        name,
        type: 'header',
    }, {
        get: () => headers()[name] as string,
        set: (value: string | number) => setHeader(name, value),
    })
}

// usage

app.get('/test', () => {
    const myHeader = useHeaderHook('x-my-header')
    myHeader.value = 'header value'
    // *Please note that useSetHeader('x-my-header') will work similarly*
    return 'ok'
})

// result:
// 200
// headers:
// x-my-header: header value

Adapter Documentation

The next paragraph is for those who wants to create threir own adapter and get more control over the wooks.

Create a new wooks context

Wooks context is a special object that stores:

  1. instance of request - is used to get data from request
  2. instance of response - is used to send a response
  3. parsed route params - usually Web App frameworks put it to req (req.params)
  4. cache store - is used to cache alread computed values, e.g. parsed body, parsed cookies, ..., in order to avoid multiple parsing/computetaion of the same entities.

When request is generated by the client a new Wooks context must be created.

const {restoreCtx, clearCtx} = createHttpContext({ req, res })

import { createHttpContext } from '@wooksjs/event-http'

function requestHandler(req, res) {
    const {
        // restoreCtx hook helps to restore wooks context
        // after any async operatuon
        restoreCtx,

        // clearCtx hook helps to clear wooks context
        // when the request is already processed
        clearCtx,

        // store hook to access wooks store of the current ctx
        store,
    } = createHttpContext({
        // request instance
        req,
        // response instance
        res,
    })

    // if req already contains parsed params (req.params)
    // then those will be picked up automatically
    // unless you overwrite it here
    store('routeParams').value = { name: 'value' }
}

Create a responder

Responder is a function that takes any output of the request handler and transforms it into http response, processing headers, cookies, formats etc.

const {createResponse, respond} = createWooksResponder()

import { createWooksResponder, createHttpContext } from '@wooksjs/event-http'

const {createResponse, respond} = createWooksResponder(
    /*renderer, // (optional) instance of TWooksResponseRenderer*/
    /*errorRenderer, // (optional) instance of TWooksResponseRenderer*/
)

async function requestHandler(req, res) {
    // 1. create wooks context
    const {restoreCtx, clearCtx} = createHttpContext({ req, res })
    // 2. process request based on routers/handlers and get the output
    const response = await createHttpContext()
    // 3. restore wooks context
    restoreCtx()
    // 4. respond
    respond(response)
    // 5. clear wooks context
    clearCtx()
}

async function processHandlers() {
    // routing, processing, handling, ...
}

Restore Context

There is one more way to get restoreCtx hook besides the one you get when createHttpContext

const { restoreCtx, clearCtx } = useHttpContext()

import { useHttpContext } from '@wooksjs/event-http'

async function someHandler() {
    const { restoreCtx, clearCtx } = useHttpContext()
    await ... // some async operations
    restoreCtx()
    // here the wooks context is back
}

Keywords

FAQs

Package last updated on 22 Dec 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc