GithubHelp home page GithubHelp logo

oakserver / oak Goto Github PK

View Code? Open in Web Editor NEW
5.0K 40.0 227.0 52.53 MB

A middleware framework for handling HTTP with Deno, Node, Bun and Cloudflare Workers 🐿️ 🦕

Home Page: https://oakserver.github.io/oak/

License: MIT License

TypeScript 99.84% HTML 0.02% Dockerfile 0.14%
middleware-framework deno http-server oak router-middleware middleware-frameworks

oak's Issues

GraphQL

It will be nice to have GraphQL middleware. I'd like to help with it.

ErrorEvent is not defined

Hello, I'm trying to use error handler, however I'm not able to use it

Can anyone help?

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use((ctx) => {
  ctx.throw(500);// Uncaught ReferenceError: ErrorEvent is not defined
});

app.addEventListener("error", (evt) => {
  console.log(evt.error);
});

await app.listen({ port: 8000 });

Stdout:
image

Property 'params' does not exist on type 'Context<Record<string, any>>'

The documentation shows "params" as a variable attached to the "context", but the type definition is missing the params for some reason, so the question is, are there two different types of context in the module? why does using context without explicit type works, but when giving an explicit type it fails?

using deno 1.0

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

const router = new Router();

// Breaks when compiling...
router.get('/', (ctx: Context) => {
  console.log(ctx.params);
})

// Doesn't break when compiling
router.get('/', ctx => {
  console.log(ctx.params);
})

Seems like the issue is simply that the field doesn't exist on the Context class, so to fix it we just need to add "params: Record<string, any>" to the class in this file...
https://github.com/oakserver/oak/blob/master/context.ts

🐞 Can't run examples

Both of the examples fail with both Deno 0.10 and 0.11 with the following errors;

$ deno index.ts --allow-read --allow-net
Compile file:///Users/bevan/projects/denoworld/index.ts

error TS2694: Namespace 'Deno' has no exported member 'ReadResult'.

► https://deno.land/[email protected]/io/bufio.ts:7:24

7 type ReadResult = Deno.ReadResult;
                         ~~~~~~~~~~

error TS2339: Property 'nread' does not exist on type 'number'.

► https://deno.land/[email protected]/io/bufio.ts:134:19

134         assert(rr.nread >= 0, "negative read");
                      ~~~~~


Found 2 errors.

On macos 10.13.6 High Sierra;

$ deno version
deno: 0.12.0
v8: 7.7.200
typescript: 3.5.1

Q&A: Middleware for error handling

If I wanted to throw a 500 error through my oak based API, how would I catch an error an being able to return it without Deno throwing as well?

Something like this in oak, would be nice:

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    //Resolve error here
  }
});

Q&A: Router prefix problem

Hello!
So I've been trying to use oak to tinker arround and found either a bug or I'm using it in an incorrect way.
I have the following router :

const TodoRouter = new Router({
    prefix: '/api/todo'
}); 

TodoRouter.get('/' , async (ctx) => {
    console.log('api')
    ctx.response.body = "Hello world"
} )

What I expected : doing a Get request to localhost:port/api/todo would return "Hello World"
What happened : Doing a Get Request to localhost:port/api/todo return nothing
image

So my Question is, when using a Router without a Prefix, the '/' route, work for either localhost:port and localhost:port/ so I would assume that with a prefix works the same, with that in mind is this the correct behaviour or a bug?
Thanks in advance

ctx.request.body() is not working

Thank you for this beautiful work!

Anyway I call ctx.request.body() forces the endpoint to Error out and not console.log() or add a response body

import { Application, Router } from "https://deno.land/x/oak/mod.ts"

let port = 8084,
    router = new Router(),
    app = new Application()

router
  .post('/wtf', async ctx => {
    let body = await ctx.request.body()
    console.log(body)
    ctx.response.body = { hello: 'world' }
  })

app.use(router.routes())
app.use(router.allowedMethods())

app.listen(`0.0.0.0:${ port }`)

Q&A: Can you close the server manually?

Thanks for maintaining this project!

I want to close down the Oak server each test.

application.use(...routes);
application.listen({ port });
test_code(port); 
application.close(); // <-- Something like this 

Is this possible?

Olav

Using ctx.throw() inside router doesn't work as expected

version: 4.0.0

The issue is, the error is expected to be caught, and it is when throwing from app.use(), but when called from the router, the error makes the server crash.

