GoodMan
GoodMan

Reputation: 650

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

I get this error message when I try to test the /api/register end point with Postman and following POST request:

{
    "name" : "first",
    "email" : "[email protected]",
    "password" : "123"
}
[uncaught application error]: TypeError - Cannot read properties of undefined (reading 'name')

    request: { url: "http://0.0.0.0:8000/api/register", method: "POST", hasBody: true }
    response: { status: 404, type: undefined, hasBody: false, writable: true }
    
        at register (file:///C:/Users/m/app_back/controllers/auth_controller.ts:9:22)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async EventTarget.#handleRequest (https://deno.land/x/[email protected]/application.ts:379:9)
    TypeError: Cannot read properties of undefined (reading 'name')
        at register (file:///C:/Users/m/app_back/controllers/auth_controller.ts:9:22)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async dispatch (https://deno.land/x/[email protected]/middleware.ts:41:7)
        at async EventTarget.#handleRequest (https://deno.land/x/[email protected]/application.ts:379:9)

This is my auth_controller.ts file:

import {
      create, verify, decode, getNumericDate, RouterContext, hashSync, compareSync
    } from "../deps.ts";
    import { userCollection } from "../mongo.ts";
    import User from "../models/user.ts";
    
    export class AuthController {
      async register(ctx: RouterContext) {
        const { value: { name, email, password } } = await ctx.request.body().value;
    
        let user = await User.findOne({ email });
        if (user) {
          ctx.response.status = 422;
          ctx.response.body = { message: "Email is already used" };
          return;
        }
        const hashedPassword = hashSync(password);
        user = new User({ name, email, password: hashedPassword });
        await user.save();
        ctx.response.status = 201;
        ctx.response.body = {
          id: user.id,
          name: user.name,
          email: user.email
        };
      }
      async login(ctx: RouterContext) {
        const { value: { email, password } } = await ctx.request.body().value;
        if (!email || !password) {
          ctx.response.status = 422;
          ctx.response.body = { message: "Please provide email and password" };
          return;
        }
        let user = await User.findOne({ email });
        if (!user) {
          ctx.response.status = 422;
          ctx.response.body = { message: "Incorrect email" };
          return;
        }
        if (!compareSync(password, user.password)) {
          ctx.response.status = 422;
          ctx.response.body = { message: "Incorrect password" };
          return;
        }
    
        const key = await crypto.subtle.generateKey(
          { name: "HMAC", hash: "SHA-512" },
          true,
          ["sign", "verify"],
        );
    
        const jwt = create( { 
          alg: "HS256",
          typ: "JWT",
        }, {
          iss: user.email,
          exp: getNumericDate(
            Date.now() + parseInt(Deno.env.get("JWT_EXP_DURATION") || "0"))
        },
        key
        );
    
        ctx.response.body = {
          id: user.id,
          name: user.name,
          email: user.email,
          jwt,
        };
      }
    }
    
    export default new AuthController();

What is the problem and how can I resolve it?

EDIT: I added this line to the code:

console.log( await ctx.request.body().value );

And this is the result:

{ name: "first", email: "[email protected]", password: "123" }

Upvotes: 0

Views: 3666

Answers (1)

Renat Zaicev
Renat Zaicev

Reputation: 26

You are facing this issue because you are trying to access ctx.request.body().value.value.name (notice multiple value porperties). You could change line 9 of your auth_controller.ts to this to fix it:

const { name, email, password } = await ctx.request.body().value;

On a side note, I also noticed few more issues with your current code.

Your JWT algorithm and generated secret key encryption algorithm should match

So either change your hash encryption on line 47 to SHA-256 or your JWT algorithm on line 53 to HS512.

You don't need to pass current date to getNumericDate function

This helper function already does this job for you, all you need to pass here is the time period (in seconds) when you want your token to expire. In your case it would be:

getNumericDate(Deno.env.get("JWT_EXP_DURATION") || 0)}

Upvotes: 1

Related Questions