- v0.1.43Latest
- v0.1.30
- v0.1.21
- v0.1.20
- v0.1.10
- v0.1.0
- v0.0.950
- v0.0.945
- v0.0.941
- v0.0.94
- v0.0.932
- v0.0.927
- v0.0.926
- v0.0.922
- v0.0.921
- v0.0.92
- v.0.0.9
- v0.0.89
- v0.0.87
- v0.0.84
- v0.0.773
- v0.0.7
- v0.0.682
- v0.0.681
- v0.0.675
- v0.0.67
- v0.0.66
- v0.0661
- v0.0.65
- v0.0.64
- v0.0.63
- v0.0.62
- v0.0.61
- v0.0.6
- v0.0.56
- v0.0.4.0
- v0.0.3.0
- v0.0.2.3
- v0.0.2.2
- v0.0.2.1
- v0.0.2.0
- v0.0.1.91
- v0.0.1.9
- v0.0.1.1
- v0.0.1.0
- v0.0.0.99
- v0.0.0.71
- v0.0.0.7
- v0.0.0.65
- v0.0.0.6
- v0.0.0.5
- v0.0.0.4
- v0.0.0.3
- v0.0.0.2
Vixeny
Unleash the functional beast~
Introduction
Vixeny is a purely functional web framework in TypeScript that aims to rival other typed programming languages like Go or Rust.
- High-Performance: Carefully optimized for delivering top-tier performance at every processing level.
- Self-Sufficiency: Operates independently, with no external dependencies.
- Immutable Data: Prioritizes data safety and eliminates side effects.
- Scalability: Ensures high performance even under heavy loads.
- Extensive Testing: Over 100 different tests to ensure stability, reliability, and robustness in various scenarios and environments.
- User-Friendly: Provides clear syntax and comprehensive documentation for developers at all levels.
Benchmarks
Bun
Deno
Get Started in 10 Minutes!
Hello World in Deno!
import { serve } from "https://deno.land/std/http/server.ts";
import vixeny from "https://deno.land/x/endofunctor/fun.ts";
//import vixeny from "npm:vixeny/fun";
await serve(
vixeny({ hasName: "http://127.0.0.1:8080/" })([
{
path: "/",
f: () => "hello world",
},
]),
{ port: 8080, hostname: "127.0.0.1" },
);
Hello World in Bun!
import vixeny from "vixeny/fun";
export default {
port: 8080,
hostname: "127.0.0.1",
fetch: vixeny({ hasName: "http://127.0.0.1:8080/" })([
{
path: "/",
f: () => "hello world",
},
])
}
The Basics
/*
The vixeny framework requires:
vixeny(options)([...petitions])
Options - Configuration options for the vixeny server.
Petitions - An array of Petition (routes).
*/
import { Petitions } from "vixeny/types";
//Petition in the hello world example.
{
path: "/",
f: () => "hello world",
}
Parameters
[
{
path: '/param/:name/bun/:where',
f: (req) => `Hello ${req.param.name}, the oven is ready for you at : ${req.param.where}`
},
{
path: '/param/:name/deno/:where',
f: (req) => `Hello ${req.param.name}, time to ride the t-rex at : ${req.param.where}`
},
]
Query
[
{
path: '/query/name',
f: (req) => `Your name is : ${req.query?.name || "default"}`
},
{
path: '/query/nameAndId',
f: (req) => `Your name is : ${req.query?.name || 'default'} with the id : ${req.query?.id || "-1"}`
},
// Only the 'name' field is parsed from the query, ignoring other fields,
// using "only" improves significantly the performance.
{
path: '/query/onlyName',
query: {
only: ["name"]
},
f: (req) => `Hello ${req.query?.name || 'default'}`
},
]
Options
[
// This petition has the pre-set ".html" header that sets to "text/html".
{
path: "/headers/hello",
headers: ".html",
f: () => "<p>Hello world!</p>"
},
// Headers can also be manually set using an object. Here,
// Here, "Content-Type" is manually set to "text/html".
{
path: "/headers/again",
headers: { "Content-Type": "text/html"},
f: () => "<p>Hello world!</p>"
},
// This route mirrors the body of the request.
// Here, the "POST" method is used.
{
path: "/headers/method",
method: "POST", // "GET" | "HEAD" | "POST" | "DELETE"
status: 201,
f: (request) => request.req.body
}
]
Type Request
/*
* By setting the type to "request", the return type is changed from BodyInit to Response.
*/
[
// The ":name" is a dynamic part of the route which will match any string.
// The function 'f' checks if the 'name' parameter equals "Bun" or "Deno".
// If so , it responds with a 200 status code.
// If 'name' is anything else, it responds with a 400.
{
path: "/response/who/:name",
type: "request",
f: (req) => (req.param.name === "Bun" || req.param.name === "Deno")
? new Response( "Welcome", {status:200})
: new Response( "Only devs here", {status: 400})
}
]
Vixeny
Offers the ability to manage different aspects of an HTTP request-response cycle in the arguments as response, including headers, response status, request methods, query , parameters an others.
- add: allows you to add fields to the arguments, effectively enabling parsing for certain aspects of the request when your arguments go out of the scope
import functionX from "outOfScope"
[
{
//(f) will have the fields "req" and "param"
path:"/example/:id",
add: ["req","param"],
f: f => functionX(f)
}
]
- delete: allows you to remove fields from the arguments, providing the ability to exclude certain aspects of the request when there are no needed.
[
{
path: '/query/block',
delete: ['query'],
f: () => "Hello world"
}
]
Vixeny will always try to give you only what is necessary, not only for optimization, but also for the sake of safety and to avoid side effects.
Type Response
/*
* When the type is set to "response", the optimizer is bypassed.
* In such case, a Request is received and a Response is returned directly.
* Note that "r" is used instead of "f"
*/
[
// The route has the type set to "response", bypassing the optimizer.
// The function 'r' directly takes a Request object and returns a Response object.
{
path: "/response/hello",
type: "response",
r: (request) => new Response("Hello world!")
}
]
Type Static
/*
* The "path" is relative to where the terminal is currently located.
* In this example, we're serving files from the "misc" directory.
* MIME types are enabled by default but can be disabled by setting "mime: false".
* At the moment, only one static file can be served at a time.
*/
[
{
type: "static",
name: "/static/",
path: "./misc/",
},
]
Join all together
In the Vixeny framework, the spread operator (...
) can be used to efficiently include or import routes from other modules or parts of your application. This technique simplifies code organization and encourages a modular design.
The example you provided demonstrates the use of the spread operator in the main route configuration:
[
// A simple "Hello World" petition
{
path: "/",
f: () => "Hello world"
},
// Petitions imported from other modules using the spread operator
...urlParams,
...urlQueries,
...httpOptions,
...typeRequest,
...typeResponse,
...staticServer,
...jsonStringifier
]
In this configuration array, urlParams
, urlQueries
, httpOptions
, typeRequest
, typeResponse
, staticServer
, and jsonStringifier
are arrays of routes that are defined elsewhere in your application. By using the spread operator, these petitions definitions are unpacked and included directly.
Stringifier
/*
* This method uses the use of JSON Schema for faster serialization.
* By defining the structure of our data, we can potentially speed up JSON.stringify by a factor of 3 or more.
*/
[
// The function 'f' returns the parameters of the request.
// The 'json' attribute is used to define a JSON Schema that describes the structure of the expected JSON data.
{
path: "/json/:name",
f: (req) => req.param,
json: {
scheme: {
type: "object",
properties:{
name: {
type: "string"
}
},
required: ["name"]
}
}
}
]
Wildcard
//assuming we have these petitions
[
{path: "/hello/*", f: () => "first"},
{path: "/hello/nested/*" , f: () => "second"}
]
// new Request("http://127.0.0.1:8080/hello/nested/hi") -> "second"
// new Request("http://127.0.0.1:8080/hello/hi") -> "first"
Sign and verify
//explication of how it works goes here
there are two ways to use it:
vixeny({
hasName: 'http://127.0.0.1:3000/'
})
([
// -> http://127.0.0.1:3000/sign/01234567
// -> 01234567.k+1wEh9x
{
path: "/sign/:id",
signer: {
seed: "PUT_YOUR_SEED"
},
f: f =>
f.param.id.length > 7
? f.sign(f.param.id)
: "null"
},
{
// -> http://127.0.0.1:3000/verify/01234567.k+1wEh9x
// -> valid
path: "/verify/:token",
verifier: {
seed: "PUT_YOUR_SEED"
},
f: f => f.verify(f.param.token)
? "valid"
: "inValid"
}
])
import signer from "./components/tokens/signer.ts"
import verifier from "./components/tokens/verifier.ts"
const sign = signer({seed:"PUT_YOUR_SEED"})
const verify = verifier({seed:"PUT_YOUR_SEED"})
console.log(verify(sign("01234567")))
Thank you and enjoy using Vixeny!
Experimental Features
These features are still under development and may change over time.
Modularity
Compose and work as you want with components:
import stringify from "vixeny/components/stringify/stringify"
//Experimental
import signer from "vixeny/components/tokens/signer"
import verifier from "vixeny/components/tokens/verifier"
Q&A
Why doesnโt Vixeny support Node.js?
Node.js is not supported due to its incompatibility with the Response and Request methods used by Vixeny.