Fast, Bun-powered, and Bun-only(for now) Web API framework with full Typescript support.

Overview

Zarf

Fast, Bun-powered, and Bun-only(for now) Web API framework with full Typescript support.

Quickstart

Starting with Zarf is as simple as instantiating the Zarf class, attaching route handlers and finally starting the server

import { Zarf } from "@zarfjs/zarf"

const app = new Zarf()

app.get("/hello", (ctx) => {
    return ctx.json({
        hello: "hello"
    })
})

app.get("/", (ctx) => {
    return ctx.html(`Welcome to Zarf App server`)
})

app.listen({
    port: 3000
}, (server) => {
    console.log(`Server started on ${server.port}`)
})

App and Routing

Routes are how you tell where/when/what to respond when somebody visits your app's URLs, and @zarfjs/zarf lets you easily register routes, with all the commonly used HTTP verbs like GET, POST, PUT, DELETE, etc.

Here's how you'd define your app routes -

// GET
app.get("/posts", (ctx) => {
    return ctx.json({
        posts: [/* all of the posts */]
    })
})

// POST
app.post("/posts", async(ctx) => {
    const { request } = ctx
    const body = await request?.json()
    // ... validate the post body
    // ... create a post entry
    return ctx.json(body)
})

// PUT
app.put("/posts/:id", async(ctx, params) => {
    const { request } = ctx
    const id = params.id
    const body = await request?.json()
    // ... validate the post body
    // ... upadte the post entry
    return ctx.json(body)
})

// DELETE
app.del("/posts/:id", async(ctx, params) => {
    const id = params.id
    // ... validate the del op
    // ... delete the post entry
    return ctx.json({ deleted: 1 })
})

Routing: Context

Context available as the first argument to your route handlers is a special object made available to all the route handlers which

  • lets you access vaious details w.r.t Request object
  • provides convenience methods like json, text, html to send Response to the client

The most accessed/useful object could be the Request object itself(available at ctx.request), but it offers few other methods too

  • setHeader
  • setType
  • setVary
  • isType
  • accepts to determine things about the current request, or change few things about the response that's send to the client.

Routing: Params

Params is the second argument available to your route handlers, that lets you access the route parameters easily.

app.get("/products/:id", (ctx, params) => {
    // params.id ? //
    // Pull the details
    return ctx.json({
        product: {/* all of the posts */}
    })
})

@zarfjs/zarf supports all the common URL patterns you'd expect in a Web-App/API framework

app.get("/user/:name/books/:title", (ctx, params) => {
    const { name, title } = params
    return ctx.json({
        name,
        title
    })
})

app.get("/user/:name?", (ctx, params) => {
    return ctx.json({
        name: params.name || 'No name found'
    })
})

// /admin/feature/path/goes/here
app.get("/admin/*all", (ctx, params) => {
    return ctx.json({
        supPath: params.all // -> /feature/path/goes/here
    })
})

// /v1/nike/shop/uk
// /v1/nike/uk/shop/shop-at...
app.get("/v1/*brand/shop/*name", (ctx, params) => {
    return ctx.json({
        params // -> { brand: 'nike', ...},  { brand: 'nike/uk', ...}
    })
})

RoadMap

A lot of great stuff is actually planned for the project. The Alpha version is majorly focussing on making the core stable and provide all the essential features. Here's snapshot of the roadmap.(private)

Zarf Roadmap

Meta

The project is developed on

  • OS - MacOS Monterey
  • Bun - v0.1.13
