# HTTP paginated

HTTP paginated action will help you fetch the data from paginated HTTP API endpoint. UI is similar to Postman but important thing to keep in mind is you can reference the data in **ctx** from previous actions and you can use JavaScript in the expression fields that have JS syntax highlighting.

Currently we only support JSON with HTTP paginated, if you will require SOAP of anything else you will for now have to resort to using [Expression action](expression) and rolling your own logic. We are planing to add UI support similar to Postman in the future.\
\
Endpoint name is non functional this is just for easier tracking in the left side actions panel. Right below endpoint name there is a drop-down field where you select HTTP request method (GET or POST).

### HTTP Endpoint

<div align="left"><figure><img src="https://296734879-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlDOQVFjSsWJSm47zpFE%2Fuploads%2Fynamo3rO9y8F2sktCBQb%2FHTTP%20endpoint.png?alt=media&#x26;token=a66764ed-807e-4b2b-8e54-92c06f1341de" alt=""><figcaption></figcaption></figure></div>

**Important note:** currently you can not use JavaScript in HTTP URL, we will change that in the future to enable dynamic URLs and using **ctx** variables as URL.

### HTTP Headers

Next lets tackle Authorization headers. Headers are specified as string key non script-able and value that is a JavaScript expression, think of this as ``{ "Authorization": `Bearer ${env.apiKey}`}``.

<div align="left"><figure><img src="https://296734879-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlDOQVFjSsWJSm47zpFE%2Fuploads%2FUOrtLyAlBQ0lvTGzoFXA%2FHTTP%20headers.png?alt=media&#x26;token=0904b3c6-aa17-45c8-bc39-072b006032fe" alt=""><figcaption></figcaption></figure></div>

You can see we are referencing **env.apiKey** for a bearer token, we recommend that you use [workflow environment variables](../workflow-env-variables) marked as secret to specify any sensitive data.

<figure><img src="https://296734879-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlDOQVFjSsWJSm47zpFE%2Fuploads%2FzK2oL2ppjBhkSxvJluvd%2FWorkflow%20env%20vars.png?alt=media&#x26;token=3273f094-9496-4f1d-8d0a-aa6a759e7fb0" alt=""><figcaption></figcaption></figure>

Depending on what query parameters or body parameters your request requires you will need to specify those as well.

### HTTP Query Parameters

Lets start with HTTP query parameters. Same rules apply left side key is just a string and right side is JavaScript expression. Query parameters will be applied to URL in this case `https://api.stripe.com/v1/products?limit=50&shippable=false`

<div align="left"><figure><img src="https://296734879-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlDOQVFjSsWJSm47zpFE%2Fuploads%2FhF3wSmEUMwAKvaRPTdOl%2FHTTP%20query%20params.png?alt=media&#x26;token=5243e887-6608-43c4-adf4-ffd7cb934bcf" alt=""><figcaption></figcaption></figure></div>

### HTTP POST Body

When doing HTTP POST request you will have to first select POST next to your endpoint and then new body tab will appear. Syntax for specifying body is a bit different, you have to write keys as a string.

<div align="left"><figure><img src="https://296734879-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlDOQVFjSsWJSm47zpFE%2Fuploads%2FY3k0M9BJl8xu83vYWFnZ%2FHTTP%20POST%20body.png?alt=media&#x26;token=74b44c1e-af73-4f05-8384-c3612328330c" alt=""><figcaption></figcaption></figure></div>

### HTTP Script

There is an additional tab called Script that is meant to provide more flexibility, you can express all of the above UI concept directly in JavaScript code in there. You will have access to some variables that are passed to you and predefined as:

```javascript
const headers = new Headers()
const params = new URLSearchParams()
let body = undefined
// Those are predefined by the action you should not redefine those in your code!
```

Example of how the Script tab expression would look like for some of the examples we have done in the UI so far and one additional use case with if statement.

```javascript
headers.append("Authorization", `Bearer ${env.apiKey}`)

body = JSON.stringify({
    name: "New product name",
    active: true
})

params.append("limit", 50)
if (ctx.lastItemId !== null) {
  params.append("starting_after", ctx.lastItemId)
}
```

### End Pagination On

Next you need to specify the JavaScript expression for **End pagination on**. By default this should be true so that action will stop after fetching first set of data, when you validate that everything is functioning, write the termination case that makes sense for your pagination.\
\
Some HTTP APIs return **has\_more** boolean as part of response, some return **next\_item** cursor and null if there are no more pages, and some endpoints just do not return any indicator. For no indicator in response, your logic should be if you have requested 50 items by specific some limit API parameter, then check if there is less the 50 items returned you know there is not next page and you should terminate.\
\
"End pagination on" Examples:

```javascript
// {data: {data: [], has_more: true} }
ctx.res.data.has_more === false
// {data: {data: [], next_item: "..."} }
!ctx.res.data.next_item
// req {limit: 50}  -- {data: {data: []} }
Array.isArray(ctx.res.data.data) && ctx.res.data.data.length < 50
```

### HTTP Response Result

Finally in the bottom we have **Result variable** that specifies how the result should be saved in the **ctx** object. By default this is set to **res** which means that you will have the response in the **ctx.res**

The structure of the response object will be the following.

```json
"res": {
    "data": {...},
    "ok": true,
    "status": 200,
    "statusText": ""
}
```
