|
| 1 | +--- |
| 2 | +title: 'Pass data between stages' |
| 3 | +meta_title: 'Pass data between stages | Introduction to Appbase.io' |
| 4 | +meta_description: 'Learn how to pass data between pipeline stages' |
| 5 | +keywords: |
| 6 | + - concepts |
| 7 | + - appbase.io |
| 8 | + - elasticsearch |
| 9 | + - pipelines |
| 10 | + - reactivesearch |
| 11 | + - stages |
| 12 | +sidebar: 'docs' |
| 13 | +--- |
| 14 | + |
| 15 | +Passing data between stages can be considered one of the most essential parts of pipelines. Since we provide quite a lot of pre-built stages, it is essential that the data between them is shared in some way and is passable from one stage to another. |
| 16 | + |
| 17 | +This can be achieved by writing the data to the `context` and accessing them through the `context`. |
| 18 | + |
| 19 | +## What is Context |
| 20 | + |
| 21 | +Every stage in the pipeline has access to a `context` variable. `context` is a JSON object that contains details about the pipeline being executed. Some of the keys that are populated in the context are: |
| 22 | + |
| 23 | +- `request` |
| 24 | +- `response` |
| 25 | +- `envs` |
| 26 | + |
| 27 | +Here's an example context: |
| 28 | + |
| 29 | +```json |
| 30 | +{ |
| 31 | + "request": { |
| 32 | + "body": "{\"query\": [{\"id\": \"some ID\", \"value\": \"search term\", \"dataField\": [\"text\"]}]}", |
| 33 | + "headers": { |
| 34 | + "Content-Type": "application/json" |
| 35 | + } |
| 36 | + }, |
| 37 | + "envs": { |
| 38 | + "someEnvKey": "test" |
| 39 | + }, |
| 40 | + "response": { |
| 41 | + "body": "" |
| 42 | + } |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +Note that `envs` key will contain an object where key and values are populated from the pipeline config or per stage `envs`. |
| 47 | + |
| 48 | +> `request.body` and `response.body` are stringified JSON. This is because some ElasticSearch endpoints support non JSON data like nd-json. |
| 49 | +
|
| 50 | +## How to write/access context data |
| 51 | + |
| 52 | +### Writing to context |
| 53 | + |
| 54 | +Anything can be written to the context. Since it is just a JSON object, it can be easily modified from a custom JavaScript stage. |
| 55 | + |
| 56 | +Let's say we want to add a field `customData` to the context with the value `{'test': 'nothing here'}`. We can do that with the following JavaScript script: |
| 57 | + |
| 58 | +```js |
| 59 | +function handleRequest() { |
| 60 | + return { |
| 61 | + customData: { |
| 62 | + test: "nothing here" |
| 63 | + } |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +Once we have the script defined, we can just define the stage like this: |
| 69 | + |
| 70 | +```yml |
| 71 | +- id: add custom data |
| 72 | + scriptRef: addCustom.js |
| 73 | +``` |
| 74 | +
|
| 75 | +> Assuming the above JS script is named as `addCustom.js`. |
| 76 | + |
| 77 | +### Accessing from context |
| 78 | + |
| 79 | +Field can be easily accessed from the context. Let's say we have a script that needs to access the `customData` field from above, that can be done in the following way: |
| 80 | + |
| 81 | +```js |
| 82 | +customData = context.customData; |
| 83 | +``` |
| 84 | + |
| 85 | +> Every script that is running is populated with a `context` variable that contains the latest updated context in that stage of the pipeline. |
| 86 | + |
| 87 | +### Things to note |
| 88 | + |
| 89 | +All stages can modify context but stages that run asychronously come with a downside. Stages can be run asynchronously by setting the `async: true` flag while defining the pipeline. |
| 90 | + |
| 91 | +However, stages that run with the above flag are not allowed to update **already existing** fields in the context. This means that if a stage has a script that runs asynchronously, it cannot modify the `request.body` value or any value that exists in the context from before. |
| 92 | + |
| 93 | +It can, however, **add new fields** to the context that can be accessed in further stages. |
| 94 | + |
| 95 | +## Example Scenario: Dynamic input |
| 96 | + |
| 97 | +Let's take the example of the `replaceWords`. We have to pass the input to `replaceWords` through the `inputs.data` field. |
| 98 | + |
| 99 | +Following is how we replace the term `test` with `not test` in the search term: |
| 100 | + |
| 101 | +```yml |
| 102 | +- id: replace search term |
| 103 | + use: replaceWords |
| 104 | + inputs: |
| 105 | + data: |
| 106 | + test: not test |
| 107 | +``` |
| 108 | + |
| 109 | +This is pretty straight forward, however, if we want to make the input dynamic, we can do that through context. Let's say before the above stage runs we have another stage that adds a `replaceWordDetails` field to the context: |
| 110 | + |
| 111 | +```yml |
| 112 | +- id: populate details |
| 113 | + script: "function handleRequest() { return { replaceWordDetails: {'test': 'not test'} } }" |
| 114 | +``` |
| 115 | + |
| 116 | +We can then directly pass this context field to the `replaceWords` stage as an input in the following way: |
| 117 | + |
| 118 | +```yml |
| 119 | +- id: replace search term |
| 120 | + needs: |
| 121 | + - populate details |
| 122 | + inputs: |
| 123 | + data: "{{replaceWordDetails}}" |
| 124 | +``` |
| 125 | + |
| 126 | +> Note that we are using the `needs` field to make sure that the populate details stage runs before the replace search term stage in order to have the `replaceWordDetails` field populated. |
0 commit comments