npm package: @resolution/jira-api-client
Description: JIRA Platform & Software API Client based on OpenAPI Schema from Atlassian.
Author: Marat Dulin
Latest version: 0.16.8

# jira-api-client

Atlassian Jira API client based on OpenAPI schema.

Provides Clients for Jira Platform, Jira Software, and Jira Service Management APIs.

Compatible with the following request/fetch Atlassian libraries:

 * [atlassian-connect-express](https://bitbucket.org/atlassian/atlassian-connect-express)
 * [atlassian-connect-js](https://bitbucket.org/atlassian/atlassian-connect-js)
 * [@forge/api](https://developer.atlassian.com/cloud/jira/platform/forge/)
 * [@forge/bridge](https://developer.atlassian.com/cloud/jira/platform/forge/)

## Installation

Note that this package requires `zod` as a peer dependency.

Install using npm

```bash
npm add @resolution/jira-api-client zod
```

Or using yarn

```bash
yarn add @resolution/jira-api-client zod
```

## Usage

### Connect

Inside Connect iframe:

```typescript
import { JiraPlatformApi, JiraSoftwareApi } from '@resolution/jira-api-client';

async function test() {
  const jiraPlatformApi = new JiraPlatformApi({ AP: window.AP });
  const issue = await jiraPlatformApi.issues.getIssue({ issueIdOrKey: "PROJ-1" });
  console.log('Issue:', issue);

  const jiraSoftwareApi = new JiraSoftwareApi({ AP: window.AP });
  const boards = await jiraSoftwareApi.boards.getAllBoards();
  console.log('Boards:', boards);

  const jiraServiceManagementApi = new JiraServiceManagementApi({ AP: window.AP });
  const systemInfo = await jiraServiceManagementApi.info.getInfo();
  console.log('JSM Info:', systemInfo);
}

test().catch(console.error);
```

On the server side using `atlassian-connect-express`:

```typescript
import atlassianConnectExpress from 'atlassian-connect-express';
import { JiraPlatformApi, JiraSoftwareApi, JiraServiceManagementApi } from '@resolution/jira-api-client';

const app = express();
const ace = atlassianConnectExpress(app);

app.use(ace.authenticate());

app.get('/issue/:issueKey', async () => {
  const jiraPlatformApi = new JiraPlatformApi({ ace, clientKey: req.context.clientKey });
  res.status(200).send(await jiraPlatformApi.issues.getIssue({ issueIdOrKey: req.params.issueKey }));
});

app.get('/boards', async () => {
  const jiraSoftwareApi = new JiraSoftwareApi({ ace, clientKey: req.context.clientKey });
  res.status(200).send(await jiraSoftwareApi.boards.getAllBoards());
});

app.get('/system-info', async () => {
  const jiraServiceManagementApi = new JiraServiceManagementApi({ ace, clientKey: req.context.clientKey });
  res.status(200).send(await jiraServiceManagementApi.info.getInfo());
});

app.listen(3000);
```

### Forge

Inside Forge iframe:

```typescript
import { JiraPlatformApi, JiraSoftwareApi, JiraServiceManagementApi } from '@resolution/jira-api-client';
import { requestJira } from '@forge/bridge';

async function test() {
  const jiraPlatformApi = new JiraPlatformApi({ requestJira });
  const issue = await jiraPlatformApi.issues.getIssue({ issueIdOrKey: "PROJ-1" });
  console.log('Issue:', issue);

  const jiraSoftwareApi = new JiraSoftwareApi({ requestJira });
  const boards = await jiraSoftwareApi.boards.getAllBoards();
  console.log('Boards:', boards);
  
  const jiraServiceManagementApi = new JiraServiceManagementApi({ requestJira });
  const systemInfo = await jiraServiceManagementApi.info.getInfo();
  console.log('JSM Info:', systemInfo);
}

test().catch(console.error);
```

On the server side using `@forge/api`:

```typescript
import { JiraPlatformApi, JiraSoftwareApi, JiraServiceManagementApi } from '@resolution/jira-api-client';
import * as forgeApi from '@forge/api';

export const handler = async ({ payload }) => {
  const jiraPlatformApi = new JiraPlatformApi({ forgeApi });
  const issue = await jiraPlatformApi.issues.getIssue({ issueIdOrKey: payload.issueKey });

  const jiraSoftwareApi = new JiraSoftwareApi({ forgeApi });
  const boards = await jiraSoftwareApi.boards.getAllBoards();

  const jiraServiceManagementApi = new JiraServiceManagementApi({ forgeApi });
  const systemInfo = await jiraServiceManagementApi.info.getInfo();

  return { issue, boards, systemInfo };
};
```

External fetch on the server side:

```typescript
import { JiraPlatformApi, JiraSoftwareApi, JiraServiceManagementApi } from '@resolution/jira-api-client';
import { fetch } from "@forge/api";

const baseUrl = "https://your-jira-instance.atlassian.net";

export const handler = async ({ payload }) => {
  const jiraPlatformApi = new JiraPlatformApi({ fetch, baseUrl });
  const issue = await jiraPlatformApi.issues.getIssue({ issueIdOrKey: payload.issueKey });

  const jiraSoftwareApi = new JiraSoftwareApi({ fetch, baseUrl });
  const boards = await jiraSoftwareApi.boards.getAllBoards();

  const jiraServiceManagementApi = new JiraServiceManagementApi({ fetch, baseUrl });
  const systemInfo = await jiraServiceManagementApi.info.getInfo();

  return { issue, boards, systemInfo };
};
```

## Impersonalization

When using API on the server side, you can impersonalize the API client.
This is useful when you need to access API resources on behalf of a different user or app.

### `atlassian-connect-express`

By default, `atlassian-connect-express` makes requests on behalf of the app.
To impersonalize the API client, you need to provide the `userAccountId` to the API client:

```typescript
// ...
app.get('/sprint-issues/:sprintId', async () => {
  const jiraSoftwareApi = new JiraSoftwareApi({
    ace,
    clientKey: req.context.clientKey,
    userAccountId: req.context.userAccountId
  });
  res.status(200).send(await jiraSoftwareApi.sprint.getIssuesForSprint({
    sprintId: 1
  }));
});
// ...
```

This can also be achieved by calling `asUser` method on the API client:

```typescript
const jiraSoftwareApi = new JiraSoftwareApi({
  ace,
  clientKey: req.context.clientKey
});
const issues = await jiraSoftwareApi.sprint.getIssuesForSprint({
  sprintId: 1
});
```

### `@forge/api`

By default, `@forge/api` makes requests on behalf of the current user.
To perform requests on behalf of the app, you need to provide the `asApp` to the API client:

```typescript
// ...
export const handler = async ({ payload }) => {
  const jiraSoftwareApi = new JiraSoftwareApi({
    forgeApi,
    asApp: true
  });
  return await jiraSoftwareApi.sprint.getIssuesForSprint({ sprintId: 1 });
};
```

This can also be achieved by calling `asApp` method on the API client:

```typescript
const jiraSoftwareApi = new JiraSoftwareApi({ forgeApi });
const issues = await jiraSoftwareApi.asApp().sprint.getIssuesForSprint({ sprintId: 1 });
```

## Error handling

All API methods return a promise that resolves to the response data or rejects with an `ApiError` instance.

ApiError class:

```typescript
export class ApiError extends Error {
  readonly message: string;
  readonly name: "ApiError";
  readonly url: URL;
  readonly request: CommonHttpClientFetchRequest | undefined;
  readonly response: CommonHttpClientFetchResponse | undefined;
  readonly options: CommonHttpClientOptions | undefined;
}
```

Checking response status example:

```typescript
try {
    const issue = await jiraPlatformApi.issues.getIssue({ issueIdOrKey: "PROJ-1" });
    console.log('Issue:', issue);
} catch (error) {
    if (error instanceof ApiError && error.response?.status === 404) {
        console.error('Issue not found.');
    } else {
        console.error(error);
    }
}
```

## API Documentation

 * [JiraPlatformApi](https://resolutiongmbh.bitbucket.io/docs/jira-api-client/classes/index.JiraPlatformApi.html)
 * [JiraSoftwareApi](https://resolutiongmbh.bitbucket.io/docs/jira-api-client/classes/index.JiraSoftwareApi.html)
 * [JiraServiceManagementApi](https://resolutiongmbh.bitbucket.io/docs/jira-api-client/classes/index.JiraServiceManagementApi.html)
 * [ApiError](https://resolutiongmbh.bitbucket.io/docs/jira-api-client/classes/index.ApiError.html)
 * [All the other exported types](https://resolutiongmbh.bitbucket.io/docs/jira-api-client/modules/index.html)

## References

 * [Jira Platform API](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/)
 * [Jira Software API](https://developer.atlassian.com/cloud/jira/software/rest/intro/)
 * [Atlassian Connect for JIRA](https://developer.atlassian.com/cloud/jira/platform/getting-started-with-connect/)
 * [Atlassian Forge for JIRA](https://developer.atlassian.com/cloud/jira/platform/getting-started-with-forge//)

## License

This repository is licensed under the [MIT License](./LICENSE.md).