-1

Basically I'm running into this error when trying to use UseCase class on Deno.

[uncaught application error]: TypeError - Cannot read properties of undefined (reading 'getAppInfosUseCase')

request: { url: "http://127.0.0.1:3030/", method: "GET", hasBody: false }
response: { status: 200, type: undefined, hasBody: false, writable: true }

    at handle (file:///C:/Users/joaop/Documents/dev/web/back-end/deno/shynotes-api%20(MVC)/src/useCases/GetAppInfos/GetAppInfosController.ts:11:39)
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at https://deno.land/x/oak@v10.6.0/router.ts:1148:20
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at composedMiddleware (https://deno.land/x/oak@v10.6.0/middleware.ts:44:12)
    at dispatch (https://deno.land/x/oak@v10.6.0/router.ts:1154:28)
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at composedMiddleware (https://deno.land/x/oak@v10.6.0/middleware.ts:44:12)
    at Application.#handleRequest (https://deno.land/x/oak@v10.6.0/application.ts:389:34)
    at Application.listen (https://deno.land/x/oak@v10.6.0/application.ts:559:28)

App Structure

project-structure

src/

app.ts

import { Application } from 'https://deno.land/x/oak@v10.6.0/mod.ts';
import { router } from './routes.ts';
import 'https://deno.land/x/dotenv@v3.2.0/load.ts';

const app = new Application();

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

export { app };

routes.ts

import { Router } from 'https://deno.land/x/oak@v10.6.0/router.ts';
import { getAppInfosController } from './useCases/GetAppInfos/index.ts';

const router = new Router();

router.get('/', getAppInfosController.handle);

export { router };

server.ts

import { app } from './app.ts';

await app.listen({
    port: 3030,
});

src/useCases/

GetAppInfosController.ts

import { Context } from 'https://deno.land/x/oak@v10.6.0/context.ts';
import { GetAppInfosUseCase } from './GetAppInfosUseCase.ts';

export class GetAppInfosController {
    constructor(
        private getAppInfosUseCase: GetAppInfosUseCase,
    ) {}

    handle(context: Context) {
        context.response.status = 200;
        return context.response.body = this.getAppInfosUseCase.execute();
    }
}

GetAppInfosUseCase.ts

export class GetAppInfosUseCase {
    execute() {
        return {
            author: 'Jphn',
            github: 'github.com/Jphn',
        };
    }
}

index.ts

import { GetAppInfosUseCase } from './GetAppInfosUseCase.ts';
import { GetAppInfosController } from './GetAppInfosController.ts';

const getAppInfosUseCase = new GetAppInfosUseCase();

const getAppInfosController = new GetAppInfosController(getAppInfosUseCase);

export { getAppInfosController, getAppInfosUseCase };
João Pedro
  • 9
  • 1
  • 4
  • Great job providing all of the necessary information to reproduce the issue. So many questions lack that critical detail. (The only thing I'd suggest also adding in the future is the version of Deno that you were using.) – jsejcksn Jul 28 '22 at 03:05

2 Answers2

1

This question seems like you are in need of help debugging. I copied the data in your question to files in a directory on my file system to reproduce. Let's start with some basics:

The version of Deno I'm using:

% deno --version
deno 1.24.0 (release, x86_64-apple-darwin)
v8 10.4.132.20
typescript 4.7.4

Type-checking your code:

% deno check src/server.ts 
Download https://deno.land/x/dotenv@v3.2.0/load.ts
Download https://deno.land/x/dotenv@v3.2.0/mod.ts
Download https://deno.land/x/dotenv@v3.2.0/util.ts
error: Module not found "file:///Users/deno/so-73142682/src/useCases/GetAppInfos/index.ts".
    at file:///Users/deno/so-73142682/src/routes.ts:2:39

The first problem revealed is that there's an invalid module specifier in ./src/routes.ts:

import { Router } from 'https://deno.land/x/oak@v10.6.0/router.ts';
import { getAppInfosController } from './useCases/GetAppInfos/index.ts'; /*
                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unable to load a local module: "file:///Users/deno/so-73142682/src/useCases/GetAppInfos/index.ts".
  Please check the file path. deno(no-local) */

const router = new Router();

router.get('/', getAppInfosController.handle);

export { router };

The specifier just needs to be changed to "./useCases/index.ts". After making that change, let's type-check again:

% deno check src/server.ts
Check file:///Users/deno/so-73142682/src/server.ts

Now type-checking passes: great. Let's try running the module:

% deno run --allow-read=".env,.env.defaults" --allow-net="0.0.0.0:3030" src/server.ts

The process doesn't terminate, so something's happening. Let's try making a GET request to the host. In a separate terminal shell:

% deno eval --print "(await fetch('http://localhost:3030')).status"
500

The status of the request is 500. Let's switch back to the shell where the app is running and check if there's any output. There is:

[uncaught application error]: TypeError - Cannot read properties of undefined (reading 'getAppInfosUseCase')

request: { url: "http://localhost:3030/", method: "GET", hasBody: false }
response: { status: 200, type: undefined, hasBody: false, writable: true }

    at handle (file:///Users/deno/so-73142682/src/useCases/GetAppInfosController.ts:11:45)
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at https://deno.land/x/oak@v10.6.0/router.ts:1148:20
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at composedMiddleware (https://deno.land/x/oak@v10.6.0/middleware.ts:44:12)
    at dispatch (https://deno.land/x/oak@v10.6.0/router.ts:1154:28)
    at dispatch (https://deno.land/x/oak@v10.6.0/middleware.ts:41:13)
    at composedMiddleware (https://deno.land/x/oak@v10.6.0/middleware.ts:44:12)
    at Application.#handleRequest (https://deno.land/x/oak@v10.6.0/application.ts:389:34)
    at Application.listen (https://deno.land/x/oak@v10.6.0/application.ts:559:28)

Looking at the beginning of the stack trace shows that the error originated at this location:

at handle (file:///Users/deno/so-73142682/src/useCases/GetAppInfosController.ts:11:45)

The 11:45 means line 11, column 45. Let's check that position in the source module ./src/useCases/GetAppInfosController.ts:

import { Context } from 'https://deno.land/x/oak@v10.6.0/context.ts';
import { GetAppInfosUseCase } from './GetAppInfosUseCase.ts';

export class GetAppInfosController {
    constructor(
        private getAppInfosUseCase: GetAppInfosUseCase,
    ) {}

    handle(context: Context) {
        context.response.status = 200;
        return context.response.body = this.getAppInfosUseCase.execute(); /*
                                            ~~~~~~~~~~~~~~~~~~
                                      Here's where the error occurred.
                                  `this` was `undefined` at the call site */
    }
}

The stack doesn't make this obvious, but the actual problem is where you use the handle method in ./src/routes.ts:

import { Router } from 'https://deno.land/x/oak@v10.6.0/router.ts';
import { getAppInfosController } from './useCases/index.ts';

const router = new Router();

router.get('/', getAppInfosController.handle); /*
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                This is an unbound method call */

export { router };

Method binding has already been covered extensively on this site in other questions, so I won't reiterate the details here. You just need to bind the class instance object to the method so that when it's invoked as a function, the this value refers to the class instance object:

router.get('/', getAppInfosController.handle.bind(getAppInfosController));
//                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

After saving those changes, let's stop the app using ctrl + c in the terminal and start it again:

^C

% deno run --allow-read=".env,.env.defaults" --allow-net="0.0.0.0:3030" src/server.ts

Now let's make another GET request to the host in a separate terminal shell, but this time we'll print the body as parsed JSON (because that's the expected response format):

% deno eval --print "await (await fetch('http://localhost:3030')).json()"
{ author: "Jphn", github: "github.com/Jphn" }

Now it looks like what's expected. Issue solved.

jsejcksn
  • 27,667
  • 4
  • 38
  • 62
-1

server.ts

import { Router } from 'https://deno.land/x/oak@v10.6.0/router.ts';
import { getAppInfosController } from './useCases/GetAppInfos/index.ts';

const router = new Router();

// router.get('/', getAppInfosController.handle);
router.get('/', (context) => {
  getAppInfosController.handle(context);
});

export { router };
João Pedro
  • 9
  • 1
  • 4
  • Without any additional information, it's not clear what this code snippet should tell us. Is this additional information for the question? In that case, you should edit the question to add it there. Is this supposed to answer your own question? Then please write a few sentences to explain what you changed and how it solves the problem. Just a code snippet without any explanation has not much value. – jps Jul 29 '22 at 08:28
  • It's a resolution of the problem, if it was an additional one I would have added the question, but I appreciate your comment. @jps – João Pedro Aug 03 '22 at 12:05
  • *It's a resolution of the problem* - fine, but why don't you just edit the answer to add some explanation as suggested before? Code-only answers should generally be avoided. – jps Aug 03 '22 at 21:15