const router = new Router();

app.use(async (ctx, next) => {
   try {
      await next();
   } catch(err) {
      console.log(err); // <-- this is not called
   }
})

// I throw an error here and expect it to be caught, or sent to the client, but the server crashes instead
router.get(ctx => ctx.throw(500));

app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

Can't run Hello World example

I have copy pasted from the docs to to remove my sketchy typing from the equation :)

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use((ctx) => {
  ctx.response.body = "Hello world!";
});

await app.listen("127.0.0.1:8000");

then running deno run --allow-net server.ts

I get 25 errors after compilation that I can paste below for reference:

error TS2322: Type '(_: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.

https://deno.land/[email protected]/http/_io.ts:10:5

10 read(_: Uint8Array): Promise<number | null> {
~~~~

error TS2322: Type '(buf: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.

https://deno.land/[email protected]/http/_io.ts:35:12

35 return { read };
~~~~

error TS2322: Type '(buf: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.

https://deno.land/[email protected]/http/_io.ts:113:12

113 return { read };
~~~~

error TS2339: Property 'iter' does not exist on type 'typeof Deno'.

https://deno.land/[email protected]/http/_io.ts:167:34

167 for await (const chunk of Deno.iter(r)) {
~~~~

error TS2345: Argument of type 'Reader' is not assignable to parameter of type 'Writer'.
Property 'write' is missing in type 'Reader' but required in type 'Writer'.

https://deno.land/[email protected]/http/_io.ts:265:31

265 const n = await Deno.copy(r.body, writer);
~~~~~~

'write' is declared here.

► $asset$/lib.deno.ns.d.ts:504:5

504     write(p: Uint8Array): Promise<number>;
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error TS2339: Property 'listenTls' does not exist on type 'typeof Deno'.

https://deno.land/[email protected]/http/server.ts:16:17

16 const { listen, listenTls } = Deno;
~~~~~~~~~

error TS2694: Namespace 'Deno' has no exported member 'ListenTlsOptions'.

https://deno.land/[email protected]/http/server.ts:289:38

289 export type HTTPSOptions = Omit<Deno.ListenTlsOptions, "transport">;
~~~~~~~~~~~~~~~~

error TS2694: Namespace 'Deno' has no exported member 'ListenTlsOptions'.

https://deno.land/[email protected]/http/server.ts:309:26

309 const tlsOptions: Deno.ListenTlsOptions = {
~~~~~~~~~~~~~~~~

error TS2694: Namespace 'Deno' has no exported member 'WriterSync'.

https://deno.land/[email protected]/io/bufio.ts:8:24

8 type WriterSync = Deno.WriterSync;
~~~~~~~~~~

error TS2469: The '>=' operator cannot be applied to type 'symbol'.

https://deno.land/[email protected]/io/bufio.ts:90:14

90 assert(rr >= 0, "negative read");
~~

error TS2365: Operator '+=' cannot be applied to types 'number' and 'number | unique symbol'.

https://deno.land/[email protected]/io/bufio.ts:91:7

91 this.w += rr;
~~~~~~~~~~~~

error TS2469: The '>' operator cannot be applied to type 'symbol'.

https://deno.land/[email protected]/io/bufio.ts:92:11

92 if (rr > 0) {
~~

error TS2416: Property 'read' in type 'BufReader' is not assignable to the same property in base type 'Reader'.
Type '(p: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.
Type 'number | null' is not assignable to type 'number | unique symbol'.
Type 'null' is not assignable to type 'number | unique symbol'.

https://deno.land/[email protected]/io/bufio.ts:123:9

123 async read(p: Uint8Array): Promise<number | null> {
~~~~

error TS2469: The '>=' operator cannot be applied to type 'symbol'.

https://deno.land/[email protected]/io/bufio.ts:133:16

133 assert(nread >= 0, "negative read");
~~~~~

error TS2322: Type 'number | unique symbol' is not assignable to type 'number | null'.
Type 'unique symbol' is not assignable to type 'number | null'.

https://deno.land/[email protected]/io/bufio.ts:138:9

138 return rr;
~~~~~~~~~~

error TS2322: Type 'number | unique symbol' is not assignable to type 'number | null'.
Type 'unique symbol' is not assignable to type 'number | null'.

https://deno.land/[email protected]/io/bufio.ts:145:7

145 rr = await this.rd.read(this.buf);
~~

error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.

https://deno.land/[email protected]/path/_constants.ts:51:19

51 const isWindows = build.os == "windows";
~~~~~~~~~~~~~~~~~~~~~

error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.

https://deno.land/[email protected]/path/_globrex.ts:5:15

5 const isWin = Deno.build.os === "windows";
~~~~~~~~~~~~~~~~~~~~~~~~~~~

error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.

https://deno.land/[email protected]/path/mod.ts:7:19

7 const isWindows = Deno.build.os == "windows";
~~~~~~~~~~~~~~~~~~~~~~~~~~

error TS2345: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.

https://deno.land/[email protected]/path/posix.ts:433:18

433 return new URL(url).pathname;
~~~

error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.

https://deno.land/[email protected]/path/separator.ts:2:19

2 const isWindows = Deno.build.os == "windows";
~~~~~~~~~~~~~~~~~~~~~~~~~~

error TS2339: Property 'get' does not exist on type '{ (): { [index: string]: string; }; (key: string): string | undefined; }'.

https://deno.land/[email protected]/path/win32.ts:42:18

42 path = env.get(=${resolvedDevice}) || cwd();
~~~

error TS2345: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.

https://deno.land/[email protected]/path/win32.ts:911:18

911 return new URL(url).pathname
~~~

error TS2339: Property 'mtime' does not exist on type 'FileInfo'.

https://deno.land/x/oak/send.ts:151:55

151 if (!response.headers.has("Last-Modified") && stats.mtime) {
~~~~~

error TS2339: Property 'mtime' does not exist on type 'FileInfo'.

https://deno.land/x/oak/send.ts:152:49

152 response.headers.set("Last-Modified", stats.mtime.toUTCString());
~~~~~

Router post does not work.

Hi,

I am new to deno and oak.

The below code doesnt work for post method but WORKS for get.

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

const router = new Router();
router
  .post("/", context => {
    context.response.body = "Hello world Johnson!";
  });

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen("127.0.0.1:8000");

Any thoughts on this? Thanks in advance.

Unpin deno_std dependencies

I'm not suggesting to disregard the deno_std version altogether, but ass of right now - without #19 -oak is incompatible with the latest version of Deno because all deps are pinned to v0.9.0. Obviously there are major benefits to having releases pinned to the Deno runtime version it was developed for, but it would be nice to at least have a version of oak without the dependencies pinned to a specific Deno version.

This could be in the form of the master branch or a latest/unpinned tagged release that keeps getting updated.

value is coming as Uint8Array

I am trying to make post request for login and, sending body with postman. But request.body().value returns a Uint8Array, because of this, i can't handle username and passoword.

Here is how i sent the data by using postman
Ekran Alıntısı3

Here is my code
Ekran Alıntısı
Ekran Alıntısı1

TypeScript compiler error in Router example in README.md

Steps to reproduce

  1. Copy exmaple from https://deno.land/x/oak/#router
  2. Run code
error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  Type 'undefined' is not assignable to type 'string'.

► file:///Users/calebmchenry/code/sandbox/deno-server/src/server.ts:20:41

20       context.response.body = books.get(context.params.id);

Edit:
deno --version

deno 0.40.0
v8 8.2.308
typescript 3.8.3

error: Uncaught PermissionDenied: network access to "127.0.0.1:8000", run again with the --allow-net flag

Hey, guys, how are you?
I'm starting my studies with the deno and I came across the following message: what could be wrong?

peidrao in deno on  master [?] took 11s 
❯ sudo deno helloDenos.ts
Compile file:///home/peidrao/deno/helloDenos.ts
error: Uncaught PermissionDenied: network access to "127.0.0.1:3000", run again with the --allow-net flag
► $deno$/ops/dispatch_json.ts:43:11
    at PermissionDenied ($deno$/errors.ts:81:5)
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at sendSync ($deno$/ops/dispatch_json.ts:72:10)
    at listen ($deno$/ops/net.ts:50:10)
    at listen ($deno$/net.ts:168:18)
    at serve (server.ts:251:20)
    at listen (application.ts:29:25)
    at helloDenos.ts:8:5

Request body middleware

I wanted to make simple REST API with oak but noticed that there is no body field on Request, or worse any way to access underlying ServerRequest's body. I guess body parsing middleware is missing.

Pass through Reader response body type to Deno's HTTP server

Deno's current Response interface allows Reader as the body type.

/**
 * Interface of HTTP server response.
 * If body is a Reader, response would be chunked.
 * If body is a string, it would be UTF-8 encoded by default.
 */
export interface Response {
  status?: number;
  headers?: Headers;
  body?: Uint8Array | Reader | string;
}

This would be convenient to have in oak since, for example, dejs renders its templates to a Reader.

Route handlers with query params not matching

Hi,

Apologies if am doing this incorrectly. Noticing route handlers with query params are not matching.

Can reproduce this through examples/routingServer.ts:

  1. Remove the code block 40-42:
  // .get("/book", async (context) => {
  //   context.response.body = Array.from(books.values());
  // })
  1. Query the server (am using postman): GET http://127.0.0.1:8000/book?id=1234
  2. Observe that the server returns 404 Not Found

Error: Type 'Boolean' has no call signatures.

What was done

A file called app.ts was created with the following code:

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use(ctx => {
  ctx.response.body = "Hello World!";
});

console.log("Listening.....");
await app.listen({ port: 8000 });

Subsequently, the following command was executed:

deno --allow-net app.ts

Expected output

Expected deno to compile the code successfully and see the following line in stdout:

Listening.....

Actual Output

Compilation failed with the following error:

Compile file:///home/angad/Desktop/covidcomm/covidcomm/app.ts
error TS2349: This expression is not callable.
  Type 'Boolean' has no call signatures.

► https://deno.land/x/oak/send.ts:62:36

62     return (await Deno.stat(path)).isFile();
                                      ~~~~~~

error TS2349: This expression is not callable.
  Type 'Boolean' has no call signatures.

► https://deno.land/x/oak/send.ts:139:15

139     if (stats.isDirectory()) {
                  ~~~~~~~~~~~


Found 2 errors.

Error screenshot:
image

Environment

Package Version
deno 0.41.0
v8 8.2.308
typescript 3.8.3

image

Is it possible to handle BrokenPipe errors?

There doesn't seem to be a way to handle BrokenPipe errors thrown in std/http/server.ts for individual requests from oak without modifying the Application class. The error occurs if the HTTP client closes the connection prematurely.

Here is an example.

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

console.log("Starting...");

const router = new Router();
const veryLong = "foo bar baz qux ".repeat(1000000);

router.get("/demo", async ctx => {
  ctx.response.type = "text/html; charset=utf-8";
  ctx.response.body = `<h1>Hello!</h1>\n${veryLong}`;
});

const app = new Application();
app
  .use(router.routes())
  .use(router.allowedMethods())
  .listen("localhost:8080");

Save the code above as demo.ts and run the following shell commands to reproduce the error.

> deno --version
deno 0.31.0
v8 8.1.108
typescript 3.7.2
> deno --allow-net demo.ts &
> Compile file:///home/dbohdan/demo.ts
Starting...
> curl http://localhost:8080/demo & sleep 0.1; killall curl
> error: Uncaught BrokenPipe: Broken pipe (os error 32)   
► $deno$/dispatch_minimal.ts:59:11
    at DenoError ($deno$/errors.ts:20:5)
    at unwrapResponse ($deno$/dispatch_minimal.ts:59:11)
    at sendAsyncMinimal ($deno$/dispatch_minimal.ts:102:10)
fish: Job 2, “curl http://localhost:8080/demo…” terminated by signal SIGTERM (Polite quit request)
Job 1, 'deno --allow-net demo.ts &' has ended

Feature Request: Cookie support

I hope some easy cookie handler could be implemented just like koa did.

app.use(async (ctx) => {
  ctx.cookies.get('key'); // => "value" | undefined

  ctx.cookies.set('key', 'value', { httpOnly: true });
  // => set `Set-Cookie` header automatically
})

Is there any API documentation available?

Hi team,
great work! I am getting started with oak these days and looking for some materials, like API documentation. Is there any official API documentation available?
All the best,
Florian

Router prefix

Based on the RouterOptions interface, it seems like I should be able to specify a prefix for a router by declaring a new router like so:

const router = new Router({
    prefix: 'example',
});

However, it seems the Router constructor doesn't actually do anything with the prefix router option.

I cloned the repo and fixed this for personal use. If you're interested I could create a PR. Do you already have this addition on your radar?

Bodyless response

I'm developing simple API with oak, I want to return simple 404 response.

function notFound(context: Context) {
    context.response.status = Status.NotFound;
}

code above causes server to hang because there is no body in response.

If you do:

function notFound(context: Context) {
    context.response.status = Status.NotFound;
    context.response.body = "";
}

everything's working correctly.

Is this a bug or did I forget about something?

Use tag releases for ease of use

Hey @kitsonk !

Currently I'm using git commit hash to fix to a version (ex: Deno v0.42, 1.0.0 rc2, etc) so I can use it in my project, but it would be way better to have a tag to fix to.

Proxy middleware

I'd like to use Oak to proxy API requests onto another server, while overriding some with other responses and/or serving up local static assets for others. A proxy middleware would be nice.

Serving static files

Trying to serve static files using this code snippet in the README.md yield the following error.

app.use(async (context) => { await send(context, context.request.path, { root: "./static", index: "index.html", }); });

Error.
error TS2339: Property 'path' does not exist on type 'Request'. await send(context, context.request.path, {

The second post JSON will result in 404 errors

I started a server with the following code.

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

async function server() {
  const app = new Application();
  const router = new Router();
  router.post("/json", async ctx => {
    ctx.response.body = "test";
  });
  app.use(router.routes());
  await app.listen(`0.0.0.0:5000`);
}
server();

But when I submit requests usingPOST and application/json. The first time I get the right response, however, all subsequent requests will get 404 errors

However, when I use curl access, it seems normal. It only happens on the browser and postman. I guess it's related to the reuse of connections.

errorStatus and Status are not comparable

The example for ErrorHandling in the readme does not work, stating that Type 'Status.NotFound' is not comparable to type 'ErrorStatus'.

This is the said part of the readme

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    if (isHttpError(err)) {
      switch (err.status) {
        case Status.NotFound:
          // handle NotFound
          break;
        default:
        // handle other statuses
      }
    } else {
      // rethrow if you can't handle the error
      throw err;
    }
  }
});

The fix that I could come up with is not pretty and is to cast err.status as Status but that is only possible by casting into unknown first and then into Status

switch (err.status as unknown as Status) {

Am I missing something?

Wrong concurrency model

This is a piece of code from Oak:

https://github.com/oakserver/oak/blob/master/application.ts#L25-L35

This incorrectly uses await for each request. As a result, requests cannot be executed in parallel, but are executed serially. If two requests are sent in succession, each of which takes 10s, eventually all requests will be completed in 20s instead of all being completed at the same time in 10s

import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use(async ctx => {
  await new Promise(resolve => setTimeout(resolve, 10000));
  ctx.response.body = "Hello World!";
});
await app.listen({ port: 8000 });

Deno on Win 10 TS Error

Hi Everyone,

I am try Oak middleware as as example below:

import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use((ctx) => {
  ctx.response.body = "Hello world!";
});
await app.listen("127.0.0.1:8000");

I already install typescript as global npm install -g typescript, and run Deno on terminal with deno --allow-net .\oak.ts, my operating system Win 10 is latest version update, and i also try running as Administrator or another user on terminal and with same Error output, anyone can point some best a away..?, thanks in advance

Error appear as below:

Compile file:///D:/deno-sample/oak.ts
error TS2322: Type '(_: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
  Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.

► https://deno.land/[email protected]/http/_io.ts:10:5

10     read(_: Uint8Array): Promise<number | null> {
       ~~~~
error TS2322: Type '(buf: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.  Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.

► https://deno.land/[email protected]/http/_io.ts:35:12

35   return { read };
              ~~~~
error TS2322: Type '(buf: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.  Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.
► https://deno.land/[email protected]/http/_io.ts:113:12
113   return { read };
               ~~~~
error TS2339: Property 'iter' does not exist on type 'typeof Deno'.

► https://deno.land/[email protected]/http/_io.ts:167:34

167   for await (const chunk of Deno.iter(r)) {
                                     ~~~~

error TS2345: Argument of type 'Reader' is not assignable to parameter of type 'Writer'.
  Property 'write' is missing in type 'Reader' but required in type 'Writer'.
► https://deno.land/[email protected]/http/_io.ts:265:31
265     const n = await Deno.copy(r.body, writer);
                                  ~~~~~~
  'write' is declared here.

    ► $asset$/lib.deno.ns.d.ts:463:5

    463     write(p: Uint8Array): Promise<number>;
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2339: Property 'listenTls' does not exist on type 'typeof Deno'.

► https://deno.land/[email protected]/http/server.ts:16:17
16 const { listen, listenTls } = Deno;
                   ~~~~~~~~~
error TS2694: Namespace 'Deno' has no exported member 'ListenTlsOptions'.
► https://deno.land/[email protected]/http/server.ts:289:38
289 export type HTTPSOptions = Omit<Deno.ListenTlsOptions, "transport">;
                                         ~~~~~~~~~~~~~~~~
error TS2694: Namespace 'Deno' has no exported member 'ListenTlsOptions'.
► https://deno.land/[email protected]/http/server.ts:309:26

309   const tlsOptions: Deno.ListenTlsOptions = {
                             ~~~~~~~~~~~~~~~~
error TS2694: Namespace 'Deno' has no exported member 'WriterSync'.
► https://deno.land/[email protected]/io/bufio.ts:8:24
8 type WriterSync = Deno.WriterSync;
                         ~~~~~~~~~~
error TS2469: The '>=' operator cannot be applied to type 'symbol'.

► https://deno.land/[email protected]/io/bufio.ts:90:14

90       assert(rr >= 0, "negative read");
                ~~
error TS2365: Operator '+=' cannot be applied to types 'number' and 'number | unique symbol'.
► https://deno.land/[email protected]/io/bufio.ts:91:7

91       this.w += rr;
         ~~~~~~~~~~~~
error TS2469: The '>' operator cannot be applied to type 'symbol'.
► https://deno.land/[email protected]/io/bufio.ts:92:11

92      if (rr > 0) {
             ~~
error TS2416: Property 'read' in type 'BufReader' is not assignable to the same property in base type 'Reader'.
  Type '(p: Uint8Array) => Promise<number | null>' is not assignable to type '(p: Uint8Array) => Promise<number | unique symbol>'.
    Type 'Promise<number | null>' is not assignable to type 'Promise<number | unique symbol>'.
      Type 'number | null' is not assignable to type 'number | unique symbol'.
        Type 'null' is not assignable to type 'number | unique symbol'.
► https://deno.land/[email protected]/io/bufio.ts:123:9

123   async read(p: Uint8Array): Promise<number | null> {
            ~~~~
error TS2469: The '>=' operator cannot be applied to type 'symbol'.
► https://deno.land/[email protected]/io/bufio.ts:133:16
133         assert(nread >= 0, "negative read");
                   ~~~~~
error TS2322: Type 'number | unique symbol' is not assignable to type 'number | null'.
  Type 'unique symbol' is not assignable to type 'number | null'.
► https://deno.land/[email protected]/io/bufio.ts:138:9
138         return rr;
            ~~~~~~~~~~
error TS2322: Type 'number | unique symbol' is not assignable to type 'number | null'.
  Type 'unique symbol' is not assignable to type 'number | null'.
► https://deno.land/[email protected]/io/bufio.ts:145:7
145       rr = await this.rd.read(this.buf);
          ~~
error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.
► https://deno.land/[email protected]/path/_constants.ts:51:19

51 const isWindows = build.os == "windows";
                     ~~~~~~~~~~~~~~~~~~~~~
error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.
► https://deno.land/[email protected]/path/_globrex.ts:5:15
5 const isWin = Deno.build.os === "windows";
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.
► https://deno.land/[email protected]/path/mod.ts:7:19
7 const isWindows = Deno.build.os == "windows";
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2345: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
  Type 'URL' is not assignable to type 'string'.
► https://deno.land/[email protected]/path/posix.ts:433:18

433   return new URL(url).pathname;
                     ~~~
error TS2367: This condition will always return 'false' since the types 'OperatingSystem' and '"windows"' have no overlap.
► https://deno.land/[email protected]/path/separator.ts:2:19

2 const isWindows = Deno.build.os == "windows";
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2339: Property 'get' does not exist on type '{ (): { [index: string]: string; }; (key: string): string | undefined; }'.
► https://deno.land/[email protected]/path/win32.ts:42:18

42       path = env.get(`=${resolvedDevice}`) || cwd();
                    ~~~
error TS2345: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
  Type 'URL' is not assignable to type 'string'.
► https://deno.land/[email protected]/path/win32.ts:911:18

911   return new URL(url).pathname
                     ~~~
error TS2304: Cannot find name 'AbortSignal'.
► https://deno.land/x/oak/application.ts:18:12

18   signal?: AbortSignal;
              ~~~~~~~~~~~
error TS2304: Cannot find name 'AbortSignal'.
► https://deno.land/x/oak/application.ts:27:12
27   signal?: AbortSignal;
              ~~~~~~~~~~~
error TS2304: Cannot find name 'ErrorEventInit'.

► https://deno.land/x/oak/application.ts:45:11

45   extends ErrorEventInit {
             ~~~~~~~~~~~~~~
error TS2304: Cannot find name 'ErrorEvent'.

► https://deno.land/x/oak/application.ts:78:61
78 export class ApplicationErrorEvent<S extends State> extends ErrorEvent {
                                                               ~~~~~~~~~~
error TS2345: Argument of type '{ context: Context<S>; message: any; error: any; }' is not assignable to parameter of type 'ApplicationErrorEventInit<S>'.
  Object literal may only specify known properties, and 'message' does not exist in type 'ApplicationErrorEventInit<S>'.

► https://deno.land/x/oak/application.ts:153:53

153       new ApplicationErrorEvent("error", { context, message, error }),
                                                        ~~~~~~~

error TS2416: Property 'addEventListener' in type 'Application<S>' is not assignable to the same property in base type 'EventTarget'.
  Type '(type: "error", listener: ApplicationErrorEventListener<S> | ApplicationErrorEventListenerObject<S> | null, options?: any) => void' is not assignable to type '(type: string, callback: EventListener | EventListenerObject | null, options?: boolean | AddEventListenerOptions | undefined) => void'.
    Types of parameters 'listener' and 'callback' are incompatible.
      Type 'EventListener | EventListenerObject | null' is not assignable to type 'ApplicationErrorEventListener<S> | ApplicationErrorEventListenerObject<S> | null'.
        Type 'EventListener' is not assignable to type 'ApplicationErrorEventListener<S> | ApplicationErrorEventListenerObject<S> | null'.      
          Type 'EventListener' is not assignable to type 'ApplicationErrorEventListener<S>'.
            Types of parameters 'evt' and 'evt' are incompatible.
              Type 'ApplicationErrorEvent<S>' is missing the following properties from type 'Event': type, target, currentTarget, composedPath, 
and 17 more.
► https://deno.land/x/oak/application.ts:202:3

202   addEventListener(
      ~~~~~~~~~~~~~~~~
error TS2304: Cannot find name 'AddEventListenerOptions'.

► https://deno.land/x/oak/application.ts:205:25

205     options?: boolean | AddEventListenerOptions,
                            ~~~~~~~~~~~~~~~~~~~~~~~
error TS2416: Property 'addEventListener' in type 'Application<S>' is not assignable to the same property in base type 'EventTarget'.
  Type '(type: "error", listener: ApplicationErrorEventListener<S> | ApplicationErrorEventListenerObject<S> | null, options?: any) => void' is not assignable to type '(type: string, callback: EventListener | EventListenerObject | null, options?: boolean | AddEventListenerOptions | undefined) => void'.

► https://deno.land/x/oak/application.ts:207:3
207   addEventListener(
      ~~~~~~~~~~~~~~~~
error TS2304: Cannot find name 'EventListenerOrEventListenerObject'.
► https://deno.land/x/oak/application.ts:209:15

209     listener: EventListenerOrEventListenerObject | null,
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2304: Cannot find name 'AddEventListenerOptions'.

► https://deno.land/x/oak/application.ts:210:25

210     options?: boolean | AddEventListenerOptions,
                            ~~~~~~~~~~~~~~~~~~~~~~~

error TS2345: Argument of type '{ message: string; error: any; }' is not assignable to parameter of type 'ApplicationErrorEventInit<Record<string | number | symbol, any>>'.
  Object literal may only specify known properties, and 'message' does not exist in type 'ApplicationErrorEventInit<Record<string | number | symbol, any>>'.

► https://deno.land/x/oak/application.ts:254:46

254         new ApplicationErrorEvent("error", { message, error }),
                                                 ~~~~~~~
error TS2322: Type '() => boolean' is not assignable to type 'boolean'.
► https://deno.land/x/oak/send.ts:62:12
62     return (await Deno.stat(path)).isFile;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Did you mean to call this expression?
    ► https://deno.land/x/oak/send.ts:62:12
    62     return (await Deno.stat(path)).isFile;
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?

► https://deno.land/x/oak/send.ts:135:9

135     if (stats.isDirectory) {
            ~~~~~~~~~~~~~~~~~

error TS2339: Property 'mtime' does not exist on type 'FileInfo'.

► https://deno.land/x/oak/send.ts:151:55

151   if (!response.headers.has("Last-Modified") && stats.mtime) {
                                                          ~~~~~
error TS2339: Property 'mtime' does not exist on type 'FileInfo'.

► https://deno.land/x/oak/send.ts:152:49

152     response.headers.set("Last-Modified", stats.mtime.toUTCString());
                                                    ~~~~~
Found 38 errors.

[Proposal] Better type support

Since this project followed koa's design, it has the same problem on types. Here I have a proposal to bring better type support for middleware.

The problem is that you cannot extend Application's type parameter when applying middlewares(which attach extra properties to ctx.state) on it. For example:

const app = new Application()

app.use(ctx => {
    ctx.state.username = 'foo'
}).use(ctx => {
    // not type safe for username
    ctx.state.username
})

My idea is we can change the prototype of use like this:

class Application<S>{
  use<NS extends {} = S>(middleware: Middleware<NS, Context<NS>>): Application<NS extends S ? NS : (S & NS)>
}

So we can happily write middleware with type checking:

// when need to extend context type, declare only what you want to attach
app.use((ctx: Context<{ name: string }>) => {
  ctx.state.name = 'foo'
  // I'm not including next here for simplification 
})
// extend again
.use((ctx: Context<{ id: string }>) => {
  ctx.state.id = 'id'
})
// context type is by default according to last middleware
.use((ctx) => {
  // ctx has a default type
  ctx.state.id = 'id'
  ctx.state.name = 'name'
})

It's not hard to do so if we don't support applying multiple middleware by one use call(which should be a rare use case).

And it's a little complicated for Router, we also want Router to have same context type as Application, so the Router instance must be created by a Application instance, so its type parameter can be inherited.

Application<S> {
  createRouter(): Router<S>
}

If you're good with this, I'll be working on it and send a pull request. Or please reply if have any comments.

Q&A: How to get list of implemented routes for router?

How can I get a list of all the routes that my router has available?
Guiding myself from the self question in Koa something like this can be done:

router.get('/', async (context: RouterContext) => {
  context.response.body = "This is a response";
});

router.stack.map(i => i.path);

`Transfer-Encoding:chunked` in request headers causes `UnexpectedEOFError`

I tried to send HTTP GET request with Transfer-encoding: chunked in the request header such as following command then.

$ curl "http://localhost:8000" -H "Transfer-encoding: chunked"

Then http server process faced UnexpectedEOFError.

error: Uncaught UnexpectedEOFError: Unexpected EOF
► io.ts:66:34

66     if (line === Deno.EOF) throw new UnexpectedEOFError();
                                    ^

    at UnexpectedEOFError (bufio.ts:28:5)
    at read (io.ts:66:34)

server.ts is following.

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use(ctx => {
  ctx.response.body = "Hello World!";
});

await app.listen({ port: 8000 });

Stopping the server

First and foremost: keep up the good work, i like where this project is going (:

I tried to implement an fs.watch logic that restarts oak on file change. For this I added the AbortController as mentioned in the README and I added controller.abort() to my fs.watch. Unfortunately neither the promise from app.listen was ever resolved, nor was the underlying server closed - it also seems like server.close() is not called in https://github.com/oakserver/oak/blob/master/application.ts#L226

Do I misunderstand the idea behind the AbortController? Or is this just not fully implemented?

Sub-routers

The idea is to be able to use a router as path of an another router. Maybe this is supported, if so, sorry for creating a duplicate issue.

Property 'ErrorKind' does not exist on type 'typeof Deno'.

The object Deno changed. please use Deno.errors.NotFound instead of Deno.NotFound

error TS2339: Property 'ErrorKind' does not exist on type 'typeof Deno'.

► https://deno.land/x/oak/send.ts:149:29

149       if (err.kind === Deno.ErrorKind.NotFound) {
                                ~~~~~~~~~

Cookies not working

Cookies are not working.

Example:

.get(
    '/setCookie',
    (context) => {
      context.cookies.set('auth', JSON.stringify({count:1}))
      context.response.body = 'cookie set'
    }
  )
  .get(
    '/getCookie',
    (context) => {
      context.response.body = 'hello' + context.cookies.get('auth')
    }
  )

This doesn't return the cookie value on the second request.

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.