-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Testing / modifying code examples #2133
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
Changes from all commits
0759115
0127d31
c9ab7f2
53db31d
489a290
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,21 +17,18 @@ It's important to understand the core difference between Node.js and the JavaScr | |
| ## Adding a code step | ||
|
|
||
| 1. Click the **+** button below any step of your workflow. | ||
| 2. Select the option to **Run Node.js code**. | ||
|
|
||
| <div> | ||
| <img alt="Code step" src="./images/new-code-step.png"> | ||
| </div> | ||
| 2. Select the option to **Run custom code**. | ||
| 3. Select the `nodejs14.x` runtime. | ||
|
|
||
| You can add any Node.js code in the editor that appears. For example, try: | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| console.log('This is Node.js code'); | ||
| $.export('test', 'Some test data'); | ||
| return 'Test data'; | ||
| }) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
|
|
@@ -44,7 +41,7 @@ You can make code steps reusable by allowing them to accept props. Instead of ha | |
| For example, let's define a `firstName` prop. This will allow us to freely enter text from the workflow builder. | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| props: { | ||
| firstName: { | ||
| type: 'string', | ||
|
|
@@ -68,37 +65,43 @@ Accepting a single string is just one example, you can build a step to accept ar | |
|
|
||
| [Read the props reference for the full list of options](/components/api/#props). | ||
|
|
||
| ## `async` function declaration | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section still referenced the old function declaration so I modified to discuss components. lmk if you think this can be improved |
||
| ## How Pipedream Node.js components work | ||
|
|
||
| You'll notice an [`async` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) declaration that appears when you add a new Node.js code step: | ||
| When you add a new Node.js code step or use the examples in this doc, you'll notice a common structure to the code: | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| // this Node.js code will execute when your workflow is triggered | ||
| }) | ||
| // this Node.js code will execute when the step runs | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| This communicates a couple of key concepts: | ||
| This defines [a Node.js component](/components/api/). Components let you: | ||
|
|
||
| - Any async code within a code step [**must** be run synchronously](/workflows/steps/code/async/), using the `await` keyword or with a Promise chain, using `.then()`, `.catch()`, and related methods. | ||
| - Pipedream passes the variables `event` and `steps` to every code step. `event` is a read-only object that contains the data that triggered your event, for example the HTTP request sent to your workflow's endpoint. `steps` is also an object, and contains the [data exported from previous steps](/workflows/steps/#step-exports) in your workflow. | ||
| - Pass input to steps using [props](/code/nodejs/#passing-props-to-code-steps) | ||
| - [Connect an account to a step](/connected-accounts/#from-a-code-step) | ||
| - [Issue HTTP responses](/workflows/steps/triggers/#customizing-the-http-response) | ||
| - Perform workflow-level flow control, like [ending a workflow early](#ending-a-workflow-early) | ||
|
|
||
| If you're using [step props](/code/nodejs/#passing-props-to-code-steps) or [connect an account to a step](/connected-accounts/#from-a-code-step), they are available under `this` within the `run` function of the step. | ||
| When the step runs, Pipedream executes the `run` method: | ||
|
|
||
| - Any asynchronous code within a code step [**must** be run synchronously](/workflows/steps/code/async/), using the `await` keyword or with a Promise chain, using `.then()`, `.catch()`, and related methods. | ||
| - Pipedream passes the `steps` variable to the run method. `steps` is also an object, and contains the [data exported from previous steps](/workflows/steps/#step-exports) in your workflow. | ||
| - You also have access to the `$` variable, which gives you access to methods like `$.respond`, `$.export`, [and more](/components/api/#actions). | ||
|
|
||
| If you're using [props](/code/nodejs/#passing-props-to-code-steps) or [connect an account to a step](/connected-accounts/#from-a-code-step), the component exposes them in the variable `this`, which refers to the current step: | ||
|
|
||
| ```javascript | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| // this Node.js code will execute when your workflow is triggered | ||
|
|
||
| }) | ||
| // `this` refers to the running component. Props, connected accounts, etc. are exposed here | ||
| console.log(this) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| When you use [step parameters](/code/nodejs/#passing-props-to-code-steps), Pipedream passes the `props` object (named pairs of prop key and its associated value) to the function. | ||
|
|
||
| When you [connect an account to a step](/connected-accounts/#from-a-code-step), Pipedream passes the API keys to [`this.appName.$auths` object](/workflows/steps/code/auth/#the-auths-object) to the function. | ||
| When you [connect an account to a step](/connected-accounts/#from-a-code-step), Pipedream exposes the auth info in the variable [`this.appName.$auth`](/workflows/steps/code/auth/#the-auths-object). | ||
|
|
||
| ## Logs | ||
|
|
||
|
|
@@ -116,7 +119,7 @@ export default defineComponent({ | |
| console.dir({ | ||
| name: "Luke" | ||
| }) | ||
| }) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
|
|
@@ -222,7 +225,7 @@ In general, if you just need to make an HTTP request but don't care about the re | |
|
|
||
| ## Returning HTTP responses | ||
|
|
||
| You can return HTTP responses from [HTTP-triggered workflows](/workflows/steps/triggers/#http) using the [`$respond()` function](/workflows/steps/triggers/#customizing-the-http-response). | ||
| You can return HTTP responses from [HTTP-triggered workflows](/workflows/steps/triggers/#http) using the [`$.respond()` function](/workflows/steps/triggers/#customizing-the-http-response). | ||
|
|
||
| ## Managing state | ||
|
|
||
|
|
@@ -243,15 +246,15 @@ For more information on what functionality is available for those languages, ple | |
| By default, Node.js steps don't have access to the database service. It needs to be injected by defining it as a `prop`. | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| props: { | ||
| // Define that the "db" variable in our component is a database | ||
| db: "$.service.db", | ||
| }, | ||
| async run({ steps, $ }) { | ||
| // Now we can access the database at "this.db" | ||
| this.db.set("name", "Dylan") | ||
| }) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
|
|
@@ -336,7 +339,7 @@ export default defineComponent({ | |
|
|
||
| // If the current email being passed from our webhook is already in our list, exit early | ||
| if(emails.includes(email)) { | ||
| $.flow.exit('Already welcomed this user'); | ||
| return $.flow.exit('Already welcomed this user'); | ||
| } | ||
|
|
||
| // Add the current email to the list of past emails so we can detect it in the future runs | ||
|
|
@@ -352,7 +355,7 @@ The `$.service.db` is only currently available in Node.js code steps. It is not | |
| In addition, `$.service.db` can hold up to {{ $site.themeConfig.SERVICE_DB_SIZE_LIMIT }} per step. | ||
|
|
||
|
|
||
| ## `$end` | ||
| ## Ending a workflow early | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some references to |
||
|
|
||
| Sometimes you want to end your workflow early, or otherwise stop or cancel the execution or a workflow under certain conditions. For example: | ||
|
|
||
|
|
@@ -361,60 +364,46 @@ Sometimes you want to end your workflow early, or otherwise stop or cancel the e | |
| - You only want to run your workflow for users in the United States. If you receive a request from outside the U.S., you don't want the rest of the code in your workflow to run. | ||
| - You may use the `user_id` contained in the event to look up information in an external API. If you can't find data in the API tied to that user, you don't want to proceed. | ||
|
|
||
| **In any code step, calling the `$.flow.exit()` function will end the execution of the workflow immediately.** No remaining code in that step, and no code or destination steps below, will run for the current event. | ||
| **In any code step, calling `return $.flow.exit()` will end the execution of the workflow immediately.** No remaining code in that step, and no code or destination steps below, will run for the current event. | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| $.flow.exit(); | ||
| return $.flow.exit(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always forget that using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wow I didn't know that. My other examples are broken then. I thought it was the same behavior as |
||
| console.log("This code will not run, since $.flow.exit() was called above it"); | ||
| }) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| You can pass any string as an argument to `$.flow.exit()`: | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| $.end("Event doesn't have the correct schema"); | ||
| }) | ||
| return $.flow.exit("End message"); | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| This message will appear in the Inspector in the **Messages** column for the event where `$.flow.exit()` was called: | ||
|
|
||
| <div> | ||
| <img alt="Dollar end message in inspector" src="./images/dollar-end.png" width="300px"> | ||
| </div> | ||
|
|
||
| Like any other code, `$.flow.exit()` can be called conditionally: | ||
|
|
||
| ```javascript | ||
| defineComponent({ | ||
| export default defineComponent({ | ||
| async run({ steps, $ }) { | ||
| // Flip a coin, running $.flow.exit() for 50% of events | ||
| if (Math.random() > 0.5) { | ||
| $.flow.exit(); | ||
| return $.flow.exit(); | ||
| } | ||
| console.log("This code will only run 50% of the time"); | ||
| }) | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| ## Errors | ||
|
|
||
| [Errors](https://nodejs.org/dist/latest-v10.x/docs/api/errors.html#errors_errors) raised in a code step will stop the execution of code or destinations that follow. | ||
|
|
||
| You'll see the message associated with the error in the Inspector and the code step where the error was raised. | ||
|
|
||
| <div> | ||
| <img alt="Exception message" src="./images/exception.png"> | ||
| </div> | ||
|
|
||
| ## Using secrets in code | ||
|
|
||
| Workflow code is private by default, but [you can make a workflow public](/public-workflows/). In either case, we recommend you don't include secrets — API keys, tokens, or other sensitive values — directly in code steps. | ||
| Workflow code is private. Still, we recommend you don't include secrets — API keys, tokens, or other sensitive values — directly in code steps. | ||
|
|
||
| Pipedream supports [environment variables](/environment-variables/) for keeping secrets separate from code. Once you create an environment variable in Pipedream, you can reference it in any workflow using `process.env.VARIABLE_NAME`. The values of environment variables are private. | ||
|
|
||
|
|
@@ -449,12 +438,12 @@ When you're searching for how to do something in JavaScript, some of the code yo | |
| Many of the most basic JavaScript tutorials are geared towards writing code for a web browser to run. This is great for learning — a webpage is one of the coolest things you can build with code. We recommend starting with these general JavaScript tutorials and trying the code you learn on Pipedream: | ||
|
|
||
| - [JavaScript For Cats](http://jsforcats.com/) | ||
| - [Mozilla - JavaScript First Steps](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps) | ||
| - [Mozilla - JavaScript First Steps](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps) | ||
| - [StackOverflow](https://stackoverflow.com/) operates a programming Q&A site that typically has the first Google result when you're searching for something specific. It's a great place to find answers to common questions. | ||
|
|
||
| ### I know how to code, but don't know JavaScript | ||
|
|
||
| - [A re-introduction to JavaScript (JS tutorial)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) | ||
| - [A re-introduction to JavaScript (JS tutorial)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) | ||
| - [MDN language overview](https://developer.mozilla.org/en-US/docs/Web/JavaScript) | ||
| - [Eloquent Javascript](https://eloquentjavascript.net/) | ||
| - [Node School](https://nodeschool.io/) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ export default defineComponent({ | |
| } | ||
| }, | ||
| async run({ steps, $ }) { | ||
| const web = new WebClient(this.slack.$auths.oauth_access_token) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing references from
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, good catch |
||
| const web = new WebClient(this.slack.$auth.oauth_access_token) | ||
|
|
||
| return await web.chat.postMessage({ | ||
| text: "Hello, world!", | ||
|
|
@@ -38,12 +38,12 @@ Now the step in the workflow builder will allow you to connect your Slack accoun | |
|
|
||
| [[toc]] | ||
|
|
||
| ## Accessing API tokens with `this.appName.$auths` | ||
| ## Accessing connected account data with `this.appName.$auth` | ||
|
|
||
| In our Slack example above, we created a Slack `WebClient` using the Slack OAuth access token: | ||
|
|
||
| ```javascript | ||
| const web = new WebClient(this.slack.$auths.oauth_access_token); | ||
| const web = new WebClient(this.slack.$auth.oauth_access_token); | ||
| ``` | ||
|
|
||
| Where did `this.slack` come from? Good question. It was generated by the definition we made in `props`: | ||
|
|
@@ -62,7 +62,7 @@ export default defineComponent({ | |
| // ... rest of the Node.js step | ||
| ``` | ||
|
|
||
| The Slack access token is generated by Pipedream, and is available to this step in the `this.slack.$auths` object: | ||
| The Slack access token is generated by Pipedream, and is available to this step in the `this.slack.$auth` object: | ||
|
|
||
| ```javascript | ||
| export default defineComponent({ | ||
|
|
@@ -83,18 +83,12 @@ export default defineComponent({ | |
|
|
||
| `this.appName.$auths` contains named properties for each account you connect to the associated step. Here, we connected Slack, so `this.slack.$auths` contains the Slack auth info (the `oauth_access_token`). | ||
|
|
||
| You can view the named properties of the `this.appName.$auths` object for connected accounts next to the account connections: | ||
|
|
||
| <div> | ||
| <img alt="Slack auths object" width="500" src="./images/auths-property.png"> | ||
| </div> | ||
|
|
||
| The names of the properties for each connected account will differ with the account. Pipedream typically exposes OAuth access tokens as `oauth_access_token`, and API keys under the property `api_key`. But if there's a service-specific name for the tokens (for example, if the service calls it `server_token`), we prefer that name, instead. | ||
|
|
||
| To list the `this.[app name].$auths` properties available to you for a given app, run `Object.keys` on the app: | ||
|
|
||
| ```javascript | ||
| console.log(Object.keys(this.slack.$auths)) // Replace auths.slack with your app's name | ||
| console.log(Object.keys(this.slack.$auth)) // Replace this.slack with your app's name | ||
| ``` | ||
|
|
||
| and run your workflow. You'll see the property names in the logs below your step. | ||
|
|
@@ -111,11 +105,7 @@ When you search for an app in a step: | |
|
|
||
| 1. Click the **+** button below any step. | ||
| 2. Search for the app you're looking for and select it from the list. | ||
| 3. Select the option to **Run Node.js code with [app]**. | ||
|
|
||
| <div> | ||
| <img alt="Slack test request" width="400" src="./images/run-node-with-slack.png"> | ||
| </div> | ||
| 3. Select the option to **Use any [app] API**. | ||
|
|
||
| This code operates as a template you can extend, and comes preconfigured with the connection to the target app and the code for authorizing requests to the API. You can modify this code however you'd like. | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.