Skip to content

Commit

Permalink
Merge pull request #8 from highsidelabs/2.x
Browse files Browse the repository at this point in the history
v2.x
  • Loading branch information
jlevers committed Aug 6, 2024
2 parents 0b614d3 + 24912df commit 55316ce
Show file tree
Hide file tree
Showing 20 changed files with 514 additions and 552 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Validate, lint, and test

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
php: [8.2, 8.3]

steps:
- uses: actions/checkout@v3

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Lint
run: php vendor/bin pint --test

- name: Run test suite
run: vendor/bin/phpunit
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ composer.lock
.php-cs-fixer.cache

vendor/
.idea/
.phpunit.cache/
100 changes: 36 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p align="center">
<a href="https://highsidelabs.co" target="_blank">
<img src="https://github.com/highsidelabs/.github/blob/main/images/logo.png?raw=true" width="125">
<img src="https://github.com/highsidelabs/.github/blob/main/images/logo.png?raw=true" width="125" alt="Highside Labs logo">
</a>
</p>

Expand Down Expand Up @@ -65,46 +65,42 @@ This library has two modes:
1. Publish the config file:

```bash
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="config"
$ php artisan vendor:publish --tag="spapi-config"
```

2. Add these environment variables to your `.env`:

```env
SPAPI_AWS_ACCESS_KEY_ID=
SPAPI_AWS_SECRET_ACCESS_KEY=
SPAPI_LWA_CLIENT_ID=
SPAPI_LWA_CLIENT_SECRET=
SPAPI_LWA_REFRESH_TOKEN=
# Optional
# SPAPI_AWS_ROLE_ARN=
# SPAPI_ENDPOINT_REGION=
```

If in Seller Central, you configured your SP API app with an IAM role ARN rather than an IAM user ARN, you'll need to put that ARN in the `SPAPI_AWS_ROLE_ARN` environment variable. Otherwise, you can leave it blank. Set `SPAPI_ENDPOINT_REGION` to the region code for the endpoint you want to use (EU for Europe, FE for Far East, or NA for North America).

You're ready to go!
Set `SPAPI_ENDPOINT_REGION` to the region code for the endpoint you want to use (EU for Europe, FE for Far East, or NA for North America). The default is North America.

### Usage

