Giter Site home page Giter Site logo

aaronwlee / attain Goto Github PK

View Code? Open in Web Editor NEW
79.0 4.0 3.0 3.96 MB

Deno API middleware Server

Home Page: https://aaronwlee.github.io/Attain/

License: MIT License

TypeScript 98.47% HTML 0.16% Batchfile 0.56% Shell 0.81%
deno framework front-end back-end server server-side-rendering

attain's Introduction

attain

Attain - v1.1.2 - Website

attain ci license

nest badge

A middleware web framework for Deno which is using http standard library inspired by express and Oak.

Attain is blazingly fast due to handled the multi-structured middleware and routes effectively. It also strictly manage memory consumption.

Only for Deno - Require Deno version up to: v1.16.4

Any contributions to the code would be appreciated. :)


Download and use

import { App, Router } from "https://deno.land/x/attain/mod.ts";
// or
import { App, Router } from "https://deno.land/x/[email protected]/mod.ts";
// or
import { App, Router, Request, Response } from "https://raw.githubusercontent.com/aaronwlee/attain/1.1.2/mod.ts";
# deno run --allow-net --unstable main.ts

Contents

Getting Start

import { App } from "https://deno.land/x/attain/mod.ts";
import type { Request, Response } from "https://deno.land/x/attain/mod.ts";

const app = new App();

const sampleMiddleware = (req: Request, res: Response) => {
  console.log("before send");
};

app.get("/:id", (req, res) => {
  console.log(req.params);
  res.status(200).send(`id: ${req.params.id}`);
});

app.use(sampleMiddleware, (req, res) => {
  res.status(200).send({ status: "Good" });
});

app.listen({ port: 3500 });

Procedure explain

The middleware process the function step by step based on registered order.

alt text

import { App } from "https://deno.land/x/attain/mod.ts";

const app = new App();

