Fen

Build Status GitHub tag (latest SemVer) GitHub tag (latest SemVer)

A simple web framework for deno.

Welcome to join us or give your advice

Now I'm working on sqlflow (use sql to train ai) so this project will get less maintain.

Logo

How 2 use

First you should install deno:

curl -fsSL https://deno.land/x/install/install.sh | sh

Try it with https://deno.land/x/fen/ to import!

Test if it's work:

import { Server } from "https://deno.land/x/fen@v0.7.2/server.ts";

const s = new Server();

s.port = 1882;

s.start();

Add your own controller

import { Server } from "https://deno.land/x/fen@v0.7.2/server.ts";

const s = new Server();

// pls keep in mind that you may add an async function as controller
s.setController(async context => {
  context.body = "It's alive!";
});

s.port = 1882;

s.start();

Then roll with the deno!

deno ${yours}.ts -A

About Context

Context is the only way now to pass data and get data.

{
 // ---- All from ServerRequest
  url,
  method,
  proto,
  headers,
  conn,
  reader,
  writer,
 // ----
  request,
  path, // url path without params and ip:port
  params, // Map<string, string>  params in url
  data: new Map<string, any>(),
  body: "",// respond body
  status: 200,// respond status
  config: {
    disableRespond: false, // disable fen's respond
    disableBodyEncode: false,
    disableContentType: false,
    mimeType: "text/plain",
    charset: "utf-8"
  },
  reqBody, // request body(after try to decode)
  originBody, // request body
  logger, // logger
  throw(code, message) // throw an http error
};

About Process

process is a series of process between controller, you can develop your own process;

Session Process

It's a simple session for Fen, using session(a map) to store data.

import { Server } from "https://deno.land/x/fen@v0.7.2/server.ts";
import { Session } from "https://deno.land/x/fen@v0.7.2/process/session.ts";

const session = new Session();

const s = new Server();

s.addProcess(session.process);

s.port = 1882;

s.setController(async context => {
  const session = context.data.get("session");
  let c = session.get("c") || 1;

  if (context.path === "/") {
    session.set("c", c + 1);
  }

  context.body = `It\'s alive for path '/' ${c} times in this browser!`;
});

s.start();

About Tool

Tool is a series function that help to do sth with controller

As you can see in Session

const cookie = cookieReader(cookie);
setCookie.append("set-cookie", cookie2String(cookie));

Router

In fen we provide a way to arrange route, router tool.

This example shows many way to use router

import { Server } from "https://github.com/fen-land/deno-fen/raw/master//server.ts";
import { Router } from "https://github.com/fen-land/deno-fen/raw/master//tool/router.ts";

const s = new Server();

s.port = 1882;

s.logger.changeLevel("ALL");

let mergeRouter = new Router("merge");

mergeRouter
  .get(
    "/",
    async context =>
      (context.body = `${context.data.get("router").name} in ${
        context.data.get("router").route
      }`)
  )
  .post(
    "/",
    async context =>
      (context.body = `POST ${context.data.get("router").name} in ${
        context.data.get("router").route
      }`)
  )
  .get(
    "me",
    async context =>
      (context.body = `${context.data.get("router").name} in ${
        context.data.get("router").route
      }`)
  );

let router = new Router();

router
  .get("/:id", async context => {
    context.body = `we have ${JSON.stringify(
      context.data.get("router").params
    )} in ${context.data.get("router").route}`;
  })
  .get("/:id/:name", async context => {
    context.body = `we have ${JSON.stringify(
      context.data.get("router").params
    )} in ${context.data.get("router").route}`;
  })
  .get("/hello/:name", async context => {
    context.body = `hello ${context.data.get("router").params.name} in ${
      context.data.get("router").route
    }`;
  })
  .use({
    "/use": {
      get: async context =>
        (context.body = `use in ${context.data.get("router").route}`)
    }
  })
  .merge("/merge", mergeRouter);
s.setController(router.controller);

s.start();

Router now support these method:

    use(route: IRoute) // a way to add route
    // IRoute just like:
    // {[path]: {[method]: async function controller(cxt)}}
    merge(route: string, router:Router) // merge other router by add prefix route
    get
    post
    head
    put
    delete
    connect
    options
    trace

Logger

In fen we provide a way to log info through logger we provide. Logger now have 5 level for log to help you develop. You can access them on context.logger .

    'ALL':  Display all log,
    'TRACE': trace some detail,
    'DEBUG': log to help you debug,
    'INFO': normal info for you,
    'WARN': simple warn,
    'ERROR': error that won't stop the server,
    'FATAL': once it happened, server won't work,
    'OFF': Disable all log

You can change log level by changeLevel, logger also can access on Server instance

logger.changeLevel("ALL");

Static

We provide a tool for static file, it will generate a controller for server(or router).

import { Server } from "https://github.com/fen-land/deno-fen/raw/master//server.ts";
import { staticProcess } from "https://github.com/fen-land/deno-fen/raw/master//tool/static.ts";

const s = new Server();

s.port = 1882;
// it will respond file from the path where deno run
s.setController(staticProcess({ root: "" }));

s.start();

and here is some of the option you can fit in

{
    root: root path of the file,
    maxAge: (s),
    allowHidden: allow access hidden file,
    index: access if no file name provide 'index.html',
    immutable: immutable in cache-control,
    pathRender: (path) => afterpath, if you want do sth. with path
};

Update Log


View repository on GitHub