GithubHelp home page GithubHelp logo

tinyhttp / tinyhttp Goto Github PK

View Code? Open in Web Editor NEW
2.6K 23.0 122.0 10.6 MB

๐Ÿฆ„ 0-legacy, tiny & fast web framework as a replacement of Express

Home Page: https://tinyhttp.v1rtl.site

License: MIT License

TypeScript 99.78% JavaScript 0.15% Shell 0.07%
web webframework nodejs javascript javascript-framework backend http-server express-js http esm

tinyhttp's Introduction




tinyhttp

โšก Tiny web framework as a replacement of Express


npm GitHub Workflow Status Coverage



tinyhttp is a modern Express-like web framework written in TypeScript and compiled to native ESM, that uses a bare minimum amount of dependencies trying to avoid legacy hell.

Features

  • โšก 66% faster than Express
  • โš™ Express middleware compat
  • โ†ช Async middleware support
  • โ˜‘ ESM-only
  • ๐Ÿš€ No legacy dependencies, just the JavaScript itself
  • ๐Ÿ”จ Types out of the box
  • ๐Ÿ”ฅ Prebuilt middleware for modern Node.js

Visit tinyhttp website for docs, guides and middleware search.

Install

Node.js 14.21.3+ is required.

pnpm i @tinyhttp/app

Donate

You can donate with fiat or crypto here.

Sponsors


Deta

molefrog

Contributing

There are many ways to contribute:

For ways to contribute, please see the documentation.

tinyhttp's People

Contributors

aarontravass avatar ahmad-reza619 avatar alcar avatar aldy505 avatar allcontributors[bot] avatar arnovsky avatar betelgeuse1 avatar bra1l0r avatar dependabot[bot] avatar dxu23 avatar elianiva avatar esthedebeste avatar groenroos avatar iketiunn avatar ionellupu avatar khmm12 avatar koljatm-edeka avatar luiginator avatar mauriziopz avatar omrilotan avatar rhnsharma avatar rocktimsaikia avatar rokaicker avatar sachaw avatar setheal avatar shzmr avatar talentlessguy avatar tomhooijenga avatar vitalybaev avatar wakeupmh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tinyhttp's Issues

[Feature] Precompressed static content

Reduce transmission overhead by delivering precompressed (gz/br) versions of static content when the request header indicates support

Expand the static middleware to support serving pre-compressed files with the appropriate headers.

404 when passing more than 1 middleware to app.method

Sooooo,
I am having a new issue: the first response gives an actual error/result (which is expected), but on the second request it responds with my 404 noMatchHandler.. It doesn't matteer what the url is on the second request, it just sends the 404 and then complains the headers are already sent.

Create PostgreSQL example

Create an example of using tinyhttp with PostgreSQL via pg-promise

If you know a better / more modern PostgreSQL client for Node.js, feel free to suggest them in this thread

app logic can be taken from MongoDB example

Typescript example doesn't send responses

Describe the bug

I'm just getting started with tinyhttp so I may be misunderstanding something, but here goes.

I copied the typescript example, changed the package.json to include "@tinyhttp/app": "0.4.7" to get it to work with npm.

After installing and starting I get the Started on http://localhost:3000 message in the terminal, but visiting localhost:3000 doesn't output anything.

Does tinyhttp require pnpm or is it just a suggestion?

To Reproduce

Steps to reproduce the behavior:

  1. Copy https://github.com/talentlessguy/tinyhttp/tree/master/examples/typescript
  2. Remove existing @tinyhttp/app dependency and install your own with npm
  3. npm run start
  4. Visit localhost:3000

Expected behavior

<h1>Hello World</h1> should be sent a response, but nothing is and the site just times out.

Versions

  • node: v12.18.2
  • @tinyhttp/app: 0.4.7

Add the rest of HTTP methods to Router

Is your feature request related to a problem? Please describe.

At the moment Router only has a few methods that can be used. There must be all of them.

Describe the solution you'd like

Copy paste some method and change it's name.

to get a full list of methods:

node -p 'http.METHODS'

Additional context

router.ts file

[core] Template engines support

Is your feature request related to a problem? Please describe.

at the moment tinyhttp doesn't have a direct template engine support that Express has.

Describe the solution you'd like

Would be cool to have app.engine and app.render methods being implemented. I need to think of the best approach, probably will analyze some existing solutions first.

Additional context

Express docs reference:

Express API implementation TODO

This is the issue to track progress of Express API implementation

App

Properties

  • app.locals
  • app.mountpath

