A specialized datasource for the GitHub REST API with pre-configured methods for common GitHub operations.
interface GithubApiConfig extends RestApiConfig {
personalAccessToken?: string; // GitHub Personal Access Token
defaultOrg?: string; // Default organization
defaultRepo?: string; // Default repository
apiVersion?: string; // API version (defaults to 'v3')
}import { DatasourceCatalog } from '@statuscompliance/databinder';
import { GithubApiDatasource } from '@statuscompliance/databinder/datasources';
const catalog = new DatasourceCatalog();
catalog.registerDatasource(GithubApiDatasource);
const githubApi = catalog.createDatasourceInstance('github-api', {
personalAccessToken: 'ghp_xxxxxxxxxxxx',
defaultOrg: 'octocat',
defaultRepo: 'Hello-World',
apiVersion: 'v3'
}, 'github-instance');
const linker = new Linker({ datasources: [githubApi] });
const dataBinder = new DataBinder({ linker });Fetches user information.
// Get authenticated user
const user = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getUser'
});
// Get specific user
const user = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getUser',
username: 'octocat'
});Fetches repository information.
const repo = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getRepository',
owner: 'octocat',
repo: 'Hello-World'
});Fetches repositories for a user or organization.
const repos = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getRepositories',
owner: 'octocat',
type: 'public', // 'public', 'private', 'all'
sort: 'updated',
direction: 'desc',
pagination: {
enabled: true,
pageSize: 30
}
});Fetches issues from a repository.
const issues = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getIssues',
owner: 'octocat',
repo: 'Hello-World',
state: 'open', // 'open', 'closed', 'all'
labels: ['bug', 'help wanted'],
sort: 'created',
direction: 'desc'
});Fetches a specific issue.
const issue = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getIssue',
owner: 'octocat',
repo: 'Hello-World',
issueNumber: 42
});Fetches pull requests from a repository.
const prs = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getPullRequests',
owner: 'octocat',
repo: 'Hello-World',
state: 'open',
sort: 'updated',
direction: 'desc'
});Fetches a specific pull request.
const pr = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getPullRequest',
owner: 'octocat',
repo: 'Hello-World',
pullNumber: 123
});Fetches file or directory contents from a repository.
const content = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getContents',
owner: 'octocat',
repo: 'Hello-World',
path: 'README.md',
ref: 'main' // optional branch/tag/commit
});Searches for code across GitHub.
const results = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'searchCode',
query: 'addClass in:file language:js repo:jquery/jquery'
});Searches for issues and pull requests.
const results = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'searchIssues',
query: 'is:issue is:open label:bug repo:octocat/Hello-World'
});If you set defaultOrg and defaultRepo in the configuration, you can omit them from method calls:
const githubApi = catalog.createDatasourceInstance('github-api', {
personalAccessToken: 'ghp_xxxxxxxxxxxx',
defaultOrg: 'octocat',
defaultRepo: 'Hello-World'
}, 'github-instance');
// Now you can omit owner and repo
const issues = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getIssues',
state: 'open'
});GitHub API responses are automatically paginated:
const repos = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getRepositories',
owner: 'octocat',
pagination: {
enabled: true,
pageSize: 100, // Max is 100 for GitHub API
startPage: 1
}
});const issues = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getIssues',
owner: 'octocat',
repo: 'Hello-World',
state: 'all',
labels: ['bug', 'critical'],
sort: 'comments', // 'created', 'updated', 'comments'
direction: 'desc', // 'asc', 'desc'
since: '2024-01-01T00:00:00Z'
});The recommended way to authenticate is using a Personal Access Token:
{
personalAccessToken: 'ghp_xxxxxxxxxxxx'
}Depending on your use case, you may need different scopes for your token:
repo- Full control of private repositoriespublic_repo- Access to public repositoriesread:org- Read organization membershipuser- Read user profile data
GitHub API has rate limits:
- Authenticated requests: 5,000 requests per hour
- Unauthenticated requests: 60 requests per hour
The datasource includes retry logic to handle rate limiting automatically.
try {
const repo = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getRepository',
owner: 'nonexistent',
repo: 'repo'
});
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Repository not found');
} else if (error instanceof AuthenticationError) {
console.log('Invalid token or insufficient permissions');
}
}- Use Personal Access Tokens instead of password authentication
- Set appropriate scopes for your token (principle of least privilege)
- Handle rate limits gracefully
- Use pagination for large result sets
- Cache responses when appropriate to reduce API calls
- Monitor your rate limit usage
const repos = ['repo1', 'repo2', 'repo3'];
const allIssues = [];
for (const repo of repos) {
const issues = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getIssues',
owner: 'my-org',
repo,
state: 'all'
});
allIssues.push(...issues.data);
}const securityIssues = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'searchIssues',
query: 'is:open label:security org:my-org'
});async function getDirectoryContents(owner, repo, path = '') {
const contents = await dataBinder.fetchFromDatasource('github-instance', {
methodName: 'getContents',
owner,
repo,
path
});
const files = [];
for (const item of contents.data) {
if (item.type === 'file') {
files.push(item);
} else if (item.type === 'dir') {
const subFiles = await getDirectoryContents(owner, repo, item.path);
files.push(...subFiles);
}
}
return files;
}For more details on the GitHub API, visit: