qoq-ts / qoq

A TS-Only node framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

QOQ

A restful node framework for real type checking, a new way for avoiding syntax mistake and saving life. It's based on popular koa2, almostly the total middlewares can be integrated into here.


🔥 no typescript, no coding.


License GitHub Workflow Status (branch) Codecov npm

Features

  • web router
  • console commander
  • validator
  • caching
  • slot
  • strong type-checking

Installation

yarn add qoq

Official Related

Project Version Platform Description
qoq-redis npm Web, Console redis command, cache extension
qoq-compress npm Web gzip, brotli
qoq-morgan npm Web logger
qoq-cors npm Web CORS
qoq-ratelimit npm Web request rate limiter
qoq-jwt npm Web validating json token
qoq-etag npm Web header: etag
qoq-response-time npm Web header: X-Response-Time
qoq-helmet npm Web security headers
qoq-pretty-json npm Web format JSON
qoq-static npm Web static file serve
qoq-views npm Web template rendering
qoq-json-error npm Web JSON error handler

And more from koa community...

Demos

Hello World

Usage

Create web app

// src/index.ts
import { WebApplication } from 'qoq';

const app = new WebApplication();

app.listen(3000, () => {
  console.log('Server started!');
});

Create web slots (middleware)

// src/bootstrap/web.ts
import { WebSlotManager, Tree } from 'qoq';
import { Cors } from 'qoq-cors';
import { Redis } from 'qoq-redis';

export const webSlots = WebslotManager
  .use(new Cors())
  .use(new Redis())
  .use((ctx, next) => {
    console.log(ctx.request.ip);
    return next();
  });
export const advancedSlots = webSlots.use(...).use(...);

// the trunk will always run through
// until slot or router interrput it ( by skip execute next() ).
Tree.trunk(advancedSlots);

Create web router

// src/routers/index.ts
import { WebRouter, validator } from 'qoq';
import { webSlots } from '../bootstrap/web';

export const router = new WebRouter({
  prefix: '/',
  // slots behind webSlots will be convert to router group slots
  slots: webSlots.use(new CustomSlot()).use(...),
});

router
  .get('/user/:id')
  .params({
    id: validator.number,
  })
  .action(async (ctx, payload) => {
    const userId = payload.params.id; // TS type annotation: number
    const user = await ctx.redis.get(`user-${userId}`);

    !user && ctx.throw(400, 'user not found');
    ctx.body = user;
  });

router
  .get('/users')
  .query({
    // page is required, otherwise a 400 bad-request error will be thrown.
    page: validator.number,
    // pageSize is optional and will set to 10 when data is undefined/null.
    pageSize: validator.number.default(10),
  })
  .action(async (ctx, payload) => {
    // TS type annotation: { page: number; pageSize: number }
    const { page, pageSize } = payload.query;
    const users = await User.findAll({
      offset: (page - 1) * pageSize,
      limit: pageSize,
    });

    ctx.body = users;
  });

router
  .post('/user')
  .body({
    name: validator.string,
    vip: validator.boolean.default(false),
    homepage: validator.url.optional(),
  })
  .action(async (ctx, payload) => {
    // TS type annotation of body: { name: string; vip: boolean; homepage?: string }
    const user = await User.create(payload.body);

    ctx.status = 201;
    ctx.body = user;
  });

Create console app

// src/index.ts
import { ConsoleApplication } from 'qoq';

const app = new ConsoleApplication();

app.execute().then(() => {
  // Optional invoke here.
  process.exit(0);
});

Create console router

// src/commands/index.ts
import { ConsoleRouter, validator } from 'qoq';
import { webSlots } from '../bootstrap/web';

export const router = new ConsoleRouter({
  prefix: '/',
  slots: consoleSlots
    // as router group slots
    .use(new CustomSlot()),
});

router
  .command('my:schedule')
  .options({
    dateFrom: validator.string.optional(),
    dateTo: validator.string.optional(),
  })
  .alias({
    f: 'dateFrom',
    t: 'dateTo',
  })
  .action(async (ctx, payload) => {
    // TS type annotation: { dateFrom?: string; dateTo?: string }
    const { dateFrom, dateTo } = payload.options;

    // ...your business
    console.log('Done!');
  });

You can execute this command like this:

npx qoq my:schedule
# or
npx qoq my:schedule --dateFrom '..' --dateTo '..'
# or
npx qoq my:schedule -f '..' -t '..'

For testing, feel free to execute command as follows:

test ('can do something', async () => {
  const app = new ConsoleApplication();
  const ctx = await app.execute('my:schedule', '-f', '..', '-t', '..');
  expect(...);
});

Cli

npx qoq -h
# or
yarn qoq -h
# or
node ./src/console.js -h
# or
ts-node ./src/console.ts -h

About

A TS-Only node framework

License:MIT License


Languages

Language:TypeScript 98.4%Language:JavaScript 1.6%