const sleep = (time: number) => {
  return new Promise(resolve => setTimeout(() => resolve(), time)
};

app.use((req, res) => {
  console.log("First step");
}, async (req, res) => {
  await sleep(2000); // the current request procedure will stop here for two seconds.
  console.log("Second step");
});

app.use((req, res) => {
  // pend a job
  res.pend((afterReq, afterRes) => {
    console.log("Fourth step");
    console.log("Fifth step with error");
    console.log("You can finalize your procedure right before respond.")
    console.log("For instance, add a header or caching.")
  })
})

// last step
app.use("/", (req, res) => {
  console.log("Third step with GET '/'");
  // this is the end point
  res.status(200).send({status: "Good"});
});

app.use("/", (req, res) => {
  console.log("Will not executed");
});

app.get("/error", (req, res) => {
  console.log("Third step with GET '/error'");
  throw new Error("I have error!")
})

app.error((err, req, res) => {
  console.log("Fourth step with error");
  console.log("A sequence of error handling.", err)
  res.status(500).send("Critical error.");
})

app.listen({ port: 3500 });

How To

Web Socket Example

Auto Recovery

Boilerplate

A Deno web boilerplate by burhanahmeed

Methods and Properies

Response

Methods Getter

  • getResponse(): AttainResponse
    Get current response object, It will contain the body, status and headers.

  • headers(): Headers
    Get current header map

  • getStatus(): number | undefined
    Get current status

  • getBody(): Uint8Array
    Get current body contents

Functions

  • pend(...fn: CallBackType[]): void
    Pend the jobs. It'll start right before responding.

  • status(status: number)
    Set status number

  • body(body: ContentsType)
    Set body. Allows setting Uint8Array, Deno.Reader, string, object, boolean. This will not respond.

  • setHeaders(headers: Headers)
    You can overwrite the response header.

  • getHeader(name: string)
    Get a header from the response by key name.

  • setHeader(name: string, value: string)
    Set a header.

  • setContentType(type: string)
    This is a shortcut for the "Content-Type" in the header. It will try to find "Content-Type" from the header then set or append the values.

  • send(contents: ContentsType): Promise<void | this>
    Setting the body then executing the end() method.

  • await sendFile(filePath: string): Promise<void>
    Transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename's extension.
    Required to be await
    These response headers might be needed to set for fully functioning

Property Description
maxAge Sets the max-age property of the Cache-Control header in milliseconds or a string in ms format
root Root directory for relative filenames.
cacheControl Enable or disable setting Cache-Control response header.
  • await download(filePath: string, name?: string): Promise<void>
    Transfers the file at the path as an "attachment". Typically, browsers will prompt the user to download and save it as a name if provided.
    Required to be await

  • redirect(url: string | "back")
    Redirecting the current response.

  • end(): Promise<void>
    Executing the pended job then respond back to the current request. It'll end the current procedure.

Request

Oak for deno

This class used Oak's request library. Check this.
Note: to access Oak's Context.params use Request.params. but require to use a app.use(parser) plugin.

Router

Methods

  • use(app: App | Router): void
  • use(callBack: CallBackType): void
  • use(...callBack: CallBackType[]): void
  • use(url: string, callBack: CallBackType): void
  • use(url: string, ...callBack: CallBackType[]): void
  • use(url: string, app: App | Router): void
  • get...
  • post...
  • put...
  • patch...
  • delete...
  • error(app: App | Router): void;
  • error(callBack: ErrorCallBackType): void;
  • error(...callBack: ErrorCallBackType[]): void;
  • error(url: string, callBack: ErrorCallBackType): void;
  • error(url: string, ...callBack: ErrorCallBackType[]): void;
  • error(url: string, app: App | Router): void;
    It'll handle the error If thrown from one of the above procedures.

Example

app.use((req, res) => {
  throw new Error("Something wrong!");
});

app.error((error, req, res) => {
  console.error("I handle the Error!", error);
  res.status(500).send("It's critical!");
});
  • param(paramName: string, ...callback: ParamCallBackType[]): void;
    Parameter handler router.param

Example

const userController = new Router();

userController.param("username", (req, res, username) => {
  const user = await User.findOne({ username: username });
  if (!user) {
    throw new Error("user not found");
  }
  req.profile = user;
});

userController.get("/:username", (req, res) => {
  res.status(200).send({ profile: req.profile });
});

userController.post("/:username/follow", (req, res) => {
  const user = await User.findById(req.payload.id);
  if (user.following.indexOf(req.profile._id) === -1) {
    user.following.push(req.profile._id);
  }
  const profile = await user.save();
  return res.status(200).send({ profile: profile });
});

export default userController;

These are middleware methods and it's like express.js.

App

App extends Router Methods

  • This has all router's methods

Properties

  • listen(options)
    Start the Attain server.
  options: {
    port: number;             // required
    debug?: boolean;          // debug mode
    hostname?: string;        // hostname default as 0.0.0.0
    secure?: boolean;         // https use
    certFile?: string;        // if secure is true, it's required
    keyFile?: string;         // if secure is true, it's required
  }
  • database(dbCls) NEW FEATURE!
    Register a database to use in all of your middleware functions.
    Example:
/* ExampleDatabase.ts */
class ExampleDatabase extends AttainDatabase {
    async connect() {
        console.log('database connected');
    }
    async getAllUsers() {
        return [{ name: 'Shaun' }, { name: 'Mike' }];
    }
}

/* router.ts */
const router = new Router();

router.get('/', async (req: Request, res: Response, db: ExampleDatabase) => {
  const users = await db.getAllUsers();
  res.status(200).send(users);
})

/* index.ts */
const app = new App();

await app.database(ExampleDatabase);

app.use('/api/users', router);

NOTE: for this feature to work as expected, you must:

  • provide a connect() method to your database class
  • extend the AttainDatabase class

This feature is brand new and any contributins and ideas will be welcomed
  • static startWith(connectFunc) Automatically initialize the app and connect to the database with a connect function.

  • static startWith(dbClass) Automatically initialize the app create a database instance.

Nested Routing

Path - router.ts

warn: async await will block your procedures.

import { Router } from "https://deno.land/x/attain/mod.ts";

const api = new Router();
// or
// const api = new App();

const sleep = (time: number) => {
  new Promise((resolve) => setTimeout(() => resolve(), time));
};

// It will stop here for 1 second.
api.get("/block", async (req, res) => {
  console.log("here '/block'");
  await sleep(1000);
  res.status(200).send(`
  <!doctype html>
  <html lang="en">
    <body>
      <h1>Hello</h1>
    </body>
  </html>
  `);
});

// It will not stop here
api.get("/nonblock", (req, res) => {
  console.log("here '/nonblock'");
  sleep(1000).then((_) => {
    res.status(200).send(`
      <!doctype html>
      <html lang="en">
        <body>
          <h1>Hello</h1>
        </body>
      </html>
      `);
  });
});

export default api;

Path - main.ts

import { App } from "https://deno.land/x/attain/mod.ts";
import api from "./router.ts";

const app = new App();

// nested router applied
app.use("/api", api);

app.use((req, res) => {
  res.status(404).send("page not found");
});

app.listen({ port: 3500 });
# start with: deno run -A ./main.ts

Extra plugins

  • logger : Logging response "response - method - status - path - time"
  • parser : Parsing the request body and save it to request.params
  • security: Helping you make secure application by setting various HTTP headers Helmet

Security options

Options Default?
xss (adds some small XSS protections) yes
removePoweredBy (remove the X-Powered-By header) yes
DNSPrefetchControl (controls browser DNS prefetching) yes
noSniff (to keep clients from sniffing the MIME type) yes
frameguard (prevent clickjacking) yes
  • staticServe : It'll serve the static files from a provided path by joining the request path.

Out of box

import {
  App,
  logger,
  parser,
  security,
  staticServe,
} from "https://deno.land/x/Attain/mod.ts";

const app = new App();

// Set Extra Security setting
app.use(security());

// Logging response method status path time
app.use(logger);

// Parsing the request body and save it to request.params
// Also, updated to parse the queries from search params
app.use(parser);

// Serve static files
// This path must be started from your command line path.
app.use(staticServe("./public", { maxAge: 1000 }));

app.use("/", (req, res) => {
  res.status(200).send("hello");
});

app.use("/google", (req, res) => {
  res.redirect("https://www.google.ca");
});

app.use("/:id", (req, res) => {
  // This data has parsed by the embedded URL parser.
  console.log(req.params);
  res.status(200).send(`id: ${req.params.id}`);
});

app.post("/submit", (req, res) => {
  // By the parser middleware, the body and search query get parsed and saved.
  console.log(req.params);
  console.log(req.query);
  res.status(200).send({ data: "has received" });
});

app.listen({ port: 4000 });

More Features

Switch your database with just one line of code

Using the app.database() option, you can switch your database with just one line of code! To use this feature, create a database class that extends the AttainDatabase class:

class PostgresDatabase extends AttainDatabase {
  #client: Client
  async connect() {
    const client = new Client({
      user: Deno.env.get('USER'),
      database: Deno.env.get('DB'),
      hostname: Deno.env.get('HOST'),
      password: Deno.env.get('PASSWORD')!,
      port: parseInt(Deno.env.get('PORT')),
    });
    await client.connect();
    this.#client = client;
  }
  async getAllProducts() {
    const data = await this.#client.query('SELECT * FROM products');
    /* map data */
    return products;
  }
}

/* OR */
class MongoDatabase extends AttainDatabase {
  #Product: Collection<Product>
  async connect() {
     const client = new MongoClient();
     await client.connectWithUri(Deno.env.get('DB_URL'));
     const database = client.database(Deno.env.get('DB_NAME'));
     this.#Product = database.collection('Product');
  }
  async getAllProducts() {
    return await this.#Product.findAll()
  }
}

Then pick one of the databases to use in your app:

await app.database(MongoDatabase);
/* OR */
await app.database(PostgresDatabase);
/* OR */
const app = App.startWith(MongoDatabase);

app.get('/products', (req, res, db) => {
  const products = await db.getAllProducts();
  res.status(200).send(products); /* will work the same! */
})

You can also provide a function that returns a database connection

import { App, Router, Request, Response, AttainDatabase } from "./mod.ts";
import { MongoClient, Database } from "https://deno.land/x/[email protected]/mod.ts";

async function DB() {
  const client = new MongoClient()
  await client.connectWithUri("mongodb://localhost:27017")
  const database = client.database("test")
  return database;
}

// allow auto inherit mode (auto inherit the types to the middleware)

const app = App.startWith(DB);
// or
const app = new App<Database>()
app.database(DB)

// this db params will have automatically inherited types from the app<> or startWith method.
app.use((req, res, db) => {

})

There are several modules that are directly adapted from other modules. They have preserved their individual licenses and copyrights. All of the modules, including those directly adapted are licensed under the MIT License.

All additional work is copyright 2021 the Attain authors. All rights reserved.

attain's People

Contributors

aaronwlee avatar itays123 avatar tonypark0403 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

Watchers

 avatar  avatar  avatar  avatar

attain's Issues

v0.8 not working

error: Uncaught BadResource: Bad resource ID 
    at unwrapResponse ($deno$/ops/dispatch_minimal.ts:63:11)
    at Object.sendAsyncMinimal ($deno$/ops/dispatch_minimal.ts:106:10)
    at async Object.read ($deno$/ops/io.ts:39:17)
    at async Object.copy ($deno$/io.ts:64:20)
    at async writeResponse (https://deno.land/std/http/_io.ts:264:15)
    at async ServerRequest.respond (https://deno.land/std/http/server.ts:88:7)
    at async Process.finalize (https://deno.land/x/attain/process.ts:92:7)
    at async App.handleRequest (https://deno.land/x/attain/application.ts:18:5)

is there any way to hide the logs?

Hey, love this framework
& is there any way to turn off the logs because these things are awesome during the development but unnecessary during production.

{ method: "GET", url: "/block", callBack: [AsyncFunction] }
{ method: "GET", url: "/nonblock", callBack: [Function] }
{ method: "GET", url: "/nonblock", callBack: [Function] }
{ method: "ALL", callBack: [AsyncFunction: parser] }
{
 method: "ALL",
 url: "/api(.*)",
 next: [ { method: "GET", url: "/api/nonblock", callBack: [Function], next: undefined } ]
}
{
 method: "ALL",
 url: "/api/article(.*)",
 next: [
  {
    method: "GET",
    url: "/api/article/block",
    callBack: [AsyncFunction],
    next: undefined
   },
  {
    method: "GET",
    url: "/api/article/nonblock",
    callBack: [Function],
    next: undefined
   }
]
}
{ method: "ALL", callBack: [Function] }

I thing this will be the next express framework keep it up before you know it this will be the default framework for Deno

[bug] The rest of the route didnt work when the top route has middleware

I found another bug here. When I put a middleware within the first route, second route, third route, and so on didnt work, it always return to the first route.

When I access / endpoint, it return Hello Welcome to Deno.
When I access other endpoint /users and /query it also return Hello Welcome to Deno.

When I move the exampleMiddleware to second route, the /users endpoint works, the third route /query will return the same value as second route /users.

Suppose I have this code on my router

route.get('/', exampleMiddleware, (req: Request, res: Response) => {
    res.send({
        status: 200,
        text: 'Hello Welcome to Deno'
    })
});

route.get('/users', async (req: Request, res: Response) => {
    let getUsers = await users.getUsers();
    return res.send({
        status: 200,
        data: getUsers
    });
});

route.get('/query', (req: Request, res: Response) => {
    res.send({
        status: 200,
        text: 'Middleware query params passed'
    })
});

And here is my exampleMiddleware code

 function exampleMiddleware (req: Request, res: Response):any {
    if (!req.query) {
        return res.status(200).send({
            status: 500,
            response: 'Cant pass without query params'
        })
    }
 }

What returns on debug mode

{ method: "GET", url: "/", callBack: [Function: exampleMiddleware] }
{ method: "GET", callBack: [Function] }
{ method: "GET", url: "/users", callBack: [AsyncFunction] }
{ method: "GET", url: "/query", callBack: [Function] }
{ method: "ALL", callBack: [Function: logger] }
{ method: "ALL", callBack: [AsyncFunction: parser] }
{ method: "ALL", callBack: [AsyncFunction] }
{
 method: "ALL",
 url: "/api(.*)",
 next: [
  {
    method: "GET",
    url: "/api",
    callBack: [Function: exampleMiddleware],
    next: undefined
   },
  { method: "GET", callBack: [Function] },
  { method: "GET", url: "/api/users", callBack: [AsyncFunction], next: undefined },
  { method: "GET", url: "/api/query", callBack: [Function], next: undefined }
]
}
{ method: "ALL", url: "/", callBack: [Function] }
http://localhost:3500

Upgrade Attain to support Deno 1.4.0 and std 0.69.0

Issue description: ako-deno/negotiator#1

I beleaveThis also requires a number of attain's dependency updates

error: TS1205 [ERROR]: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
  Response
  ~~~~~~~~
    at https://deno.land/x/[email protected]/deps.ts:6:3

TS1205 [ERROR]: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
  Deferred
  ~~~~~~~~
    at https://deno.land/x/[email protected]/deps.ts:19:3

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { ErrorStatus } from "./types.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/httpError.ts:30:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import {
^
    at https://deno.land/x/[email protected]/core/response.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { AttainResponse, CallBackType } from "./types.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/response.ts:8:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request } from "./request.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/utils.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Response } from "./response.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/utils.ts:2:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { BufReader } from "./buf_reader.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/headers.ts:3:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { ServerRequest } from "../deps.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/request.ts:39:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { SupportMethodType } from "./types.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/request.ts:40:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Response as DenoResponse, Status } from "../deps.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/types.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request } from "./request.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/types.ts:2:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Response } from "./response.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/types.ts:3:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import {
^
    at https://deno.land/x/[email protected]/core/router.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { ErrorCallBackType } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/defaultHandler/defaultError.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { CallBackType } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/defaultHandler/defaultPageNotFound.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { ServerRequest } from "../deps.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/process.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import {
^
    at https://deno.land/x/[email protected]/core/process.ts:5:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { MiddlewareProps, ErrorMiddlewareProps } from "./types.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/debug.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { ListenProps, ThenArg } from "./types.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/application.ts:11:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { AttainDatabase, NoParamConstructor } from "./database.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/core/application.ts:16:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/plugins/parser.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/plugins/logger.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/plugins/staticServe.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/helmat/x-xxs-protection.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/helmat/hide-powered-by.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/helmat/dns-prefetch-control.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/helmat/dont-sniff-mimetype.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/helmat/frame-guard.ts:1:1

TS1371 [ERROR]: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
import { Request, Response } from "../mod.ts";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/plugins/security.ts:1:1

Found 30 errors.

Query params returns non-empty object on URL without query params

Hi, It's cool framework!

I recently create a web boilerplate with Attain, I find something weird behavior on req.query.
In ExpressJS when I have URL without query params, it returns empty object {} on console.log(req.query).
I try using Attain and it returns { : "" } on console.log(req.query). I am afraid if someone might need to check whether the url has query params using Object.keys(req.query).length it will return an error.
I don't know the best way to check query params exist or not besides using Object.keys(req.query).length or is there any plan to make kind of query params checker?

res.pend

what is res.pend, how its work

error: Import 'https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts' failed: 500 Internal Server Error

I tried to build Attain, but it doesn't work. Apparently, it is referring to a repository that does not exist.

Download https://deno.land/[email protected]/path/_constants.ts
Download https://deno.land/[email protected]/path/_util.ts
Download https://deno.land/[email protected]/path/_constants.ts
Download https://deno.land/[email protected]/path/_util.ts
Download https://deno.land/[email protected]/path/_constants.ts
Download https://deno.land/[email protected]/path/_util.ts
Download https://deno.land/[email protected]/path/_constants.ts
Download https://deno.land/[email protected]/path/_util.ts
Download https://deno.land/[email protected]/testing/diff.ts
Download https://deno.land/[email protected]/testing/diff.ts
Download https://deno.land/[email protected]/testing/diff.ts
Download https://deno.land/[email protected]/testing/diff.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/http/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
Download https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts
error: Import 'https://cdn.pika.dev/-/[email protected]/dist=es2019,mode=types/index.d.ts' failed: 500 Internal Server Error

Absence of error handling route

In an Express Node.js application I would specify an error handling route like this:

app.use(function(err, req, res, next) {
        //error handling stuff here
});

and I would expect this to run as the next handler whenever I throw an Error in one of my routes. However, this feature doesn't seem to be present in Attain. I get the following error upon compilation:

No overload matches this call.
  The last overload gave the following error.
    Argument of type '(err: any, req: any, res: any, next: any) => void' is not assignable to parameter of type 'string'.ts(2769)

I can work around this problem by adding some try-catch statements around my code but let me know if there's a better solution I have not thought of. Thanks!

How to handle global deno error?

How to keep app running then connection to db was lost? For now deno process is just die.

//connect ot DB
var db=await connect(...)

const app = new App()
app.use((req,res)=>{...})

TS2345 error while trying to run the cli

Hello there!
I was trying to run your CLI with the command you put in your repo:
$ deno install -A -f --unstable -n attain https://deno.land/x/[email protected]/attain-cli.ts

when I did, deno cached all of the dependencies and then outputted this error:
error: TS2345 [ERROR]: Argument of type '{ depth: number; sorted: boolean; trailingComma: boolean; compact: boolean; iterableLimit: number; }' is not assignable to parameter of type 'InspectOptions'. Object literal may only specify known properties, and 'sorted' does not exist in type 'InspectOptions'. sorted: true, ~~~~~~~~~~~~ at https://deno.land/[email protected]/testing/asserts.ts:26:9

are you familiar with this problem? I also tried to run v1.0.0 but it outputted the same problem again.

CORS middleware

I think we need CORS middleware to allow access from other server/client.

Query parameters cannot be parsed out of the box

In express for example, a route like /hello?name=JohnSmith, can be parsed using req.query to get an object {name: "JohnSmith"}.

I can't find anything similar in Attain. I am aware of the parser plugin, but it only parses the body.

TS2345 [ERROR]: Argument of type 'string | URL' is not assignable to parameter of type 'string'.

Hello
I try to do a simple exercise with deno and Attain and I've had this error

`error: TS2345 [ERROR]: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.
return new URL(url).pathname
~~~
at https://deno.land/[email protected]/path/win32.ts:911:18

TS2345 [ERROR]: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.
return new URL(url).pathname;
~~~
at https://deno.land/[email protected]/path/posix.ts:433:18

Found 2 errors.`

Mi code is this:

`import { App } from 'https://deno.land/x/attain/mod.ts';

const app = new App();

app.listen( {
port: 3000
})

console.log('server running localhost:3000')`

I don't understand what happens, Is possible a global error?

Thanks!

deno-ts(2345)

My code:

import { App, Router } from "https://deno.land/x/[email protected]/mod.ts";


const app = new App();


app.get("/:id", (req, res) => {
    console.log(req.params);
    res.status(200).send(`id: ${req.params.id}`);
});


app.listen({ port: 1001 }); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Error: Argument of type '{ port: number; }' is not assignable to parameter of type 'number'.deno-ts(2345)

error: TS2502 [ERROR]:

error: TS2502 [ERROR]: 'thisArg' is referenced directly or indirectly in its own type annotation.
bind(this: T, thisArg: ThisParameterType): OmitThisParameter;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at asset:///lib.es5.d.ts:350:22

TS2577 [ERROR]: Return type annotation circularly references itself.
bind(this: T, thisArg: ThisParameterType): OmitThisParameter;
~~~~~~~~~~~~~~~~~~~~
at asset:///lib.es5.d.ts:350:54

TS2339 [ERROR]: Property 'transpileOnly' does not exist on type 'typeof Deno'.
const result = await Deno.transpileOnly({
~~~~~~~~~~~~~
at https://deno.land/x/[email protected]/viewEngine/ReactCompiler.ts:118:33

Found 3 errors.

Suggestion: A database support

I was thinking, what if we could do something like this:
class MyDatabase implements AttainDatabase { /* methods for communicating with the database, such as: */ async findAllUsers(){ return await database.query('SELECT * FROM users'); } }

the AttainDatabase interface will contain a connect method.

and then, provide a method with a generic class that implemets AttainDatabase:
app.database<MyDatabase>()

and provide a database instance in the handler functions!
that way, you will be able to change your database with just one line of code!

consider refering to my repo where I did something similar

thoughts?

routing url pattern not working

Looks line this not working then I request from browser: /js/index.js but if i just simple request /js then working first middleware.

app.use("/js",(req,res)=>{...});

or

app.use("/js*",(req,res)=>{...});

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.