All of the API classes supported by [jlevers/selling-partner-api](https://github.com/jlevers/selling-partner-api#supported-api-segments) can be type-hinted. This example assumes you have access to the `Selling Partner Insights` role in your SP API app configuration (so that you can call `SellersV1Api::getMarketplaceParticipations()`), but the same principle applies to type-hinting any other Selling Partner API class.
`SellerConnector` and `VendorConnector` can be type-hinted, and the connector classes can be used to create instances of all APIs supported by [jlevers/selling-partner-api](https://github.com/jlevers/selling-partner-api#supported-api-segments). This example assumes you have access to the `Selling Partner Insights` role in your SP API app configuration (so that you can call `SellingPartnerApi\Seller\SellersV1\Api::getMarketplaceParticipations()`), _but the same principle applies to calling any other Selling Partner API endpoint._

```php
use Illuminate\Http\JsonResponse;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\ApiException;
use Saloon\Exceptions\Request\RequestException;
use SellingPartnerApi\Seller\SellerConnector;

class SpApiController extends Controller
{
public function index(SellersApi $api): JsonResponse
public function index(SellerConnector $connector): JsonResponse
{
try {
$api = $connector->sellersV1();
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
return response()->json($result->json());
} catch (RequestException $e) {
$response = $e->getResponse();
return response()->json($response->json(), $e->getStatus());
}
}
}
Expand All @@ -119,18 +115,16 @@ class SpApiController extends Controller

```bash
# Publish config/spapi.php file
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="config"
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider"
```

2. Update the configuration to support multi-seller usage.
* Change the `installation_type` in `config/spapi.php` to `multi`.
* If the different sets of seller credentials you plan to use aren't all associated with the same set of AWS credentials (access key ID, secret access key, and optionally role ARN), make sure to change the `aws.dynamic` key to true. If you don't make that change before running migrations (the next step), the fields for AWS credentials won't be added to the database. (If you're not sure if this change applies to you, it probably doesn't.)
2. Change the `installation_type` in `config/spapi.php` to `multi`.

3. Publish the multi-seller migrations:

```bash
# Publish migrations to database/migrations/
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="multi"
$ php artisan vendor:publish --tag="spapi-multi-seller"
```


Expand All @@ -140,22 +134,16 @@ $ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartne
$ php artisan migrate
```

5. Add these environment variables to your `.env` (unless you changed the `aws.dynamic` configuration flag to `true` in step 2):

```env
SPAPI_AWS_ACCESS_KEY_ID=
SPAPI_AWS_SECRET_ACCESS_KEY=
```

### Usage

First you'll need to create a `Seller`, and some `Credentials` for that seller. The `Seller` and `Credentials` models work just like any other Laravel model.

```php
use HighsideLabs\LaravelSpApi\Models;
use HighsideLabs\LaravelSpApi\Models\Credentials;
use HighsideLabs\LaravelSpApi\Models\Seller;

$seller = Models\Seller::create(['name' => 'MySeller']);
$credentials = Models\Credentials::create([
$seller = Seller::create(['name' => 'My Seller']);
$credentials = Credentials::create([
'seller_id' => $seller->id,
// You can find your selling partner ID/merchant ID by going to
// https://<regional-seller-central-domain>/sw/AccountInfo/MerchantToken/step/MerchantToken
Expand All @@ -167,52 +155,36 @@ $credentials = Models\Credentials::create([
'client_secret' => 'fec9/aw....',
// The LWA refresh token for this seller
'refresh_token' => 'IWeB|....',

// If you have the `aws.dynamic` config flag set to true, you'll also need these attributes:
// 'access_key_id' => 'AKIA....',
// 'secret_access_key' => '23pasdf....',
// // Only necessary if you configured your SP API setup with an IAM role ARN, otherwise can be omitted
// // 'role_arn' => 'arn:aws:iam::....',
]);
```

Once you have credentials in the database, you can use them like this:
Once you have credentials in the database, you can use them to retrieve a `SellerConnector` instance, from which you can get an instance of any seller API:

```php
use HighsideLabs\LaravelSpApi\Models\Credentials;
use Illuminate\Http\JsonResponse;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\ApiException;
use Saloon\Exceptions\Request\RequestException;

class SpApiController extends Controller
{
public function __construct(SellersApi $api)
{
// Retrieve the credentials we just created
$creds = Credentials::first();
$this->api = $creds->useOn($api);
// You can now make calls to the SP API with $creds using $this->api!
}

public function index(): JsonResponse
{
try {
$result = $this->api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
$creds = Credentials::first();
/** @var SellingPartnerApi\Seller\SellersV1\Api $api */
$api = $creds->sellerConnector()->sellersV1();

try {
$result = $api->getMarketplaceParticipations();
$dto = $result->dto();
} catch (RequestException $e) {
$responseBody = $e->getResponse()->json();
}
```

Or, if you want to use a Selling Partner API class without auto-injecting it, you can quickly create one like this:
The same goes for a `VendorConnector` instance:

```php
use HighsideLabs\LaravelSpApi\SellingPartnerApi;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use HighsideLabs\LaravelSpApi\Models\Credentials;
use Illuminate\Http\JsonResponse;
use Saloon\Exceptions\Request\RequestException;

$creds = Credentials::first();
$api = SellingPartnerApi::makeApi(SellersApi::class, $creds);
/** @var SellingPartnerApi\Vendor\DirectFulfillmentShippingV1\Api $api */
$api = $creds->vendorConnector()->directFulfillmentShippingV1();
```
25 changes: 16 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "highsidelabs/laravel-spapi",
"type": "library",
"description": "A Laravel wrapper for Amazon's Selling Partner API (via jlevers/selling-partner-api)",
"version": "1.2.2",
"license": "BSD-3-Clause",
"keywords": [
"laravel",
Expand All @@ -21,22 +20,30 @@
}
],
"require": {
"php": "^8.0.2|>=8.1",
"illuminate/support": "^9.41|^10.0",
"illuminate/database": "^9.41|^10.0",
"illuminate/cache": "^9.41|^10.0",
"jlevers/selling-partner-api": "^5.9"
"php": ">=8.2",
"illuminate/support": "^11.0",
"illuminate/database": "^11.0",
"illuminate/cache": "^11.0",
"jlevers/selling-partner-api": "^7.1"
},
"require-dev": {
"laravel/pint": "^1.17",
"phpunit/phpunit": "^11.2",
"orchestra/testbench": "^9.2"
},
"autoload": {
"psr-4": {
"HighsideLabs\\LaravelSpApi\\": "src/"
}
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.13"
"autoload-dev": {
"psr-4": {
"HighsideLabs\\LaravelSpApi\\Tests\\": "tests/"
}
},
"scripts": {
"lint": "vendor/bin/php-cs-fixer fix ."
"lint": "vendor/bin/pint",
"test": "vendor/bin/phpunit --configuration ./phpunit.dist.xml"
},
"extra": {
"laravel": {
Expand Down
9 changes: 1 addition & 8 deletions config/spapi.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
return [
'installation_type' => 'single',

'aws' => [
'dynamic' => false,
'access_key_id' => env('SPAPI_AWS_ACCESS_KEY_ID'),
'secret_access_key' => env('SPAPI_AWS_SECRET_ACCESS_KEY'),
'role_arn' => env('SPAPI_AWS_ROLE_ARN'),
],

'single' => [
'lwa' => [
'client_id' => env('SPAPI_LWA_CLIENT_ID'),
Expand All @@ -22,5 +15,5 @@
],

'debug' => env('SPAPI_DEBUG', false),
'debug_file' => env('SPAPI_DEBUG_FILE', 'php://output'),
'debug_file' => env('SPAPI_DEBUG_FILE'),
];
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateSpapiSellersTable extends Migration
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Expand All @@ -24,11 +22,9 @@ public function up(): void

/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::drop('spapi_sellers');
}
}
};
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
<?php

use HighsideLabs\LaravelSpApi\SellingPartnerApi;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use SellingPartnerApi\Enums\Region;

class CreateSpApiCredentialsTable extends Migration
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Expand All @@ -30,7 +28,7 @@ public function up(): void
$table->string('selling_partner_id')->unique();

// The SP API region that these credentials are for
$table->enum('region', SellingPartnerApi::REGIONS);
$table->enum('region', Region::values());

// The app credentials that the the refresh token was created with
$table->string('client_id');
Expand All @@ -40,26 +38,14 @@ public function up(): void

// The seller these credentials are associated with
$table->foreignId('seller_id')->constrained('spapi_sellers');

// If SP API calls will only be happening with a single set of AWS credentials (meaning
// all the credentials are authorized on the same application), these columns will be
// skipped. Otherwise, they are needed to specify the AWS keys for each set of credentials.
if (config('spapi.aws.dynamic')) {
$table->string('access_key_id');
$table->string('secret_access_key');
$table->string('role_arn')->nullable();
}
});

}

/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::drop('spapi_credentials');
}
}
};
Loading

0 comments on commit 55316ce

Please sign in to comment.