Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Props for actions and tasks #1400

Open
evantahler opened this issue Feb 7, 2020 · 13 comments
Open

Type Props for actions and tasks #1400

evantahler opened this issue Feb 7, 2020 · 13 comments
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@evantahler
Copy link
Member

evantahler commented Feb 7, 2020

I'll bet we can use inputs to learn the types of params for actions and tasks, and that would really help the developer experience!

Ideally:

import { Action } from 'actionhero'

export class UserView extends Action {
  constructor() {
    super();
    this.name = "user:view";
    this.description = "view the details of a user";
    this.outputExample = {};
    this.inputs = {
      guid: { required: true, type: string },
    };
  }

  async run({ params, response }) {
   // we should be able to know that `params` only has the property `guid` and is of type `string`
    const user = await User.findByGuid(params.guid);
    response.user = await user.formatForApi();
  }
}
@evantahler
Copy link
Member Author

This is blocked by #1408

@evantahler
Copy link
Member Author

The path might involve building a pseudo-class in the ActionProcessor that extends the types of the Action, perhaps an "Intersection type" (more her: https://www.typescriptlang.org/docs/handbook/advanced-types.html)

@evantahler evantahler added the help wanted Extra attention is needed label Aug 24, 2020
@gcoonrod gcoonrod added the enhancement New feature or request label Sep 8, 2020
@papb
Copy link

papb commented Oct 21, 2020

Is it acceptable to expect as const being used when setting this.inputs?

this.inputs = {
  /* ... things here that I will think of and suggest soon ... */
} as const;

Or does it have to work without as const?

(if as const can be expected, it will be much easier to do this)

@evantahler
Copy link
Member Author

evantahler commented Oct 21, 2020

I think const will work OK! Action.inputs are static and shouldn't change over the lifecycle of the application.

@evantahler
Copy link
Member Author

Ping! @papb is there anything I can help with? I'm really excited for typed Action inputs!

@papb
Copy link

papb commented Nov 6, 2020

Pong! Sorry for the delay, I have been quite busy, but hopefully next week I will be able to help you. Sorry!!

@evantahler
Copy link
Member Author

https://github.com/sindresorhus/type-fest/blob/master/source/entries.d.ts looks relevant to our interests!

@krlicmuhamed
Copy link
Contributor

How do I declare a Action Template variable authenticate in my example.

export default class Status extends Action {
  constructor() {
    super();
    this.name = "status";
    this.description = "I will return some basic information about the API";
    this.outputExample = {
      id: "192.168.2.11",
      actionheroVersion: "9.4.1",
      uptime: 10469,
    };
    this.authenticate = true; // throws an error even though It is defined in an initializer
    // throws (src/actions/status.ts:26:10 - error TS2339: Property 'authenticate' does not exist on type 'Status'.)
  }

Initializer middleware code contains data.actionTemplate.authenticate ie.

        // Middleware code
        if (data.actionTemplate.authenticate && api.jwtauth.enabled[data.connection.type]) {
          tokenRequired = true;
        }

Thanks

@evantahler
Copy link
Member Author

evantahler commented Jan 4, 2021

@krlicmuhamed in your case, you want to make a new class that extends Action and adds the new properties:

import { Action } from "actionhero";

export abstract class AuthenticatedAction extends Action {
  authenticate: boolean;

  constructor() {
    super();
    this.middleware = ["authenticated-action"];
  }
}

And then use your new class rather than Action itself in your Actions:

export default class Status extends AuthenticatedAction {
  constructor() {
    super();
    this.name = "status";
    this.description = "I will return some basic information about the API";
    this.outputExample = {
      id: "192.168.2.11",
      actionheroVersion: "9.4.1",
      uptime: 10469,
    };
    this.authenticate = true;
  }

We do this in Grouparoo:

@krlicmuhamed
Copy link
Contributor

@evantahler hi, I tried this approach but I get alert: Failed to load C:/Projects/pratibaApi/dist/actions/authenticatedAction.js stacktrace=Error: name is required for this action for the abstract class AuthenticatedAction when I try to npm run start
Here's full stacktrace

2021-01-04T17:16:33.133Z - alert: Failed to load C:/Projects/pratibaApi/dist/actions/authenticatedAction.js stacktrace=Error: name is required for this action
    at AuthenticatedAction.validate (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\action.js:51:19)
    at Object.index_1.api.actions.loadFile (C:\Projects\pratibaApi\node_modules\actionhero\dist\initializers\actions.js:37:34)
    at async Actions.initialize (C:\Projects\pratibaApi\node_modules\actionhero\dist\initializers\actions.js:68:17)
    at async Object.initializeFunction (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:101:29)
    at async Object.asyncWaterfall (C:\Projects\pratibaApi\node_modules\actionhero\dist\modules\utils\asyncWaterfall.js:47:23)
    at async Process.initialize (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:170:13)
    at async Process.start (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:179:13)
    at async main (C:\Projects\pratibaApi\dist\server.js:13:5)
2021-01-04T17:16:33.152Z - emerg: Exception occurred in initializer `actions` during load 
2021-01-04T17:16:33.153Z - emerg: Error with initializer step: "initialize"
2021-01-04T17:16:33.154Z - emerg: Error: name is required for this action
    at AuthenticatedAction.validate (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\action.js:51:19)
    at Object.index_1.api.actions.loadFile (C:\Projects\pratibaApi\node_modules\actionhero\dist\initializers\actions.js:37:34)
    at async Actions.initialize (C:\Projects\pratibaApi\node_modules\actionhero\dist\initializers\actions.js:68:17)
    at async Object.initializeFunction (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:101:29)
    at async Object.asyncWaterfall (C:\Projects\pratibaApi\node_modules\actionhero\dist\modules\utils\asyncWaterfall.js:47:23)
    at async Process.initialize (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:170:13)
    at async Process.start (C:\Projects\pratibaApi\node_modules\actionhero\dist\classes\process.js:179:13)
    at async main (C:\Projects\pratibaApi\dist\server.js:13:5)

@evantahler
Copy link
Member Author

@krlicmuhamed Can you share example code to reproduce the error?

@krlicmuhamed
Copy link
Contributor

@krlicmuhamed Can you share example code to reproduce the error?

Here you go https://github.com/krlicmuhamed/apiauth

$ npm run build && npm run start 

> my_actionhero_project@0.1.0 build
> tsc --sourceMap false --declaration


> my_actionhero_project@0.1.0 start
> node ./dist/server.js

2021-01-05T15:25:54.820Z - alert: Failed to load C:/Projects/APIAUTH/dist/actions/classes/authenticatedAction.js stacktrace=Error: name is required for this action
    at AuthenticatedAction.validate (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\action.js:51:19)
    at Object.index_1.api.actions.loadFile (C:\Projects\APIAUTH\node_modules\actionhero\dist\initializers\actions.js:37:34)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at async Actions.initialize (C:\Projects\APIAUTH\node_modules\actionhero\dist\initializers\actions.js:68:17)
    at async Object.initializeFunction (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:101:29)
    at async Object.asyncWaterfall (C:\Projects\APIAUTH\node_modules\actionhero\dist\modules\utils\asyncWaterfall.js:47:23)
    at async Process.initialize (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:170:13)
    at async Process.start (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:179:13)
    at async main (C:\Projects\APIAUTH\dist\server.js:13:5)
2021-01-05T15:25:54.865Z - emerg: Exception occurred in initializer `actions` during load 
2021-01-05T15:25:54.867Z - emerg: Error with initializer step: "initialize"
2021-01-05T15:25:54.869Z - emerg: Error: name is required for this action
    at AuthenticatedAction.validate (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\action.js:51:19)
    at Object.index_1.api.actions.loadFile (C:\Projects\APIAUTH\node_modules\actionhero\dist\initializers\actions.js:37:34)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at async Actions.initialize (C:\Projects\APIAUTH\node_modules\actionhero\dist\initializers\actions.js:68:17)
    at async Object.initializeFunction (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:101:29)
    at async Object.asyncWaterfall (C:\Projects\APIAUTH\node_modules\actionhero\dist\modules\utils\asyncWaterfall.js:47:23)
    at async Process.initialize (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:170:13)
    at async Process.start (C:\Projects\APIAUTH\node_modules\actionhero\dist\classes\process.js:179:13)
    at async main (C:\Projects\APIAUTH\dist\server.js:13:5)
2021-01-05T15:25:54.904Z - crit: Cannot shut down actionhero, not running 
npm ERR! code 1
npm ERR! path C:\Projects\APIAUTH
npm ERR! command failed
npm ERR! command C:\Windows\system32\cmd.exe /d /s /c node ./dist/server.js

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Muhamed\AppData\Local\npm-cache\_logs\2021-01-05T15_25_55_980Z-debug.log

@evantahler
Copy link
Member Author

Ah ha! Move that class out of the ‘actions’ folder. We look through that folder and try to load anything that extends Action... but that class isn’t a real action. Can you open a new issue about this please?

@evantahler evantahler self-assigned this Jan 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants