Kryve Studio - GitHub API PHP wrapper untuk GitHub REST API

Introduction

Library PHP sederhana untuk mengakses GitHub REST API. Dibangun dengan cURL dan JSON, tanpa dependensi HTTP library tambahan. Setiap response dikembalikan sebagai array PHP.

Package ini dibuat oleh Kryve Studio dan dirilis sebagai open-source.


Installation

Via Composer

composer require kryvestudio/github-api

Requirements


Authentication

GitHub API butuh token untuk sebagian besar endpoint (terutama yang private atau write). Library ini support 3 metode auth:

Metode Constructor Kapan dipakai
Bearer Token new Client($token) Recommended: token doang, ga perlu username
Basic Auth new Client($token, $baseUrl, $username) Kalau API butuh username:password (legacy)
No Auth new Client() Public endpoints aja (rate limit lebih rendah)
Recommended: Gunakan Bearer Token. Buat token di github.com/settings/tokens.

Quickstart

Contoh paling sederhana: ambil data user publik tanpa token:

<?php

require __DIR__ . '/vendor/autoload.php';

use Kryve\GithubApi\Client;

$client = new Client();
$user = $client->get('/users/kryvestudio');

echo "Login: {$user['login']}\n";
echo "Nama: " . ($user['name'] ?? '-') . "\n";
echo "Bio: " . ($user['bio'] ?? '-') . "\n";

Bearer Token

Set token di environment variable GITHUB_TOKEN, lalu baca pake getenv():

<?php

require __DIR__ . '/vendor/autoload.php';

use Kryve\GithubApi\Client;
use Kryve\GithubApi\Api\User;
use Kryve\GithubApi\Api\Repos;

$token = getenv('GITHUB_TOKEN') ?: null;
$client = new Client($token);

$user = new User($client);
$data = $user->get('kryvestudio');
echo "Bio: {$data['bio']}\n";

$repos = new Repos($client);
$list = $repos->forUser('kryvestudio');
echo "Total repo: " . count($list) . "\n";

Basic Auth

Kalau perlu Basic Auth (misal token + username), tinggal tambah parameter ketiga:

<?php

require __DIR__ . '/vendor/autoload.php';

use Kryve\GithubApi\Client;

$client = new Client(
    token: 'ghp_xxxxx',
    baseUrl: 'https://api.github.com',
    username: 'kryvestudio'
);

$result = $client->get('/user');
print_r($result);
Catatan: GitHub udah deprecate password-based Basic Auth. Pake Bearer Token aja kecuali ada alasan khusus.

No Auth (Public)

Tanpa token, cuma bisa akses endpoint publik. Rate limit lebih rendah (60 req/jam vs 5000 req/jam kalau pake token).

<?php

require __DIR__ . '/vendor/autoload.php';

use Kryve\GithubApi\Client;

$client = new Client();
$user = $client->get('/users/kryvestudio');

Client API Reference

Kryve\GithubApi\Client adalah class inti yang handle semua komunikasi HTTP via cURL.

__construct(?string $token, string $baseUrl, ?string $username)

Parameter Type Default Deskripsi
$token ?string null GitHub personal access token
$baseUrl string 'https://api.github.com' Base URL API (ganti kalau pake GitHub Enterprise)
$username ?string null Username untuk Basic Auth (optional)

get(string $endpoint, array $params): array

Kirim GET request ke endpoint GitHub API.

Parameter Type Deskripsi
$endpoint string Path endpoint, misal '/users/kryvestudio'
$params array Query parameters (optional), misal ['per_page' => 100]

Return: array - response JSON yang sudah di-decode.

Throws: ApiException kalau HTTP status ≥ 400 atau ada error cURL.

Tips: Parameter query otomatis di-encode pake http_build_query(). Contoh: $client->get('/search/users', ['q' => 'kryve']).

User API

Kryve\GithubApi\Api\User

<?php

use Kryve\GithubApi\Client;
use Kryve\GithubApi\Api\User;

$client = new Client(getenv('GITHUB_TOKEN') ?: null);
$user = new User($client);

// GET /users/:username
$data = $user->get('kryvestudio');

echo $data['login'];       // "kryvestudio"
echo $data['name'];        // "Kryve Studio"
echo $data['bio'];         // "Indie web dev studio..."
echo $data['public_repos'];// 12
echo $data['followers'];   // 5
Method Endpoint Return
get(string $username) GET /users/:username array

Repos API

Kryve\GithubApi\Api\Repos

<?php

use Kryve\GithubApi\Client;
use Kryve\GithubApi\Api\Repos;

$client = new Client(getenv('GITHUB_TOKEN') ?: null);
$repos = new Repos($client);

// Repositori milik user
$userRepos = $repos->forUser('kryvestudio');
foreach ($userRepos as $repo) {
    echo $repo['name'] . ' - ' . ($repo['description'] ?? '-') . "\n";
}

// Repositori milik organisasi
$orgRepos = $repos->forOrg('laravel');
echo "Total repo Laravel: " . count($orgRepos) . "\n";

// Dengan query params
$filtered = $repos->forUser('kryvestudio', ['type' => 'public', 'per_page' => 5]);
Method Endpoint Return
forUser(string $username, array $params) GET /users/:username/repos array
forOrg(string $org, array $params) GET /orgs/:org/repos array

Parameter $params bisa diisi:

Issues API

Kryve\GithubApi\Api\Issues

<?php

use Kryve\GithubApi\Client;
use Kryve\GithubApi\Api\Issues;

$client = new Client(getenv('GITHUB_TOKEN') ?: null);
$issues = new Issues($client);

// GET /repos/:owner/:repo/issues
$list = $issues->list('laravel', 'framework');

foreach ($list as $issue) {
    echo "[{$issue['state']}] {$issue['title']} - @{$issue['user']['login']}\n";
}

// Filter: cuma open issues, 10 per page
$openIssues = $issues->list('laravel', 'framework', [
    'state' => 'open',
    'per_page' => 10,
]);
Method Endpoint Return
list(string $owner, string $repo, array $params) GET /repos/:owner/:repo/issues array

Parameter $params bisa diisi:


Error Handling

Semua error (HTTP 400+) dan error cURL dilempar sebagai Kryve\GithubApi\Exception\ApiException.

ApiException

<?php

use Kryve\GithubApi\Client;
use Kryve\GithubApi\Exception\ApiException;

$client = new Client();

try {
    $client->get('/users/nonexistent_user_xyz');
} catch (ApiException $e) {
    echo "Message: " . $e->getMessage() . "\n";       // "Not Found"
    echo "HTTP Code: " . $e->getCode() . "\n";        // 404
    echo "Response Body:\n";
    print_r($e->getResponseBody());                    // array dari GitHub

    if ($e->getCode() === 404) {
        // handle not found
    } elseif ($e->getCode() === 401) {
        // handle unauthorized
    } elseif ($e->getCode() === 403) {
        // rate limited? cek $e->getResponseBody()
    }
}
Method Return Deskripsi
getMessage() string Pesan error dari GitHub (misal "Not Found")
getCode() int HTTP status code (404, 401, 500, dll)
getResponseBody() ?array Full response JSON dari GitHub (nullable)
Error umum:
  • 401 - token invalid / expired
  • 403 - rate limit exceeded / forbidden
  • 404 - resource gak ditemukan (user, repo, dll)
  • 422 - validation error (parameter salah)

Testing

Library ini pake PHPUnit untuk integration test (panggil API asli).

composer test

Atau langsung:

vendor\bin\phpunit

Contoh test yang ada:

<?php

namespace Kryve\GithubApi\Tests;

use PHPUnit\Framework\TestCase;
use Kryve\GithubApi\Client;
use Kryve\GithubApi\Exception\ApiException;

class ClientTest extends TestCase
{
    private Client $client;

    protected function setUp(): void
    {
        $token = getenv('GITHUB_TOKEN') ?: null;
        $this->client = new Client($token);
    }

    public function testGetUserReturnsArray(): void
    {
        $result = $this->client->get('/users/kryvestudio');
        $this->assertIsArray($result);
        $this->assertArrayHasKey('login', $result);
    }

    public function testInvalidEndpointThrowsException(): void
    {
        $this->expectException(ApiException::class);
        $this->client->get('/users/nonexistent_user_xyz_999');
    }
}

Project Structure

├── src/
│   ├── Client.php              # HTTP client utama (cURL wrapper)
│   ├── Api/
│   │   ├── User.php            # GET /users/:username
│   │   ├── Repos.php           # GET /orgs/:org/repos & /users/:username/repos
│   │   └── Issues.php          # GET /repos/:owner/:repo/issues
│   └── Exception/
│       └── ApiException.php    # Custom exception
├── tests/
│   └── ClientTest.php          # PHPUnit integration tests
├── docs/
│   └── index.html              # Dokumentasi ini
├── composer.json
├── phpunit.xml
├── .gitignore
├── .env.example
└── README.md
Best Practice: Mau nambah endpoint API baru? Tinggal bikin file baru di src/Api/, isi class dengan constructor terima Client, dan panggil $this->client->get('/path/baru').