{"id":21746873,"url":"https://github.com/jasonbyrne/minikin","last_synced_at":"2025-04-13T06:51:07.122Z","repository":{"id":39658493,"uuid":"265840663","full_name":"jasonbyrne/minikin","owner":"jasonbyrne","description":"Small but mighty! Tiny server in TypeScript with no dependencies.","archived":false,"fork":false,"pushed_at":"2023-02-04T12:22:28.000Z","size":941,"stargazers_count":7,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T02:17:39.294Z","etag":null,"topics":["http","micro","microframework","router","server","tiny","typescript","webserver","zerodependencies"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jasonbyrne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-21T12:17:19.000Z","updated_at":"2023-06-19T08:05:47.000Z","dependencies_parsed_at":"2023-02-18T16:31:29.478Z","dependency_job_id":null,"html_url":"https://github.com/jasonbyrne/minikin","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonbyrne%2Fminikin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonbyrne%2Fminikin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonbyrne%2Fminikin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasonbyrne%2Fminikin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jasonbyrne","download_url":"https://codeload.github.com/jasonbyrne/minikin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248675458,"owners_count":21143766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","micro","microframework","router","server","tiny","typescript","webserver","zerodependencies"],"created_at":"2024-11-26T08:07:19.157Z","updated_at":"2025-04-13T06:51:07.097Z","avatar_url":"https://github.com/jasonbyrne.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![alt Minikin | Small but mighty typescript router](https://github.com/jasonbyrne/minikin/blob/master/minikin.png?raw=true)\n\n![Version](https://badgen.net/npm/v/minikin)\n![Size](https://badgen.net/packagephobia/publish/minikin)\n\nSMALL BUT MIGHTY!\n\nYet another router? Why?! Well, the other ones are really big. They have dependencies and do too much. I just wanted a simple way to start up an HTTP server, handle some routes, and handle the core use cases that you need most of the time. 80-20 rule. No other fluff. And no dependencies!\n\n# Getting Started\n\nIn the 1.\\* versions of Minikin, it shipped with both the router and server together. With version 2.0 the base package of `minikin` only includes the router. Choose the appropriate option below for your needs.\n\n## \"Hello World\" with Minikin Server\n\nFirst install the project dependency:\n\n```\nnpm i minikin\n```\n\nNow in our code, we will import Minikin and then instantiate an instance of Minikin Server. Finally we define a route that will wildcard respond to any request with \"Hello from Minikin!\". Notice that `Server()` is awaited, so we wrap the entire thing in a self-calling `async` function.\n\n```javascript\nimport Server from \"minikin\";\n\n(async () =\u003e {\n  const minikin = await Server();\n\n  minikin.route(\"*\", () =\u003e \"Hello from Minikin!\";\n})();\n```\n\nIn the above example, Minikin automatically picked an open port to listen on. The console log will tell you which port it picked or you can grab it with:\n\n```javascript\nconst port = minikin.port;\n```\n\nHowever, typically you want to specify the port to listen on. Just use the first argument to do so:\n\n```javascript\nconst minikin = await Server(8080);\n```\n\nOr of course you can use an environment variable:\n\n```javascript\nconst minikin = await Server(process.env.PORT);\n```\n\n## Using the router only\n\nIf you are not going to use the web server part of Minikin, you can save a few bytes by instaling just the router component:\n\n```bash\nnpm i minikin-router\n```\n\nWe do not need to await the router, so it doesn't need to be wrapped in an `await` function.\n\n```javascript\nimport Router from \"minikin-router\";\n\nconst minikin = Router();\n```\n\nIf aren't using the Minikin server, it means you're listening for incoming requests yourself. So define the routes the same way the below examples show you. Then when you get the event for the incoming request, pass it to the Minikin router with the `handle` method. It will parse it and return the response, which must be awaited.\n\n```javascript\nconst response = await minikin.handle(req);\n```\n\n# Routing examples\n\nThe examples below for defining routes work the same for either the server or the router.\n\n## Basic route\n\nThis will define a route that that response to `GET` requests to the `/yo` path. The second argument is a callback function that receives the incoming request. Here we simply return a string \"Yo back at ya\" as the response.\n\n```javascript\nminikin.route(\"GET /yo\", (req) =\u003e \"Yo back at ya\");\n```\n\nThis is the equivalent of the more longhand:\n\n```javascript\nminikin.route(\"GET /yo\", (req) =\u003e text(\"Yo back at ya\"));\n```\n\nYou'll need to also import the `text` class with:\n\n```javascript\nimport { text } from \"minikin-router\";\n```\n\nFor the other similar response methods that you'll find below (like `json`, `file`, etc.), you'll need to similarly import the method like the above example.\n\n## Async callbacks\n\nAll request callbacks also support `async` so that you can `await` other calls.\n\n```javascript\nminikin.route(\"GET /some-text\", async (req) =\u003e {\n  const text = await goGetSomeText();\n  return text(text);\n});\n```\n\nTo instead respond with JSON:\n\n```javascript\nminikin.route(\"GET /some-json\", async (req) =\u003e {\n  const data = await goGetSomeData();\n  return json(data);\n});\n```\n\n## Set Status Code\n\nUse the second argument of `fromJson`, `fromString`, and similar `from*` methods to set additional parameters including the status code.\n\n```javascript\nminikin.route(\"GET /error400\", (req) =\u003e\n  json(\n    {\n      error: `Don't call this endpoint!`,\n    },\n    {\n      status: 400,\n    }\n  )\n);\n```\n\n## Set Headers\n\nYou can also use that second argument to set headers:\n\n```javascript\nminikin.route(\"GET /with-headers\", (req) =\u003e\n  text(\"This is the response body\", {\n    headers: {\n      \"X-Custom-Header\": \"Some Value\",\n    },\n  })\n);\n```\n\nAlternately you can set headers like this\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e text(\"Hey!\").header(\"X-Foo\", \"Bar\"));\n```\n\nIf you want to add trailers, they work the same way as headers except are called `trailer`\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e\n  text(\"Hi\", {\n    trailers: { \"X-Some-Trailer\": \"foobar\" },\n  })\n);\n\nOr...\n\nminikin.route(\"GET /bye\", () =\u003e\n  text(\"See ya later\").trailer(\"X-Foo\", \"Bar\")\n);\n```\n\n## Set Cookies\n\nSimilarly you can set cookies on the response\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e text(\"Hey!\").cookie(\"X-Foo\", \"Bar\", 60));\n```\n\nThe above sets the TTL (Max-Age) on the cookie to 60 seconds. Alternately, the third argument can accept an object allowing you to set any of the standard cookie options.\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e\n  text(\"Hey!\").cookie(\"X-Foo\", \"Bar\", {\n    \"Max-Age\": 60,\n    SameSite: true,\n  })\n);\n```\n\n## Path Paramaters\n\nMinikin can also handle URL path params out of the box:\n\n```javascript\nminikin.route(\"GET /hello/:name\", (req) =\u003e\n  json({\n    message: `Hello to ${req.params.get(\"name\")} from Minikin!`,\n  })\n);\n```\n\n## Read incoming JSON data\n\nIt will parse the JSON body automatically:\n\n```javascript\nminikin.route(\"POST /person\", (req) =\u003e {\n  const name = req.json.name; // { name: \"Jason\" }\n  return json({\n    message: `You want to create a new person named ${name}`,\n  });\n});\n```\n\n## Using HTTPS/SSL\n\nIf you want to do HTTPS, pass in your certificate information as the segment argument\n\n```javascript\nconst minikin = await Server(8000, {\n  pfx: fs.readFileSync(\"test/fixtures/test_cert.pfx\"),\n  passphrase: \"sample\",\n});\n```\n\n## Catch-All Routes\n\nFor a catch-all for all `GET` requests, put this LAST:\n\n```javascript\nminikin.route(\"GET *\", () =\u003e\n  json(\n    {\n      message: \"File not found\",\n    },\n    { status: 404 }\n  )\n);\n```\n\nIf you want to catch all HTTP methods, use just the wildcard. Remember: ALWAYS put the catch-all case LAST!\n\n```javascript\nminikin.route(\"*\", () =\u003e text(\"Catch all\"));\n```\n\nThis is equivalent to\n\n```javascript\nminikin.route(\"* *\", () =\u003e text(\"Catch all\"));\n```\n\nIf you want to be even more concise, you can totally skip the first argument. This will be the same as the previous two examples.\n\n```javascript\nminikin.route(() =\u003e text(\"Catch all\"));\n```\n\n## Route Patterns and Wildcards\n\nYou can also wildcard parts of the route like:\n\n```javascript\nminikin.route(\"GET /*/foo\", () =\u003e\n  json({\n    message: \"This will respond to /hello/foo or /goodbye/foo\",\n  })\n);\n```\n\nAnd you can use regex within your routes. This will accept either `/hello` or `/hello/`. The question mark makes the trailing slash optional.\n\n```javascript\nminikin.route(\"GET /hello/?\", () =\u003e\n  json({\n    message: \"This will respond to /hello or /hello/\",\n  })\n);\n```\n\n## Route that response to multiple HTTP Methods\n\nIf you need to handle multiple HTTP Methods with the same handler\n\n```javascript\nminikin.route(\"PUT|PATCH /hello\", () =\u003e text(\"Hi\"));\n```\n\nYou can also do a wildcard method\n\n```javascript\nminikin.route(\"* /goodbye\", () =\u003e text(\"Cya\"));\n```\n\nIf you do not set a method at all, it will be wildcard by default, which is equivalent to the last example.\n\n```javascript\nminikin.route(\"/goodbye\", () =\u003e text(\"Cya\"));\n```\n\n## Read Cookies\n\nMinikin will automatically read incoming cookies and make then available:\n\n```javascript\nminikin.route(\"GET /hello\", (req) =\u003e\n  text(req.cookies.has(\"myCookie\") ? \"cookie set\" : \"cookie not set\")\n);\n```\n\n## Read Headers\n\nMinikin also reads the incoming headers for you:\n\n```javascript\nminikin.route(\"GET /hello\", (req) =\u003e\n  text(req.headers.has(\"someHeader\") ? \"header set\" : \"header not set\")\n);\n```\n\n## Servce response from a local file\n\nIf it's a file that contains text:\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e file(\"/path/to/file\"));\n```\n\nIf it's a local binary file, like an image:\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e binary(\"/path/to/image\"));\n```\n\n## Templating\n\nYou can pull a resposne from a static file, like you would in the previous two examples, but then do simple template replacement. This example will replace any strings with `{{ name }}` in the `hello.html` file with the corresponding value in the second argument.\n\n```javascript\nminikin.route(\"GET /hello\", () =\u003e\n  template(\"public/hello.html\", { name: \"Jason\" })\n);\n```\n\nAlternately, you can call the render method on any response to pass in the key-value replacement.\n\n```javascript\nminikin.route(\"GET /hello/:name\", () =\u003e\n  text(\"Hello, {{ name }}\").render({ name: req.params.get(\"name\") })\n);\n```\n\n# Middleware\n\nMinkin also supports middleware, most often used as guards. This allows you to chain callbacks inline on a specific route. This first example adds authentication to a single route.\n\n```javascript\nconst requireAuthentication = (req: Request) =\u003e {\n  if (!req.headers.has(\"Authorization\")) {\n    return text(\"Must Authenticate\", { status: 401 });\n  }\n};\n\nminikin.route(\"GET /protected\", requireAuthentication, () =\u003e text(\"OK\"));\n```\n\nYou can add global level middleware as well, which can act as plugins and pre-processors. The `use` method allows this, similar to other frameworks. There is an alias for this called `before`, which describes better what it does (runs before the normal routes). However, `use` is the standard with other frameworks and so more familiar to developers.\n\n```javascript\nminikin.use(parseJwtToken);\nminikin.use(processFormEncodedInput);\nminikin.use((req) =\u003e {\n  if (req.headers.get(\"User-Agent\").test(/roku|firetv|appletv/i)) {\n    req.isConnectedTv = true;\n  }\n});\n```\n\nThese `use` handlers are exactly the same as any other route. They just are processed first. So this means you can return a response from, which will stop any further processing.\n\n```javascript\nminikin.use(() =\u003e text(\"STOP!\"));\n```\n\nYou cal also pass a first argument to restrict it to certain methods and paths. This can allow it to act as a guard for many endpoints at once:\n\n```javascript\nminikin.use(\"PUT|POST|PATCH|DELETE /api/*\", requireAuthentication);\nminikin.use(\"/images/*\", preventLeeching);\n```\n\nYou can also list out multiple use callbacks, like you can on a normal route. This is useful to enforce multiple rules or to run the request through multiple pre-processors.\n\n```javascript\nminikin.use(\"/admin/*\", requireAuthentication, mustBeAdmin);\n```\n\n## Set multiple routes at once\n\nYou can also use the `routes` method (instead of singular `route` method) to set multiple routes in an object form:\n\n```javascript\nminikin.routes({\n  \"GET /hello\": () =\u003e \"hello\",\n  \"GET /hello/:name\": (req) =\u003e json({\n    message: `Hello to ${req.params.get('name')} from Minikin!`,\n  },\n  \"GET /admin\": () =\u003e text(\"Forbidden\", {\n    status: 403\n  }\n});\n```\n\n# Redirects\n\nTo do a basic redirect:\n\n```javascript\nminikin.route(\"GET /foo\", () =\u003e redirect(\"/bar\"));\n```\n\nThe default status code for a redirect is 302, but you can change that with the second argument:\n\n```javascript\nminikin.route(\"GET /foo\", () =\u003e redirect(\"/bar\", 301));\n```\n\n# Afterware\n\nOn any route, you can call the `after` method to run logic on the corresponding response. This allows you to modify the response before it gets sent back to the user. This first example would override the response of \"hi\" with \"bye\" instead:\n\n```javascript\nrouter.route(\"GET /hello\", () =\u003e text(\"hi\")).after((res) =\u003e res.content(\"bye\"));\n```\n\nIf you want to run a modifier on the response of all endpoints (not a specific route), you can do so with the `after` method.\n\n```javascript\nrouter.after((res) =\u003e {\n  res.header(\"X-Some-Header\", \"value\");\n});\n```\n\nJust like you can with `use`/`before` and `route`, you can add in a path as the first argument to `after` to only run it on matching paths.\n\n```javascript\nrouter.after(\"GET /api/*\", (res) =\u003e {\n  // Allow CORS on API endpoints\n  res.header(\"Access-Control-Allow-Origin\", \"*\");\n});\n```\n\nAnd potentially, you could completely replace a response by returning it.\n\n```javascript\nrouter.after(\"GET /replaceMe\", (res) =\u003e text(\"some new response\"));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonbyrne%2Fminikin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasonbyrne%2Fminikin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasonbyrne%2Fminikin/lists"}