Comments
  • Framework: Route Naming/Aliasing

    Framework: Route Naming/Aliasing

    It would be good to have an internal route naming convention, and a way for the framework users to provide a route name alias for quick route recalls in debugging, testing, etc.

    The routes will internally follow a convention of naming registered routes as

    /hello/:user -> hello__user /user/:name/books/:title -> user__name_books__title

    We can have a utility method like path that can return the actual path registered for a given route name

    app.path('hello__user') // returns '/hello/:user'
    app.path('user__name_books__title') // returns '/user/:name/books/:title'
    

    The registered route names can have a user provided alias. For example, a user can declare a route name alias as

    app.get("/", (ctx) => {
        return ctx.html(`Welcome to Zarf App server`)
    })
    app.as('home') // immediately following the call
    

    and can get the path of the route

    app.path('home') // returns '/'
    
    opened by one-aalam 0
  • Core: Create `Response` creator utility

    Core: Create `Response` creator utility

    Create a generic utilities to build Responses with provided status and status code

    • [x] createResp
    • [x] createRedirect
    • [x] createUnauthorized
    • [x] createNotModified

    plus, expose a bunch of specific response creators for popular responses.

    opened by one-aalam 0
  • Core: Go Zero-Dep

    Core: Go Zero-Dep

    Currently, the only dependency this project is having is a mime-type library that seems a bit big, and incompatible to be ported across multiple platforms.

    Have a native version, to go fully Zero Dep!

    opened by one-aalam 0
  • Middleware: Uploads

    Middleware: Uploads

    A middleware that reads form data parsed by body-parser and saves the binary file to the disk (an app local /uploads folder)

    Example

    import { BunTea } from 'bun-tea'
    import { bodyParser } from 'bun-tea/dist/mw/body-parser'
    import { uploads } from 'bun-tea/dist/mw/uploads'
    
    const app = new BunTea()
    
    app.post("/users", [ bodyParser({
        extensions: ['jpg', 'jpeg'],
        maxFileSizeBytes: 3_4000,
        maxSizeBytes: 5_6000
    }), uploads({
        useOriginalFileName: false,
        useLocals: true
    }) ], async (ctx) => {
        // your upload details here if `useLocals` is true
        // console.log(ctx.locals)
        return ctx.json({
            message: "users created",
        });
    })
    
    app.get("/", (ctx) => {
        return ctx.json({
          message: "Hello World! I'm ready to keep your uploads.",
        });
    })
    
    app.listen({
        port: 3000
    }, (server) => {
        console.log(`Server started on ${server.port}`)
    })
    
    opened by one-aalam 0
  • Build: Improve `imports` (or `exports`) for atomic imports from `Bun-Tea`

    Build: Improve `imports` (or `exports`) for atomic imports from `Bun-Tea`

    Currently, due to a certain a way the exports work, users of bun-tea have to do

    import { isObject } from 'bun-tea/dist/utils/is'
    import { parseQueryParams } from 'bun-tea/dist/parsers/qs'
    

    This shouldn't be either needed, or desirable. User's should be able to simply do

    import { isObject } from 'bun-tea/utils/is'
    import { parseQueryParams } from 'bun-tea/parsers/qs'
    

    Note: There's no functional code change between v0.0.1-alpha.7 and v0.0.1-alpha.11, and all releases were deployed just to verify the imports

    enhancement 
    opened by one-aalam 0
  • Middleware: CORS

    Middleware: CORS

    This middleware sets HTTP CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, etc.), necessary for making cross-origin requests

    API

    import { cors } from 'bun-tea/cors'
    

    cors(options)

    Returns the CORS middleware with applied options

    Options

    • origins: Configures an array of string for multiple origins or a single origin for the Access-Control-Allow-Origin CORS header, defaults to ['*']
    • methods: Configures the Access-Control-Allow-Methods CORS header, default to all the most common methods (GET, HEAD, PUT, PATCH, POST, DELETE)
    • allowedHeaders: configures the Access-Control-Allow-Headers CORS header (ex: ['Content-Type', 'Authorization']) when available
    • exposedHeaders: Configures the Access-Control-Expose-Headers CORS header. If not specified, no custom headers are exposed
    • credentials: Configures the Access-Control-Allow-Credentials CORS header. Passes the header only when the value true
    • maxAge: Configures the Access-Control-Max-Age CORS header. Passes the header only when available
    • vary: Configures the Vary header. The Vary header is always Origin when Access-Control-Allow-Origin CORS header is available, and is not equal to * **OPTIONS request specific
    • cacheControl: Configures the Access-Control-Max-Age CORS header. Passes the header only when available
    • preflightContinue: Set 204 and finish response if true, or continues with BAU otherwise for OPTIONS requests

    The default configuration is:

    {
        origins: ["*"],
        credentials: false,
        allowedHeaders: [],
        exposedHeaders: [],
        methods: [ "GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"  ],
        preflightContinue: false
    }
    

    Example

    import { BunTea } from 'bun-tea'
    import { cors } from 'bun-tea/cors'
    
    const app = new BunTea()
    
    app.use(cors(), 'after')
    
    app.get("/", (ctx) => {
        return ctx.json({
          message: "Hello World! I'm CORS enabled",
        });
    })
    
    app.listen({
        port: 3000
    }, (server) => {
        console.log(`Server started on ${server.port}`)
    })
    
    middleware 
    opened by one-aalam 0
  • Routing: Auto-type inference

    Routing: Auto-type inference

    Make route params auto-infer typings from the provided route paths.

    app.get("/user/:name/books/:title", (ctx, params) => {
        // params.name ? => string
        // params.title ? => string
    
        return ctx.json({
            params
        })
    })
    

    Make this work for even advanced path matchers

    opened by one-aalam 0
  • Middleware: Body Parser

    Middleware: Body Parser

    parseBody (utility/parser)

    Add a parseBody(parser) utility that can negotiate the content type of the form submissions, and returns the parsed body

    Supports:

    • [x] application/json
    • [x] application/text
    • [x] application/x-www-form-urlencoded
    • [x] multipart/form-data (not available in Bun natively)

    Example:

    // your parsed body
    const body = await parseBody(ctx.request!)
    

    Currently, plan to support reading all the content at once and improve it in the future version of the middleware (or when Bun natively supports multipart/form-data

    Middleware

    As a companion utility, add a body-parser middleware, that attaches the parsed payload to context ctx.body using the above utility.

    Supports: The middleware should support the following multipart/form-data configurations (all optional)

    • extensions - supported file extensions (default: all the extensions)
    • maxFileSizeBytes - supported maximum payload size per file (default: no restrictions)
    • maxSizeBytes - supported maximum payload size for all the files (default: no restrictions)

    Example(basic):

    import { BunTea } from 'bun-tea'
    import { bodyParser } from 'bun-tea/dist/mw/body-parser'
    
    const app = new BunTea()
    
    app.post("/users", [ bodyParser() ], (ctx) => {
        // get your parsed body here...
        // console.log(ctx.body)
        return ctx.json({
            message: "users created",
        });
    })
    
    app.listen({
        port: 3000
    }, (server) => {
        console.log(`Server started on ${server.port}`)
    })
    

    Example(with configuration):

    import { BunTea } from 'bun-tea'
    import { bodyParser } from 'bun-tea/dist/mw/body-parser'
    
    const app = new BunTea()
    
    app.post("/users", [ bodyParser({
        extensions: ['jpg'],
        maxFileSizeBytes: 2_4000,
        maxSizeBytes: 2_6000
    }) ], (ctx) => {
        // get your parsed body here...
        // console.log(ctx.body)
        return ctx.json({
            message: "users created",
        });
    })
    
    app.listen({
        port: 3000
    }, (server) => {
        console.log(`Server started on ${server.port}`)
    })
    
    enhancement middleware 
    opened by one-aalam 0
  • Routing: Support more formats

    Routing: Support more formats

    Make routing more capable and support the following formats too

    interface AppLocals {
        user: string
    }
    
    const app = new BunTea<AppLocals>()
    
    // /flights/KOL-GGN => { from: "KOL", to: "GGN" }
    app.get<{ from: string, to: string }>("/flights/:from-:to", (ctx, params) => {
        return ctx.json({
            params
        })
    })
    
    // /folder/README.md => { file: "README", ext: "md" }
    app.get<{ from: string, to: string }>("/folder/:file.:ext", (ctx, params) => {
        return ctx.json({
            params
        })
    })
    
    // /api/users.json => { ext: "json" }
    app.get<{ ext: string }>("/api/users.:ext", (ctx, params) => {
        return ctx.json({
            params
        })
    })
    
    // shop/product/color::red/size::xl => { color: "red", size: "xl" }
    app.get<{ color: string, size: string }>("/shop/product/color::color/size::size", (ctx, params) => {
        return ctx.json({
            color: params.color,
            size: params.size
        })
    })
    
    enhancement 0.0.1-alpha.next 
    opened by one-aalam 0
  • Routing: Sub-App Mounting

    Routing: Sub-App Mounting

    Allow for mounting different BunTea apps on the parent/root BunTea instance

    /**
     * Main App
     */
    interface AppLocals {
        user: string
    }
    
    const app = new BunTea<AppLocals>()
    app.get("/", (ctx) => {
        return ctx.halt(200, {
          message: "Hello World!",
        });
    })
    
    /**
     * Sub-App
     */
    interface SubAppLocals {
        admin: string
    }
    
    const subApp = new BunTea<SubAppLocals>()
    
    subApp.get<{ name: string }>("/goodbye/:name", (ctx, params) => {
        return ctx.json({
          message: `Goodbye, ${params.name}`,
        });
    })
    
    

    It's currently going to be effectively copying of the sub-app routes to the parent app routes

    In the future, the parent app can delegate important calls to sub-apps (for error handling) and do other useful stuff/delegation and proxying.

    enhancement 0.0.1-alpha.next 
    opened by one-aalam 0
  • Routing: Route Grouping

    Routing: Route Grouping

    Allow route grouping with group as a convenient method to add route prefixes on the app

    // /api
    const api = app.group('/api')  
    
     //  /api/v1
    const apiV1 = api.group('/v1')
    
    //  /api/v1/list
    apiV1.get('/list', (ctx) => {
        return ctx.json({
            list: 'list'
        })
    }) 
    
    // api/v1/user
    apiV1.get('/user', (ctx) => {
        return ctx.json({
            user: 'user'
        })
    }) 
    
    //  /api/v2
    const apiV2 = api.group('/v2')
    
    //  /api/v2/list
    apiV2.get('/list', (ctx) => {
        return ctx.json({
            list: 'list'
        })
    })
    
    //  /api/v2/user
    apiV2.get('/user', (ctx) => {
        return ctx.json({
            user: 'user'
        })
    })
    

    groups to also support middlewares at the group level

    const api = app.group("/api", (_, next) => {
        console.log("called from API route")
        return next()
    }, (ctx, next) => {
        console.log("called from API route again")
        return ctx.halt(200, "You've visited a group route. Please try going to some child route")
    })
    
    enhancement 0.0.1-alpha.next 
    opened by one-aalam 0
  • Zarf Name

    Zarf Name

    👋 current maintainer of Zarf (https://github.com/defenseunicorns/zarf). I wanted to say hi and see how we can avoid name collisions. We're in the K8s / deployment env so it might not be an issue. Thanks!

    opened by jeff-mccoy 0
  • Framework: Support runtime adapters (Deno, Node.js, etc.)/serverless functions

    Framework: Support runtime adapters (Deno, Node.js, etc.)/serverless functions

    Make Zarf adaptable to different JS runtimes (Node.js, Deno, Cloudflare, etc.)

    • [x] Bun.js - Separate out the Bun.js server as an adapter
    • [ ] Deno
    • [ ] Node.js
    • [ ] Cloudflare Workers

    and support server-less functions providers like

    • [ ] Netlify Functions
    • [ ] Vercel Functions
    opened by one-aalam 0
  • Engine: Storage

    Engine: Storage

    • Add a unified interface for all sorts of key-value stores
    • Add a in-memory session store, to demonstrate the interface and support basic in memory storage

    Implementation Details

    Add abstract class BunStorageEngine and extension BunSessionStorageEngine. As a basic implementation BunInMemorySessionStorageEngine to maintain data in memory.

    BunStorageEngine(Abstract Class) -> BunSessionStorageEngine(Implementation Class) -> BunInMemorySessionStorageEngine (Extension of Implementation Class)

    opened by one-aalam 0
  • App: Configuration

    App: Configuration

    Take useful configurations to change the behaviour of the BunTea instance

    interface BunTeaConfig {
        appName?: string
        serverHeader?: string
        strictRouting?: boolean
        errorHandler?: (ctx: AppContext, error: Errorlike) => Response | Promise<Response> | Promise<undefined> | undefined
    }
    
    enhancement 0.0.1-alpha.next 
    opened by one-aalam 0
  • Server: Configuration

    Server: Configuration

    Improve server instantiation process, and allow for more configurations

    Allow for options like

    • [ ] SSL/TLS
    • [x] Shutdown
    • [x] App naming

    Refer: https://github.com/oven-sh/bun/tree/main/examples

    enhancement 
    opened by one-aalam 0
Releases(v0.0.1-alpha.23)
🌌 Fast, in-memory, full-text search engine written in TypeScript. Now in beta.

Installation You can install Lyra using npm, yarn, pnpm: npm i @nearform/lyra yarn add @nearform/lyra pnpm add @nearform/lyra Usage Lyra is quite simp

NearForm 5.1k Dec 30, 2022
Gyazo API wrapper made in TypeScript. *For now, only upload feature.

wrap-gyazo Gyazo API wrapper made in TypeScript. *For now, only upload feature. Installation npm i wrap-gyazo Register an application with Gyazo. Gyaz

null 2 Jan 11, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Fast, and friendly Bun web framework

?? KingWorld Fast, and friendly Bun web framework. ⚡️ Faster than Express.js by 8.5x on M1 Max Named after my favorite VTuber (Shirakami Fubuki) and c

SaltyAom 114 Jan 4, 2023
⚡️ A fast, minimalist web framework for the Bun JavaScript runtime

?? Bao.js A fast, minimalist web framework for the Bun JavaScript runtime. ⚡️ Bao.js is 3.7x faster than Express.js and has similar syntax for an easy

Matt Reid 746 Dec 26, 2022
🚀 Blazing Fast S3 Powered CDN ✨ Powered By Fastify, S3 Buckets & Docker!

?? WasiCDN Blazing Fast S3 Powered CDN, Powered By Fastify, S3 Compatible Buckets & Docker! Core DockerHub: https://hub.docker.com/r/maximking19/wasic

Maxim 5 Aug 31, 2022
Fast Differentiable Tensor Library in JavaScript and TypeScript with Bun + Flashlight

A fast differentiable tensor library for research in TypeScript and JavaScript. Built with bun + flashlight. ⚠️ This is experimental software! ⚠️ Usag

Meta Research 917 Jan 7, 2023
Query for CSS brower support data, combined from caniuse and MDN, including version support started and global support percentages.

css-browser-support Query for CSS browser support data, combined from caniuse and MDN, including version support started and global support percentage

Stephanie Eckles 65 Nov 2, 2022
Full-stack-todo-rust-course - we are building this out now in prep for the real course

full-stack-todo-rust-course wip - we are building this out now in prep for the real course Plan Come up with the requirements Create user stories Desi

Brooks Builds 89 Jan 2, 2023
The jQuery plugin that brings select elements into the 21st century with intuitive multiselection, searching, and much more. Now with Bootstrap 5 support.

bootstrap-select The jQuery plugin that brings select elements into the 21st century with intuitive multiselection, searching, and much more. Now with

SnapAppointments 9.7k Dec 30, 2022
The jQuery plugin that brings select elements into the 21st century with intuitive multiselection, searching, and much more. Now with Bootstrap 5 support

bootstrap-select The jQuery plugin that brings select elements into the 21st century with intuitive multiselection, searching, and much more. Now with

SnapAppointments 9.7k Dec 30, 2022
This is a full-stack exercise tracker web application built using the MERN (MongoDB, ExpressJS, ReactJS, NodeJS) stack. You can easily track your exercises with this Full-Stack Web Application.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

WMouton 2 Dec 25, 2021
🌸 A fast and fun way to learn Japanese alphabets: hiragana & katakana. Don't wait - learn now!

Sakurator | Start learning 日本語 here Sakurator (Website publish date: ~4-6 April '22) - a personal trainer for learning Japanese alphabets (hiragana &

Anatoly Frolov 3 Jun 22, 2022
A zero-dependency, strongly-typed web framework for Bun, Node and Cloudflare workers

nbit A simple, declarative, type-safe way to build web services and REST APIs for Bun, Node and Cloudflare Workers. Examples See some quick examples b

Simon Sturmer 16 Sep 16, 2022
Tiny and expressive web framework for Bun.js

Bagel Bagel is a tiny and expressive web framework for Bun.js for building web APIs. Inspired by Express.js and Koa.js. Here we treat Typescript as fi

KaKeng Loh 34 Nov 25, 2022
A next-gen web framework made on top of bun

Eviate JS (WIP) Next-generation web framework to build powerful apps Features Simple: No more req or res. It's all ctx (context) and plain objects! Fa

eviatejs 17 Oct 30, 2022
Full-Stack Web & Mobile Developer Portfolio (Landing Page only)

[DRAFT] Full-Stack Web & Mobile Developer Portfolio (Landing Page only) ?? Contact me at: LinkedIn My company's website Project Description ⚠️ Nothing

algife 1 Feb 7, 2022