Methods

  • app.all()
  • app.engine()
  • app.listen()
  • app.param() (#162) [deprecated in Express 4.11.0]
  • app.path()
  • app.render()
  • app.route() (#94)
  • app.set()
  • app.use()

HTTP Methods

  • checkout
  • copy
  • delete
  • get
  • head
  • lock
  • merge
  • mkactivity
  • mkcol
  • move
  • m-search
  • notify
  • options
  • patch
  • post
  • purge
  • put
  • report
  • search
  • subscribe
  • trace
  • unlock
  • unsubscribe

Request

Properties

  • req.app
  • req.body
  • req.cookies
  • req.fresh
  • req.hostname
  • req.ip
  • req.ips
  • req.method
  • req.params
  • req.path
  • req.protocol
  • req.query
  • req.route
  • req.secure
  • req.signedCookies
  • req.stale
  • req.subdomains
  • req.xhr
  • req.originalUrl
  • req.is

Methods

  • req.accepts()
  • req.acceptsCharsets()
  • req.acceptsEncodings()
  • req.acceptsLanguages()
  • req.get()
  • req.is()
  • req.range()

Response

Properties

  • res.app
  • res.locals

Methods

  • res.append() (#117)
  • res.attachment()
  • res.cookie()
  • res.clearCookie()
  • res.download()
  • res.end()
  • res.format()
  • res.get()
  • res.json()
  • res.jsonp() => gonna be a separate package (@tinyhttp/jsonp)
  • res.links()
  • res.location()
  • res.redirect()
  • res.render()
  • res.send()
  • res.sendFile()
  • res.sendStatus()
  • res.set()
  • res.status()
  • res.type()
  • res.vary()

[cli] Implement CLI generator for tinyhttp apps

For faster setup of tinyhttp it would be cool to have an CLI that boostraps a tinyhttp project.

It will use cac as a CLI framework. I started working on it here:

Here's a list of requiremenets

Requirements

Flags + file generation

  • Package manager detection, via PATH and special flags like --pnpm, --yarn and --npm
  • - --eslint should pick ESLINT_JS_CONFIG for .eslintrc
  • --prettier should create .prettierrc wih PRETTIER_CONFIG
  • --full should create ESM application with ESLint & Prettier
  • new <project> should fetch the example folder from github and copy files from there.

Other

  • Run $packageManager install (e.g. pnpm install)
  • Output message about successfull installation
  • Write a detailed help message
  • Write unit tests for CLIs
  • Wrap dangerous places in try-catches

Examples

$ tinyhttp <folder>
Setting up <folder>...
Creating configuration files...
Package manager: pnpm
Installing packages...
Done!

Start the server in development mode:

pnpm dev
$ tinyhttp <folder> --template=<template>
Setting up <folder> from <template>
Creating configuration files...
Package manager: pnpm
Installing packages...
Done!

Start the server in development mode:

pnpm dev

[middleware] @tinyhttp/static resursive prop doesn't work

Describe the bug

recursive prop doesn't make anything recursive. It still has 1-level depth. Should have max depth instead, with handling all the routes properly, e.g. static/dir/file.js => /dir/file.js

Versions

  • node: 14.5.0
  • @tinyhttp/app: 0.2.1

The bug seems to be very easy to fix, so PRs are welcome

Optimize the overall site for mobile view.

Describe the bug

Most of the current pages of the site are not responsive. It can be said that no one actually gonna read API docs in mobile but making the site at least responsive is quite important.

Add any other context about the problem here.

Screenshot_3

Transfer to an org

Once the repo hits ~500 stars I think it is a good time to transfer it to a separate org, along with all es-* modules

and all new es-* things for the ecosystem will be created in there

for now tinyhttp will be still here

Allow to pass an array of middlewares

Is your feature request related to a problem? Please describe.

rn tinyhttp only allows to pass a list of wares as arguments but we also need to have support of arrays to be closer to Express.

Describe the solution you'd like

Add Handler[] to the use function argument union and handle a case when an argument is an array

Additional context

Piece of code in where middleware gets "used"

Progress

  • support for app.use
  • support for other methods

Write tests for bot-detector

Write tests for @tinyhttp/bot-detector using supertest-fetch (that is used in other tests)

The module is quite small, so a little things have to be tested:

  • It doesn't identify browser UserAgent as a bot
  • It identifies Google crawler as a bot
  • it identifies node request as a bot

[middlewares] Add `timestamp` option to logger

Would be great if the logger could have an option to print out the timestamp via timestamp property.

something like

app.use(logger({ timestamp: { format: 'MM:SS' } }))

and then

08:23:12 GET / 200 OK

I'm thinking of this option:

format: string 

Probably could be consumed by some date library and then transformed into a timestamp

Tests TODO

The final goal is of this issue is to achieve ~80-100% coverage

here's a todo list of things that require tests (based on the __tests__ folder):

โš ๏ธ List is in progress, I'll be adding new test tasks over time, here are some that you can submit already

  • core
    • app
      • app - app.set, app.enable, app.disable (codecov)
      • onError - Test a case where an error doesn't have an HTTP status code, neither is a string (codecov)
    • request
    • response
  • modules
    • accepts
    • cookie-signature
    • cookie
    • etag (#133)
    • req (#140)
    • res
      • res.format - if default only is specified, call it as a function (codecov)
      • res.format - if nothing is specified, throw 406 (codecov)
    • router
    • send (#143)
  • wares
    • cookie-parser
    • cors
      • Accept a function to set origin
    • dotenv
    • favicon
    • jwt
      • Should work with different algorithms (codecov) [pending]
    • logger
    • ping
    • bot-detector (#111)
    • ip-filter
    • jsonp (#123)\

If you want to help with tests, write down to this thread with your questions

Router methods hang if one is called after another

'm having trouble with my custom async middleware...It seems to hang on loading the POST request and the logger middleware doesnt print anything related to that request. It also seems to block any app.use() lines after the line that is cuasing it to hang, which causes 404 to not work. I'm not sure what the problem is with my code (im using async/await with bcrypt and mongodb) but it shouldnt block other methods after it? What's weird is that app.get() lines that are BEFORE the problematic line work totally fine. I'll post my code here if needed but I'm not sure what is causing it to hang. I'm pretty sure ive handled all the errors AND changed some of the functions to async functions. I also checked that I'm sending a response with res.json() or res.send() so its not that im not sending anything...

heres my middleware file: https://hastebin.com/ifocicitem.js and heres where i use it: https://hastebin.com/juhovowuvo.coffeescript

Create tinyws project (websocket framework based on tinyhttp)

Create a WebSocket wrapper for tinyhttp, similar to express-ws and express-ws-routes

Usage will be something like this:

import { App } from 'tinyws'

const app = new App() 

app.ws('/abc', (ws, req) => {
    ws.on('message', msg => {
    ws.send(msg)
  })
})

If you have a better idea of how the usage should like, share in the thread

Implementation details

App must extend Router from '@tinyhttp/router'

If possible, it shouldn't depend on extra modules. But if not, then ws can be used.

Middleware dispatch algorithm is wrong

At the moment, some Express middlewares don't work. Sometimes appending middlewares leads to non of them handling the server and resulting in 404 Not Found.

This is what we have now:

https://github.com/talentlessguy/tinyhttp/blob/0ce614319949cb03dc1a8f1298da1a1ecf35fda5/packages/app/src/app.ts#L54-L115

The app.handler function must be redone.

I don't know yet how, so feel free to suggest down below.

Now, tinyhttp uses Polka-like dispatch algorithm, but maybe my implementation is wrong, or Polka one is not applicable to this case.

[core] Add support for App as middleware

Describe the solution you'd like

tinyhttp needs to have support of app.use(Router) and app.use(App) to be more compatible with express.

So we could do this:

import { App, Router } from '@tinyhttp/app'

const app = new App()

const router = new Router()

router.get('/', (req, res) => res.end('bruh'))

app.use('/sub-app',  router)

and this:

import { App } from '@tinyhttp/app'

const app = new App()

const subApp = new App()

subApp.get('/', (req, res) => res.end('bruh'))

app.use(subApp)

Additional context

Polka.js implementation: https://github.com/lukeed/polka/blob/88f380272973019df5dc7c37611ac987bcd67d47/packages/polka/index.js#L50-61

Add badges option to @tinyhttp/logger

Is your feature request related to a problem? Please describe.

It adds emoji badges for better readability

Describe the solution you'd like

Add badges setting with 2 sub-settings to be used like this:

app.use(logger({ badges: { emoji: true, captions: false }))

Default values are both false - if badges: true - only toggle emoji. if an object is present - check for the settings.

first setting toggles emoji badges, like this โš ๏ธ
second enables emoji alt text (in case emoji fails to display or just prefer the text instead), like this: warning

here's a table of emoji / texts:

emoji text status code
โŒ Error 500
โš ๏ธ status message 4XX (Except 404)
๐Ÿ†— OK 2XX
๐Ÿ”Ž Not Found 404

Should be logged in the beginning:

๐Ÿ†— GET 200 OK /css/shared.css

Additional context

Zoya logger that has emoji:

image

[core] [middlewares] Cover everything in tests

TODO list:

Core

App

  • Should launch a basic server
  • Should chain middleware
  • Should respond on matching route
  • "*" should catch all undefined routes
  • should throw 404 on no routes
  • next function skips current middleware
  • next function handles errors
  • app.locals are get and set
  • Custom noMatchHandler works
  • Custom onError works
  • App works with HTTP 1.1
  • App works with HTTP/2
  • App works with HTTPS
  • Router is getting mounted as a sub-app
  • App is getting mounted as a sub-app
  • more coming soon

Request

  • should have default HTTP Request properties
  • req.query is being parsed properly
  • req.params is being parsed properly
  • req.set sets the header and req.get returns a header
  • req.xhr is false because of node-superagent
  • req.protocol is default to http and req.secure is false
  • req.protocol is https when the app is wrapped in https.createServer
  • req.fresh and req.stale work properly
  • more coming soon

Response

  • should have default HTTP Response properties
  • res.json stringifies the object
  • res.send sends plain text data
  • res.send sets proper headers
  • res.send falls back to res.json when sending objects
  • res.status sends status
  • res.sendStatus sends status + text
  • res.location sends Location header
  • res.set sets header
  • res.links sends links
  • more coming soon

Router

  • app.method tests
  • next() / next(err) tests
  • 404 catch tests

Middlewares

  • cors
  • static
  • jwt
  • cookie-parsrer
  • markdown
  • logger

Other packages

  • etag
  • cookie-signature
  • dotenv

Heroku don't work with tinyhttp

Describe the bug

I write a simple web service using tinyhttp and i decided to deploy on heroku.
but guess what, heroku don't compatible with tinyhttp.
when i replaced tinyhttp with express, everything works fine.

To Reproduce

Steps to reproduce the behavior:

  1. write webservice
  2. add Procfile
  3. set web: yarn start
  4. git add -A
  5. git push heroku master

Expected behavior

Working Fin!

Versions

  • node: 14
  • @tinyhttp/app: 0.4.1

Additional context

Setup code coverage

We surely need to have test coverage tool set up. I have a little experience with Codecov. Any recommendations for anything else?

Middleware

tinyhttp offers a list of pre-made middleware, to ease maintainability and provide better compatability and types.

Here will be a full list of middlewares to be implemented:

  • logger
  • markdown
  • cors
  • jwt
  • cookie-parser
  • body parser
  • session
  • ip-filter
  • favicon
  • ping (response time metric + setting X-Response-Time header)
  • bot-detector (using something like this)
  • unless (#118)
  • dotenv (load dotenv from root or specified file)
  • rate-limit (#96)
  • pug
  • jsonp

If you want to implement any and have questions, write down to the thread

Typescript +body-parser gives nextfunction error?

Describe the bug
In the readme you said tinyhttp has "Full Express middleware support", but body-parser doesn't seem to work here as seen in the examples/auth folder in this repository.

Argument of type 'NextHandleFunction' is not assignable to parameter of type 'string | AsyncHandler | SyncHandler'.
  Type 'NextHandleFunction' is not assignable to type 'AsyncHandler'.
    Types of parameters 'next' and 'next' are incompatible.
      Type 'NextFunction | undefined' is not assignable to type 'NextFunction'.
        Type 'undefined' is not assignable to type 'NextFunction'.

To Reproduce
Steps to reproduce the behavior:

Use typescript and body-parser and tinyhtttp and use the following line:

app.use(bodyParser.urlencoded({ extended: false }));

Expected behavior
I expected it to not give an error about the NextFunction.

Versions

  • node: 12
  • @tinyhttp: 0.2.3

Error image

Express body-parser doesn't parse the body

Describe the bug

With using Express body-parser, neither bodyParser.json nor bodyParser.urlencoded work. Instead of a body will with data we get {}

To Reproduce
Steps to reproduce the behavior:

import { App } from '@tinyhttp/app'
import bodyParser from 'body-parser'

const app = new App()

app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json

app.use(bodyParser.json())

app.use(function (req, res) {

  res.setHeader('Content-Type', 'text/plain')
  res.write('you posted:\n')
  res.end(JSON.stringify(req.body, null, 2))

})

app.listen(3000)

and then in terminal:

curl localhost:3000 -X POST -F "a=b"

Expected behavior

req.body would be filled with data

Versions

  • node: 14.5.0
  • @tinyhttp: 0.2.12

Additional context

body-parser repo

Use a logging library as a logger implementation instead of console.log

Is your feature request related to a problem? Please describe.
I feel that using something like pino or winston will be best for logging purposes, since there is no need to create our own logger and reinvent the wheel.

Describe the solution you'd like
Rewrite the current logger package to use a fully-featured logging library.

Describe alternatives you've considered
Using console.log has disadvantages, some users would like to save the logs to a file, log via http, etc... This is not possible using our current logging solution.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.