Add javascript SDK

This commit is contained in:
Umeda 2024-02-20 12:24:32 +09:00
parent b570970365
commit 28f5a337d6
13 changed files with 5306 additions and 0 deletions

View File

@ -0,0 +1,121 @@
# Selling Partner API JavaScript client library for Node.js (v18 or later)
## About this library
This library is to help SP-API developers to create an app in JavaScript on Node.js easier than calling HTTP endpoints directly. This library comes with the following features.
1. Login with Amazon (LWA) helper that does OAuth token refresh flow.
2. This library takes care of HTTP communication with SP-API endpoints with a help of [superagent](https://www.npmjs.com/package/superagent), so you can call SP-API by just calling a right method of library that corresponds to SP-API operation.
3. Calling SP-API requires non-standard `x-amz-access-token` HTTP request header in request. The SDK generated by this library supports to include this header with token value you specify.
4. SP-API operaitons to handle restricted data are categorized as ["Restricted Operations"](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/tokens-api-use-case-guide#restricted-operations), which requires ["Restricted Data Token" (RDT)](https://developer-docs.amazon.com/sp-api/lang-ja_JP/docs/authorization-with-the-restricted-data-token) instead of access token for tighter security. Calling restricted operation involves two seprate steps, one of wihch is calling Tokens API to retrieve RDT and the other of which is calling protected operation with RDT. This library helps to compbine these two steps into single library call.
## Installation and Generating SDK
Please note this library doesn't include SDK. You need to generate SDK with the template and script files included in this library.
### Prerequisites for SDK Generation
* Java version 7 or higher
* swagger-codegen-cli (swagger-codegen-cli-2.4.29) is recommended.
* Download swagger-codegen-cli JAR file and store it. You will need its path later when generating SDK.
* Node.js v18 or higher.
__CAUTION__: Please be aware that there are two major known issues with the latest JavaScript client library.
1. If you use swagger-codegen-cli newer than 2.4.29 (such as 2.4.30 or 3.x), there is a known compatibility issue with SP-API models that makes generating SDK fail. We recommend that you use swagger-codegen-cli-2.4.29 specifically.
2. Swagger codegen tool fails to generate SDK for "Merchant Fulfillment V0 API." For workaround, you need to modify a part of the API model file "merchantFulfillmentV0.json"
### Download swagger-codegen-cli JAR file
We use `swagger-codegen-cli` executable JAR file. You can download it by the following command.
```bash
$ wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.29/swagger-codegen-cli-2.4.29.jar
```
### Installing dependencies
Change the directory to `<package root>/src`. Run the following command to install dependencies in Node.js environment.
```bash
$ npm install
```
### Download API models and Generate SDK
Go to `<package root>/src` directory which is under the package root. In this directory you should be able to find `generate-js-sdk.sh` shell script file.
Run this script as the command line below.
```bash
$ ./generate-js-sdk.sh -j <your path to swagger-codegen-cli-2.4.X.jar>
```
You will find `models` directory and `sdk` directory under the package root.<br>
* `models`: directory contains API models cloned from SP-API GitHub.
* `sdk`: directory contains generated JavaScript SDK.
### Modify Merchant Fulfillment API model file to avoid error during SDK generation
If you want to call Merchant Fulfillment API with the generated SDK, you need to follow this instruction. There is an fatal known issue in generating Merchant Fulfillment API library. If downloading API models is successful, you should be able to find `merchantFulfillmentV0.json` file In `<package root>/models/merchant-fulfillment-api-model` directory. Open this file with an editor and find the following part.
```
"AvailableFormatOptionsForLabel": {
"$ref": "#/definitions/AvailableFormatOptionsForLabelList"
},
```
Since this part causes a fatal error in SDK generation for JavaScript, please replace this part with the following snipet.
```
"AvailableFormatOptionsForLabel": {
"type": "array",
"description": "The available label formats.",
"items": {
"$ref": "#/definitions/LabelFormatOption"
}
},
```
After modification, please run the shell script (`generate-js-sdk.sh`) again but you should type 'n' to the prompt that asks whether to download models again.
```bash
$ ./generate-js-sdk.sh -j ~/devbin/swagger-codegen-cli-2.4.29.jar
Found <package root>/models already exists. Would you like to delete all the files under '<package root>/models' and clone again? [y/n]: n # answer 'n' otherwise modification will be overwritten.
```
With the correct modification in `merchantFulfillmentV0.json`, you should be able to find generated SDK for Merchant Fulfillment API.
### How to run tests
This library contains a sample programs in `sample_node_app` directory under the packagte root.<br>In order to run the program, you need to have LWA credential information saved in the file and name it `app.config.mjs` and put it `<package root>/src` directory. Because __client secret__ and __refresh token__ shouldn't be exposed, you must make sure that you don't commit this file to the repository.
```javascript
export const AppConfig = {
lwaClientId: "< LWA client ID >",
lwaClientSecret: "< LWA client secret >",
lwaRefreshToken: "< LWA refresh token >",
endpoint: "https://sandbox.sellingpartnerapi-na.amazon.com",
}
```
After you save `app.config.mjs` file, you can run the sample program`.
```bash
$ npm run test
```
---
## How to use SDK
### Calling SP-API operation with LWA credentials
```javascript
import { SellersApi, ApiClient as SellersApiClient } from '../../sdk/src/sellers/index.js';
const sellerApiClient = new SellersApiClient("https://sellingpartnerapi-na.amazon.com");
const sellerApi = new SellersApi(sellerApiClient);
sellerApiClient.enableAutoRetrievalAccessToken("<client ID>", "<client secret>", "<refresh token>");
const participations = await sellerApi.getMarketplaceParticipations();
```
### Calling RDT-required SP-API operation with LWA credentials
```javascript
import { OrdersV0Api, ApiClient as OrdersApiClient } from '../../sdk/src/ordersV0/index.js';
const ordersApiClient = new OrdersApiClient("https://sellingpartnerapi-fe.amazon.com");
ordersApiClient.enableAutoRetrievalRestrictedDataToken("<client ID>",
"<client secret>", "<refresh token>", ["buyerInfo", "shippingAddress"]);
const ordersApi = new OrdersV0Api(ordersApiClient);
const order = await ordersApi.getOrder("<order ID to retrieve>");
```
### Calling SP-API with access token
In case you manage LWA token refresh flow, you can explicitly use the access token you got yourself for your SP-API call as follows.
```javascript
import { SellersApi, ApiClient as SellersApiClient } from '../../sdk/src/sellers/index.js';
const sellerApiClient = new SellersApiClient("https://sellingpartnerapi-fe.amazon.com");
const sellerApi = new SellersApi(sellerApiClient);
sellerApiClient.applyXAmzAccessTokenToRequest("<access token you retrieve yourself>");
const participations = await sellerApi.getMarketplaceParticipations();
```
### LWA Token refresh helper
The following code shows how to use `LwaAuthClient` to execute token refresh flow.
```javascript
import { LwaAuthClient } from "<path to helper/LwaAuthClient.mjs>";
const lwaClient = new LwaAuthClient("<client ID>", "<client secret>", "<refresh token>");
const accessToken = await lwaClient.getAccessToken();
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
{
"name": "@amzn/testsellingpartnerjavascriptapilwalib",
"type": "module",
"version": "1.0.0",
"description": "The NPM package name should always start with `@amzn/` to cleanly separate from public packages, avoid accidental publish to public repository, and allow publishing to CodeArtifact.",
"main": "/src/index.mjs",
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config test_for_generated_sdk/jest.config.json"
},
"repository": {
"type": "git",
"url": "ssh://git.amazon.com/pkg/TestSellingPartnerJavaScriptApiLwaLib"
},
"author": "",
"license": "ISC",
"dependencies": {
"superagent": "^8.0.9"
},
"devDependencies": {
"jest": "^29.6.2"
}
}

View File

@ -0,0 +1,85 @@
#!/bin/bash
GITHUB_REPO="https://github.com/amzn/selling-partner-api-models.git"
BASE_DIR=$(cd "$(dirname "$0")" && cd .. && pwd)
CLONE_DIR="$BASE_DIR/models"
# Get swagger jar file path from the input arguments
swagger_jar_path=""
while getopts 'j:' flag; do
case "${flag}" in
j) swagger_jar_path="${OPTARG}"
;;
*) echo "available options are '-j'"
exit 1
;;
esac
done
if [ ! -f "$swagger_jar_path" ]; then
echo "option '-j <path_to_jar>' did not specify executable file. Aborted."
exit 1
fi
##########################################################################
if [ -d "$CLONE_DIR" ]; then
# prompt user, and if user gives "y", delete the directory.
read -p "Found $CLONE_DIR already exists. Would you like to delete all the files under '$CLONE_DIR' and clone again? [y/n]: " confirm
if [ "$confirm" == "y" ]; then
# delete all the files in the directory
rm -rf "${CLONE_DIR:?}/*"
echo "Deleted files in $CLONE_DIR directory. Recreating $CLONE_DIR again."
git clone "$GITHUB_REPO" "$CLONE_DIR"
else
echo "OK. Proceeding with the existing ${CLONE_DIR} without cloning."
fi
else
midir "$CLONE_DIR"
git clone "$GITHUB_REPO" "$CLONE_DIR"
fi
##########################################################################
TEMPLATE_DIR="$BASE_DIR/src/resources/swagger-codegen/templates"
MODEL_DIR="$CLONE_DIR/models"
SDK_DIR="$BASE_DIR/sdk"
CODEGEN_CONFIG_PATH="$BASE_DIR/src/js.config.json"
MODELS=("${MODEL_DIR}"/*/*)
basePackage="js-client"
if [ -d "$SDK_DIR" ]; then
rm -rf "${SDK_DIR:?}/*"
fi
if [ ! -d "$SDK_DIR" ]; then
mkdir "$SDK_DIR"
fi
function get_model_name () {
swaggerFile="$1"
modelNameWithExtension="${swaggerFile##*/}"
echo "${modelNameWithExtension%.*}"
}
for model in "${MODELS[@]}"
do
modelName=$(get_model_name "$model")
echo "model = $model"
echo "model name = $modelName"
java -jar "${swagger_jar_path}" generate \
--config "${CODEGEN_CONFIG_PATH}" \
--input-spec "${model}" \
--lang javascript \
--template-dir "${TEMPLATE_DIR}" \
--output "${SDK_DIR}" \
--invoker-package "${modelName}" \
--api-package "${basePackage}.${modelName}.api" \
--model-package "${basePackage}.${modelName}.model" \
--group-id "com.amazon" \
--artifact-id "sp-api-javascript-client"
done
echo "***********************************************************"
echo "SP-API SDK is created under ${SDK_DIR} and SDK source code "
echo "should be found ${SDK_DIR}/src/<API (with verion) name>."
echo "Please copy the SDK source DIRECTORIES (such as \"catalogItems_2022-04-01\")"
echo "you want to use to the directory \"code/javascript/src/jsdsdk.\"."

View File

@ -0,0 +1,59 @@
import superagent from 'superagent';
export class LwaAuthClient {
#clientId = null;
#clientSecret = null;
#refreshToken = null;
#accessToken = null;
#accessTokenExpiry = null;
/**
* Constructs a new LwaAuthClient.
* @class
* @param {String} clientId LWA client ID. Get this value from SP-API Developer Portal.
* @param {String} clientSecret LWA client secret. Get this value from SP-API Developer Portal.
* @param {String} refreshToken LWA refresh token. Get this value from SP-API Developer Portal.
*/
constructor(clientId, clientSecret, refreshToken) {
if (!clientId || typeof clientId !== 'string') {
throw new Error(`invalid clientId.`);
}
if (!clientSecret || typeof clientSecret !== 'string') {
throw new Error(`invalid clientSecret`);
}
if (!refreshToken || typeof refreshToken !== 'string') {
throw new Error(`invalid refreshToken`);
}
this.#clientId = clientId;
this.#clientSecret = clientSecret;
this.#refreshToken = refreshToken;
}
/**
* Either retrieve LWA access token or return access token if it already has valid token.
* @returns {Promise<String>} LWA access token.
*/
async getAccessToken() {
if (this.#accessToken && this.#accessToken && this.#accessTokenExpiry > Date.now()) {
console.log(`LWA access token already exists and is valid. ${this.#accessTokenExpiry}`);
return Promise.resolve(this.#accessToken);
}
const token = await this.#doRefresh();
if (!token || !token.access_token) {
throw new Error(`Failed to refresh LWA token.`);
}
this.#accessToken = token.access_token;
this.#accessTokenExpiry = new Date().getTime() + (token.expires_in * 1000);
return this.#accessToken;
}
/**
* Private method to execute LWA token refresh flow.
* @returns {Promise<Object>} LWA token response.
*/
#doRefresh = async () => {
const res = await superagent.post('https://api.amazon.com/auth/o2/token')
.send(`grant_type=refresh_token&refresh_token=${this.#refreshToken}&client_id=${this.#clientId}&client_secret=${this.#clientSecret}`)
.set("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
return res.body;
}
}

View File

@ -0,0 +1,5 @@
{
"usePromises": true,
"useES6": true,
"modelPropertyNaming": "camelCase"
}

View File

@ -0,0 +1,769 @@
{{>licenseInfo}}
import superagent from "superagent";
import querystring from "querystring";
import { URL } from 'node:url';
{{#emitJSDoc}}/**
* @module {{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient
* @version {{projectVersion}}
*/
/**
* Private class used by ApiClient class. Used for executing LWA refresh token flow.
* @class
*/
class LwaOAuthClient {
/**
* Private member to store LWA credential and refresh token.
* @type {Object.<String, String>}
*/
#lwaClientInfo = {};
/**
* Private member to cache one access token that is retrieved by auto-retrieval.
* @type {String | null}
*/
#cachedToken = null;
/**
* Private member to cache one access token that is retrieved by auto-retrieval.
* @type {Number | null}
*/
#cachedTokenExpiration = null;
/**
* Constructs a new LwaOAuthClient.
* @param {String} clientId LWA Client ID.
* @param {String} clientSecret LWA Client Secret.
* @param {String} refreshToken LWA Refresh token.
*/
constructor(clientId, clientSecret, refreshToken) {
this.#lwaClientInfo = {
clientId, clientSecret, refreshToken,
};
}
/**
* Execute LWA refresh token flow to retrieve access token to be used for SP-API calls.
* @returns {Promise<String>} LWA access token.
*/
retrieveAccessToken = async () => {
if (this.#cachedToken && this.#cachedTokenExpiration && this.#cachedTokenExpiration > Date.now()) {
return Promise.resolve(this.#cachedToken);
}
const res = await this.#doRefresh();
this.#cachedToken = res.access_token;
this.#cachedTokenExpiration = Date.now() + res.expires_in * 1000;
return this.#cachedToken;
}
/**
* Private method to execute LWA token refresh flow.
* @returns {Promise<Object>} LWA token response.
*/
#doRefresh = async () => {
const res = await superagent.post('https://api.amazon.com/auth/o2/token')
.send(`grant_type=refresh_token&refresh_token=${this.#lwaClientInfo.refreshToken}&client_id=${this.#lwaClientInfo.clientId}&client_secret=${this.#lwaClientInfo.clientSecret}`)
.set("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
return res.body;
}
}
/**
* Private class used by ApiClient class. Used for executing LWA refresh token flow and calling Tokens API to retrieve RDT.
* @class
*/
class TokensApiClient {
/**
* Private member to execute LWA refresh token flow.
* @type {Object.<LwaOAuthClient>}
*/
#lwaClient = null;
/**
* Private member to store 'dataElements' parameter for Tokens API call.
* @type {Array.<String>}
*/
#dataElements = null;
/**
* Constructs a new TokensApiClient.
* @param {String} clientId LWA Client ID.
* @param {String} clientSecret LWA Client Secret.
* @param {String} refreshToken LWA Refresh token.
* @param {Array.<String>} dataElements Optional specifiers for PII data elements tp retrieve.
*/
constructor(clientId, clientSecret, refreshToken, dataElements) {
this.#lwaClient = new LwaOAuthClient(clientId, clientSecret, refreshToken, dataElements);
if (dataElements && !Array.isArray(dataElements)) {
throw new Error(`dataElements parameter to TokensApiClient constructor must be array of string. Illegal parameter:${dataElements}`);
}
this.#dataElements = dataElements ? dataElements : null;
}
/**
* Execute createRestrictedDataToken to retrieve RDT to be used for PII-handling SP-API calls.
* @param {String} method method for SP-API request.
* @param {String} url URL for SP-API call to be made.
* @param {Array.<String>} dataElements specify PII information to get from "buyerInfo", "shippingAddress" and "buyerTaxInformation".
* @returns {Promise<String>} Restricted Data Token (RDT).
*/
retrieveRestrictedDataToken = async (method, url) => {
const accessToken = await this.#lwaClient.retrieveAccessToken();
const urlToRequest = new URL(url);
const res = await this.#doCreateRestrictedDataToken(accessToken, method, urlToRequest);
return res.restrictedDataToken;
}
/**
* Private method to execute createRestrictedDataToken
* @param {String} accessToken Access token to call RDT request.
* @param {URL} url URL object for URL string manipulation.
* @param {Array.<String>} dataElements specify PII information to get from "buyerInfo", "shippingAddress" and "buyerTaxInformation".
* @returns {Promise<Object>} createRestrictedDataToken response.
*/
#doCreateRestrictedDataToken = async (accessToken, method, url) => {
const tokenApiUrl = `${url.origin}/tokens/2021-03-01/restrictedDataToken`;
const pathToRequest = url.pathname;
const res = await superagent.post(tokenApiUrl)
.send(
{
restrictedResources: [
{
method: method,
path: pathToRequest,
dataElements: this.#dataElements ? this.#dataElements : undefined,
}
]
}
).set("Content-Type", "application/json")
.set({"x-amz-access-token": accessToken});
return res.body;
}
}
/**
* Manages low level client-server communications, parameter marshalling, etc. There should not be any need for an
* application to use this class directly - the *Api and model classes provide the public API for the service. The
* contents of this file should be regarded as internal but are documented for completeness.
* @alias module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient
* @class
*/{{/emitJSDoc}}
export class ApiClient {
#tokenForApiCall = null;
#lwaClient = null;
#rdtClient = null;
{{#emitJSDoc}}/**
* Constructs a new ApiClient.
* @param {String} baseUrl Base URL of endpoint ex. "https://sellingpartnerapi-na.amazon.com"
*/{{/emitJSDoc}}
constructor(baseUrl) {
{{#emitJSDoc}}/**
* The base URL against which to resolve every API call's (relative) path.
* @type {String}
* @default {{{basePath}}}
*/{{/emitJSDoc}}
this.basePath = baseUrl ? baseUrl.replace(/\/+$/, '') : '{{{basePath}}}'.replace(/\/+$/, '');
{{#emitJSDoc}}/**
* The authentication methods to be included for all API calls.
* @type {Array.<String>}
*/{{/emitJSDoc}}{{=< >=}}
this.authentications = {
<#authMethods>
<#isBasic>
'<name>': {type: 'basic'}<^-last>,</-last>
</isBasic>
<#isApiKey>
'<name>': {type: 'apiKey', 'in': <#isKeyInHeader>'header'</isKeyInHeader><^isKeyInHeader>'query'</isKeyInHeader>, name: '<keyParamName>'}<^-last>,</-last>
</isApiKey>
<#isOAuth>
'<name>': {type: 'oauth2'}<^-last>,</-last>
</isOAuth>
</authMethods>
}
<={{ }}=>{{#emitJSDoc}}/**
* The default HTTP headers to be included for all API calls.
* @type {Array.<String>}
* @default {}
*/{{/emitJSDoc}}
this.defaultHeaders = {};
/**
* The default HTTP timeout for all API calls.
* @type {Number}
* @default 60000
*/
this.timeout = 60000;
/**
* If set to false an additional timestamp parameter is added to all API GET calls to
* prevent browser caching
* @type {Boolean}
* @default true
*/
this.cache = true;
{{#emitJSDoc}}/**
* If set to true, the client will save the cookies from each server
* response, and return them in the next request.
* @default false
*/{{/emitJSDoc}}
this.enableCookies = false;
/*
* Used to save and return cookies in a node.js (non-browser) setting,
* if this.enableCookies is set to true.
*/
if (typeof window === 'undefined') {
this.agent = new superagent.agent();
}
/*
* Allow user to override superagent agent
*/
this.requestAgent = null;
}
{{#emitJSDoc}}/**
* Returns this ApiClient so that you can chain the methods.
* @param {String} clientId LWA client ID.
* @param {String} clientSecret LWA client secret.
* @param {String} refreshToken LWA refresh token.
* @param {Array.<String>} dataElementsOption specify PII information to get from "buyerInfo", "shippingAddress" and "buyerTaxInformation".
* @returns {ApiClient} This ApiClient, which is going to use give accessToken for all API calls.
*/{{/emitJSDoc}}
enableAutoRetrievalRestrictedDataToken(clientId, clientSecret, refreshToken, dataElementsOption) {
// TODO
if (!clientId || !clientSecret || !refreshToken) {
throw new Error('invalid parameter(s) to enableAutoRetrievalRestrictedDataToken.');
}
this.#rdtClient = new TokensApiClient(clientId, clientSecret, refreshToken, dataElementsOption);
return this;
}
{{#emitJSDoc}}/**
* Returns this ApiClient so that you can chain the methods.
* @param {String} clientId LWA client ID.
* @param {String} clientSecret LWA client secret.
* @param {String} refreshToken LWA refresh token.
* @returns {ApiClient} This ApiClient, which is going to use give accessToken for all API calls.
*/{{/emitJSDoc}}
enableAutoRetrievalAccessToken(clientId, clientSecret, refreshToken) {
if (!clientId || !clientSecret || !refreshToken) {
throw new Error('invalid parameter(s) to enableAutoRetrievalAccessToken.');
}
this.#lwaClient = new LwaOAuthClient(clientId, clientSecret, refreshToken);
return this;
}
{{#emitJSDoc}}/**
* Returns this ApiClient so that you can chain the methods.
* @param {String} restrictedDataToken RDT token to use for SP-API call.
* @returns {ApiClient} This ApiClient, which is going to use give RDT for all API calls.
*/{{/emitJSDoc}}
applyRestrictedDataToken(restrictedDataToken) {
this.#tokenForApiCall = restrictedDataToken;
return this;
}
{{#emitJSDoc}}/**
* Returns a string representation for an actual parameter.
* @param param The actual parameter.
* @returns {String} The string representation of <code>param</code>.
*/{{/emitJSDoc}}
paramToString(param) {
if (param == undefined || param == null) {
return '';
}
if (param instanceof Date) {
return param.toJSON();
}
return param.toString();
}
{{#emitJSDoc}}/**
* Builds full URL by appending the given path to the base URL and replacing path parameter place-holders with parameter values.
* NOTE: query parameters are not handled here.
* @param {String} path The path to append to the base URL.
* @param {Object} pathParams The parameter values to append.
* @returns {String} The encoded path with parameter values substituted.
*/{{/emitJSDoc}}
buildUrl(path, pathParams) {
if (!path.match(/^\//)) {
path = '/' + path;
}
var url = this.basePath + path;
url = url.replace(/\{([\w-]+)\}/g, (fullMatch, key) => {
var value;
if (pathParams.hasOwnProperty(key)) {
value = this.paramToString(pathParams[key]);
} else {
value = fullMatch;
}
return encodeURIComponent(value);
});
return url;
}
{{#emitJSDoc}}/**
* Checks whether the given content type represents JSON.<br>
* JSON content type examples:<br>
* <ul>
* <li>application/json</li>
* <li>application/json; charset=UTF8</li>
* <li>APPLICATION/JSON</li>
* </ul>
* @param {String} contentType The MIME content type to check.
* @returns {Boolean} <code>true</code> if <code>contentType</code> represents JSON, otherwise <code>false</code>.
*/{{/emitJSDoc}}
isJsonMime(contentType) {
return Boolean(contentType != null && contentType.match(/^application\/json(;.*)?$/i));
}
{{#emitJSDoc}}/**
* Chooses a content type from the given array, with JSON preferred; i.e. return JSON if included, otherwise return the first.
* @param {Array.<String>} contentTypes
* @returns {String} The chosen content type, preferring JSON.
*/{{/emitJSDoc}}
jsonPreferredMime(contentTypes) {
for (var i = 0; i < contentTypes.length; i++) {
if (this.isJsonMime(contentTypes[i])) {
return contentTypes[i];
}
}
return contentTypes[0];
}
{{#emitJSDoc}}/**
* Checks whether the given parameter value represents file-like content.
* @param param The parameter to check.
* @returns {Boolean} <code>true</code> if <code>param</code> represents a file.
*/
{{/emitJSDoc}}
isFileParam(param) {
// fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
if (typeof require === 'function') {
let fs;
try {
fs = require('fs');
} catch (err) {}
if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
return true;
}
}
// Buffer in Node.js
if (typeof Buffer === 'function' && param instanceof Buffer) {
return true;
}
// Blob in browser
if (typeof Blob === 'function' && param instanceof Blob) {
return true;
}
// File in browser (it seems File object is also instance of Blob, but keep this for safe)
if (typeof File === 'function' && param instanceof File) {
return true;
}
return false;
}
{{#emitJSDoc}}/**
* Normalizes parameter values:
* <ul>
* <li>remove nils</li>
* <li>keep files and arrays</li>
* <li>format to string with `paramToString` for other cases</li>
* </ul>
* @param {Object.<String, Object>} params The parameters as object properties.
* @returns {Object.<String, Object>} normalized parameters.
*/{{/emitJSDoc}}
normalizeParams(params) {
var newParams = {};
for (var key in params) {
if (params.hasOwnProperty(key) && params[key] != undefined && params[key] != null) {
var value = params[key];
if (this.isFileParam(value) || Array.isArray(value)) {
newParams[key] = value;
} else {
newParams[key] = this.paramToString(value);
}
}
}
return newParams;
}
{{#emitJSDoc}}/**
* Enumeration of collection format separator strategies.
* @enum {String}
* @readonly
*/{{/emitJSDoc}}
static CollectionFormatEnum = {
{{#emitJSDoc}}/**
* Comma-separated values. Value: <code>csv</code>
* @const
*/{{/emitJSDoc}}
CSV: ',',
{{#emitJSDoc}}/**
* Space-separated values. Value: <code>ssv</code>
* @const
*/{{/emitJSDoc}}
SSV: ' ',
{{#emitJSDoc}}/**
* Tab-separated values. Value: <code>tsv</code>
* @const
*/{{/emitJSDoc}}
TSV: '\t',
{{#emitJSDoc}}/**
* Pipe(|)-separated values. Value: <code>pipes</code>
* @const
*/{{/emitJSDoc}}
PIPES: '|',
{{#emitJSDoc}}/**
* Native array. Value: <code>multi</code>
* @const
*/{{/emitJSDoc}}
MULTI: 'multi'
};
{{#emitJSDoc}}/**
* Builds a string representation of an array-type actual parameter, according to the given collection format.
* @param {Array} param An array parameter.
* @param {module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient.CollectionFormatEnum} collectionFormat The array element separator strategy.
* @returns {String|Array} A string representation of the supplied collection, using the specified delimiter. Returns
* <code>param</code> as is if <code>collectionFormat</code> is <code>multi</code>.
*/{{/emitJSDoc}}
buildCollectionParam(param, collectionFormat) {
if (param == null) {
return null;
}
switch (collectionFormat) {
case 'csv':
return param.map(this.paramToString).join(',');
case 'ssv':
return param.map(this.paramToString).join(' ');
case 'tsv':
return param.map(this.paramToString).join('\t');
case 'pipes':
return param.map(this.paramToString).join('|');
case 'multi':
//return the array directly as SuperAgent will handle it as expected
return param.map(this.paramToString);
default:
throw new Error('Unknown collection format: ' + collectionFormat);
}
}
{{#emitJSDoc}}/**
* Applies authentication headers to the request.
* @param {String} accessOrRdtToken Either Access Token or Restricted Data Token to add as 'x-amz-access-token'.
* @returns {ApiClient} This ApiClient, which is going to use give RDT for all API calls.
*/
{{/emitJSDoc}}
applyXAmzAccessTokenToRequest(accessOrRdtToken) {
if (!accessOrRdtToken) {
throw new Error('empty string, null or undefined passed to applyXAmzAccessTokenToRequest');
}
this.#tokenForApiCall = accessOrRdtToken;
return this;
}
{{#emitJSDoc}}/**
* Deserializes an HTTP response body into a value of the specified type.
* @param {Object} response A SuperAgent response object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} returnType The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns A value of the specified type.
*/
{{/emitJSDoc}}
deserialize(response, returnType) {
if (response == null || returnType == null || response.status == 204) {
return null;
}
// Rely on SuperAgent for parsing response body.
// See http://visionmedia.github.io/superagent/#parsing-response-bodies
var data = response.body;
if (data == null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) {
// SuperAgent does not always produce a body; use the unparsed response as a fallback
data = response.text;
}
return ApiClient.convertToType(data, returnType);
}
{{#emitJSDoc}}{{^usePromises}}/**
* Callback function to receive the result of the operation.
* @callback module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient~callApiCallback
* @param {String} error Error message, if any.
* @param data The data returned by the service call.
* @param {String} response The complete HTTP response.
*/{{/usePromises}}{{/emitJSDoc}}
{{#emitJSDoc}}/**
* Invokes the REST service using the supplied settings and parameters.
* @param {String} path The base URL to invoke.
* @param {String} httpMethod The HTTP method to use.
* @param {Object.<String, String>} pathParams A map of path parameters and their values.
* @param {Object.<String, Object>} queryParams A map of query parameters and their values.
* @param {Object.<String, Object>} headerParams A map of header parameters and their values.
* @param {Object.<String, Object>} formParams A map of form parameters and their values.
* @param {Object} bodyParam The value to pass as the request body.
* @param {Array.<String>} contentTypes An array of request MIME types.
* @param {Array.<String>} accepts An array of acceptable response MIME types.
* @param {(String|Array|ObjectFunction)} returnType The required type to return; can be a string for simple types or the
* constructor for a complex type.{{^usePromises}}
* @param {module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient~callApiCallback} callback The callback function.{{/usePromises}}
* @returns {{#usePromises}}{Promise} A {@link https://www.promisejs.org/|Promise} object{{/usePromises}}{{^usePromises}}{Object} The SuperAgent request object{{/usePromises}}.
*/
{{/emitJSDoc}}
async callApi(path, httpMethod, pathParams,
queryParams, headerParams, formParams, bodyParam, contentTypes, accepts,
returnType{{^usePromises}}, callback{{/usePromises}}) {
var url = this.buildUrl(path, pathParams);
var request = superagent(httpMethod, url);
if (!this.#tokenForApiCall && !this.#lwaClient && !this.#rdtClient) {
throw new Error('none of accessToken, RDT token and auto-retrieval is set.');
}
// set query parameters
if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
queryParams['_'] = new Date().getTime();
}
request.query(this.normalizeParams(queryParams));
// set header parameters
request.set(this.defaultHeaders).set(this.normalizeParams(headerParams));
// set x-amz-access-token header
if (this.#tokenForApiCall) {
// add custom header for SP-API call.
request.set({"x-amz-access-token": this.#tokenForApiCall});
} else if (this.#rdtClient) {
const rdt = await this.#rdtClient.retrieveRestrictedDataToken(httpMethod, url);
request.set({"x-amz-access-token": rdt});
} else if (this.#lwaClient) {
// execute token refresh.
const accessToken = await this.#lwaClient.retrieveAccessToken();
request.set({"x-amz-access-token": accessToken});
}
// set requestAgent if it is set by user
if (this.requestAgent) {
request.agent(this.requestAgent);
}
// set request timeout
request.timeout(this.timeout);
var contentType = this.jsonPreferredMime(contentTypes);
if (contentType) {
// Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
if(contentType != 'multipart/form-data') {
request.type(contentType);
}
} else if (!request.header['Content-Type']) {
request.type('application/json');
}
if (contentType === 'application/x-www-form-urlencoded') {
request.send(querystring.stringify(this.normalizeParams(formParams)));
} else if (contentType == 'multipart/form-data') {
var _formParams = this.normalizeParams(formParams);
for (var key in _formParams) {
if (_formParams.hasOwnProperty(key)) {
if (this.isFileParam(_formParams[key])) {
// file field
request.attach(key, _formParams[key]);
} else {
request.field(key, _formParams[key]);
}
}
}
} else if (bodyParam) {
request.send(bodyParam);
}
var accept = this.jsonPreferredMime(accepts);
if (accept) {
request.accept(accept);
}
if (returnType === 'Blob') {
request.responseType('blob');
} else if (returnType === 'String') {
request.responseType('string');
}
// Attach previously saved cookies, if enabled
if (this.enableCookies){
if (typeof window === 'undefined') {
this.agent.attachCookies(request);
}
else {
request.withCredentials();
}
}
{{#usePromises}}return new Promise((resolve, reject) => {
request.end((error, response) => {
if (error) {
reject(error);
} else {
try {
var data = this.deserialize(response, returnType);
if (this.enableCookies && typeof window === 'undefined'){
this.agent.saveCookies(response);
}
resolve({data, response});
} catch (err) {
reject(err);
}
}
});
});{{/usePromises}}
{{^usePromises}}request.end((error, response) => {
if (callback) {
var data = null;
if (!error) {
try {
data = this.deserialize(response, returnType);
if (this.enableCookies && typeof window === 'undefined'){
this.agent.saveCookies(response);
}
} catch (err) {
error = err;
}
}
callback(error, data, response);
}
});
return request;{{/usePromises}}
}
{{#emitJSDoc}}/**
* Parses an ISO-8601 string representation of a date value.
* @param {String} str The date value as a string.
* @returns {Date} The parsed date object.
*/{{/emitJSDoc}}
static parseDate(str) {
return new Date(str);
}
{{#emitJSDoc}}/**
* Converts a value to the specified type.
* @param {(String|Object)} data The data to convert, as a string or object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} type The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns An instance of the specified type or null or undefined if data is null or undefined.
*/
{{/emitJSDoc}}
static convertToType(data, type) {
if (data === null || data === undefined)
return data
switch (type) {
case 'Boolean':
return Boolean(data);
case 'Integer':
return parseInt(data, 10);
case 'Number':
return parseFloat(data);
case 'String':
return String(data);
case 'Date':
return ApiClient.parseDate(String(data));
case 'Blob':
return data;
default:
if (type === Object) {
// generic object, return directly
return data;
} else if (typeof type === 'function') {
// for model type like: User
return type.constructFromObject(data);
} else if (Array.isArray(type)) {
// for array type like: ['String']
var itemType = type[0];
return data.map((item) => {
return ApiClient.convertToType(item, itemType);
});
} else if (typeof type === 'object') {
// for plain object type like: {'String': 'Integer'}
var keyType, valueType;
for (var k in type) {
if (type.hasOwnProperty(k)) {
keyType = k;
valueType = type[k];
break;
}
}
var result = {};
for (var k in data) {
if (data.hasOwnProperty(k)) {
var key = ApiClient.convertToType(k, keyType);
var value = ApiClient.convertToType(data[k], valueType);
result[key] = value;
}
}
return result;
} else {
// for unknown type, return the data directly
return data;
}
}
}
{{#emitJSDoc}}/**
* Constructs a new map or array model from REST data.
* @param data {Object|Array} The REST data.
* @param obj {Object|Array} The target object or array.
*/{{/emitJSDoc}}
static constructFromObject(data, obj, itemType) {
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
if (data.hasOwnProperty(i))
obj[i] = ApiClient.convertToType(data[i], itemType);
}
} else {
for (var k in data) {
if (data.hasOwnProperty(k))
obj[k] = ApiClient.convertToType(data[k], itemType);
}
}
}
}
{{#emitJSDoc}}/**
* The default API client implementation.
* @type {module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient}
*/{{/emitJSDoc}}
ApiClient.instance = new ApiClient();

View File

@ -0,0 +1,101 @@
{{>licenseInfo}}
{{=< >=}}
import {ApiClient} from "../ApiClient.js";
<#imports>import {<import>} from '../<#modelPackage><&modelPackage>/</modelPackage><import>.js';
</imports>
<#emitJSDoc>/**
* <baseName> service.
* @module <#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><&apiPackage>/</apiPackage><classname>
* @version <projectVersion>
*/</emitJSDoc>
export class <classname> {
<#emitJSDoc>/**
* Constructs a new <&classname>. <#description>
* <description></description>
* @alias module:<#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>
* @class
* @param {module:<#invokerPackage><&invokerPackage>/</invokerPackage>ApiClient} [apiClient] Optional API client implementation to use,
* default to {@link module:<#invokerPackage><&invokerPackage>/</invokerPackage>ApiClient#instance} if unspecified.
*/</emitJSDoc>
constructor(apiClient) {
this.apiClient = apiClient || ApiClient.instance;
}
<#operations><#operation><#emitJSDoc><^usePromises>
/**
* Callback function to receive the result of the <operationId> operation.
* @callback module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>~<operationId>Callback
* @param {String} error Error message, if any.
* @param <#vendorExtensions.x-jsdoc-type>{<&vendorExtensions.x-jsdoc-type>} data The data returned by the service call.</vendorExtensions.x-jsdoc-type><^vendorExtensions.x-jsdoc-type>data This operation does not return a value.</vendorExtensions.x-jsdoc-type>
* @param {String} response The complete HTTP response.
*/</usePromises>
/**<#summary>
* <summary></summary><#notes>
* <notes></notes><#allParams><#required>
* @param {<&vendorExtensions.x-jsdoc-type>} <paramName> <description></required></allParams><#hasOptionalParams>
* @param {Object} opts Optional parameters<#allParams><^required>
* @param {<&vendorExtensions.x-jsdoc-type>} opts.<paramName> <description><#defaultValue> (default to <.>)</defaultValue></required></allParams></hasOptionalParams><^usePromises>
* @param {module:<#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><&apiPackage>/</apiPackage><&classname>~<operationId>Callback} callback The callback function, accepting three arguments: error, data, response<#returnType>
* data is of type: {@link <&vendorExtensions.x-jsdoc-type>}</returnType></usePromises><#usePromises>
* @return {Promise} a {@link https://www.promisejs.org/|Promise}<#returnType>, with an object containing data of type {@link <&vendorExtensions.x-jsdoc-type>} and HTTP response</returnType><^returnType>, with an object containing HTTP response</returnType></usePromises>
*/
</emitJSDoc> <operationId><#usePromises>WithHttpInfo</usePromises>(<vendorExtensions.x-codegen-arg-list><^usePromises><#hasParams>, </hasParams>callback</usePromises>) {<#hasOptionalParams>
opts = opts || {};</hasOptionalParams>
let postBody = <#bodyParam><#required><paramName></required><^required>opts['<paramName>']</required></bodyParam><^bodyParam>null</bodyParam>;
<#allParams><#required>
// verify the required parameter '<paramName>' is set
if (<paramName> === undefined || <paramName> === null) {
throw new Error("Missing the required parameter '<paramName>' when calling <operationId>");
}
</required></allParams>
let pathParams = {<#pathParams>
'<baseName>': <#required><paramName></required><^required>opts['<paramName>']</required><#hasMore>,</hasMore></pathParams>
};
let queryParams = {<#queryParams>
'<baseName>': <#collectionFormat>this.apiClient.buildCollectionParam(<#required><paramName></required><^required>opts['<paramName>']</required>, '<collectionFormat>')</collectionFormat><^collectionFormat><#required><paramName></required><^required>opts['<paramName>']</required></collectionFormat><#hasMore>,</hasMore></queryParams>
};
let headerParams = {<#headerParams>
'<baseName>': <#required><paramName></required><^required>opts['<paramName>']</required><#hasMore>,</hasMore></headerParams>
};
let formParams = {<#formParams>
'<baseName>': <#collectionFormat>this.apiClient.buildCollectionParam(<#required><paramName></required><^required>opts['<paramName>']</required>, '<collectionFormat>')</collectionFormat><^collectionFormat><#required><paramName></required><^required>opts['<paramName>']</required></collectionFormat><#hasMore>,</hasMore></formParams>
};
let contentTypes = [<#consumes>'<& mediaType>'<#hasMore>, </hasMore></consumes>];
let accepts = [<#produces>'<& mediaType>'<#hasMore>, </hasMore></produces>];
let returnType = <#returnType><&returnType></returnType><^returnType>null</returnType>;
return this.apiClient.callApi(
'<&path>', '<httpMethod>',
pathParams, queryParams, headerParams, formParams, postBody,
contentTypes, accepts, returnType<^usePromises>, callback</usePromises>
);
}
<#usePromises>
<#emitJSDoc>
/**<#summary>
* <summary></summary><#notes>
* <notes></notes><#allParams><#required>
* @param {<&vendorExtensions.x-jsdoc-type>} <paramName> <description></required></allParams><#hasOptionalParams>
* @param {Object} opts Optional parameters<#allParams><^required>
* @param {<&vendorExtensions.x-jsdoc-type>} opts.<paramName> <description><#defaultValue> (default to <.>)</defaultValue></required></allParams></hasOptionalParams><^usePromises>
* @param {module:<#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><&apiPackage>/</apiPackage><&classname>~<operationId>Callback} callback The callback function, accepting three arguments: error, data, response<#returnType>
* data is of type: {@link <&vendorExtensions.x-jsdoc-type>}</returnType></usePromises><#usePromises>
* @return {Promise} a {@link https://www.promisejs.org/|Promise}<#returnType>, with data of type {@link <&vendorExtensions.x-jsdoc-type>}</returnType></usePromises>
*/
</emitJSDoc> <operationId>(<vendorExtensions.x-codegen-arg-list>) {
return this.<operationId>WithHttpInfo(<vendorExtensions.x-codegen-arg-list>)
.then(function(response_and_data) {
return response_and_data.data;
});
}
</usePromises>
</operation></operations>
}
<={{ }}=>

View File

@ -0,0 +1,59 @@
{{>licenseInfo}}
{{=< >=}}
import {ApiClient} from './ApiClient.js';
<#models>import {<#model><classFilename></model>} from './<#modelPackage><modelPackage>/</modelPackage><importPath>.js';
</models><#apiInfo><#apis>import {<importPath>} from './<#apiPackage><apiPackage>/</apiPackage><importPath>.js';
</apis></apiInfo>
<={{ }}=>
{{#emitJSDoc}}/**{{#projectDescription}}
* {{projectDescription}}.<br>{{/projectDescription}}
* The <code>index</code> module provides access to constructors for all the classes which comprise the public API.
* <p>
* An AMD (recommended!) or CommonJS application will generally do something equivalent to the following:
* <pre>
* var {{moduleName}} = require('{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}index'); // See note below*.
* var xxxSvc = new {{moduleName}}.XxxApi(); // Allocate the API class we're going to use.
* var yyyModel = new {{moduleName}}.Yyy(); // Construct a model instance.
* yyyModel.someProperty = 'someValue';
* ...
* var zzz = xxxSvc.doSomething(yyyModel); // Invoke the service.
* ...
* </pre>
* <em>*NOTE: For a top-level AMD script, use require(['{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}index'], function(){...})
* and put the application logic within the callback function.</em>
* </p>
* <p>
* A non-AMD browser application (discouraged) might do something like this:
* <pre>
* var xxxSvc = new {{moduleName}}.XxxApi(); // Allocate the API class we're going to use.
* var yyy = new {{moduleName}}.Yyy(); // Construct a model instance.
* yyyModel.someProperty = 'someValue';
* ...
* var zzz = xxxSvc.doSomething(yyyModel); // Invoke the service.
* ...
* </pre>
* </p>
* @module {{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}index
* @version {{projectVersion}}
*/{{/emitJSDoc}}
export {
{{=< >=}}
<#emitJSDoc>/**
* The ApiClient constructor.
* @property {module:<#invokerPackage><invokerPackage>/</invokerPackage>ApiClient}
*/</emitJSDoc>
ApiClient<#models>,
<#emitJSDoc>/**
* The <importPath> model constructor.
* @property {module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><importPath>}
*/</emitJSDoc>
<importPath></models><#apiInfo><#apis>,
<#emitJSDoc>/**
* The <importPath> service constructor.
* @property {module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><importPath>}
*/</emitJSDoc>
<importPath></apis></apiInfo>
};<={{ }}=>

View File

@ -0,0 +1,18 @@
{{>licenseInfo}}
{{=< >=}}
import {ApiClient} from '../ApiClient.js';
<#imports>
import {<import>} from './<import>.js';
</imports>
<={{ }}=>
{{#models}}
{{#model}}
{{#isEnum}}
{{>partial_model_enum_class}}
{{/isEnum}}
{{^isEnum}}
{{>partial_model_generic}}
{{/isEnum}}
{{/model}}
{{/models}}

View File

@ -0,0 +1,29 @@
{
"name": "{{{projectName}}}",
"type": "module",
"version": "{{{projectVersion}}}",
"description": "{{{projectDescription}}}",
"license": "{{licenseName}}",
"main": "{{sourceFolder}}{{#invokerPackage}}/{{invokerPackage}}{{/invokerPackage}}/index.js",
"scripts": {
"test": "mocha --compilers js:babel-core/register --recursive"
},
"browser": {
"fs": false
},
"dependencies": {
"babel": "^6.23.0",
"babel-cli": "^6.26.0",
"babel-plugin-transform-builtin-extend": "^1.1.2",
"superagent": "3.7.0",
"querystring": "0.2.0"
},
"devDependencies": {
"babel-core": "6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-0": "^6.24.1",
"mocha": "~2.3.4",
"sinon": "1.17.3",
"expect.js": "~0.3.1"
}
}

View File

@ -0,0 +1,155 @@
{{#emitJSDoc}}
/**
* The {{classname}} model module.
* @module {{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{classname}}
* @version {{projectVersion}}
*/
{{/emitJSDoc}}
export class {{classname}} {{#parentModel}}extends {{classname}} {{/parentModel}}{{#parent}}{{^parentModel}}{{#vendorExtensions.x-isArray}}extends Array {{/vendorExtensions.x-isArray}}{{/parentModel}}{{/parent}}{
{{#emitJSDoc}}
/**
* Constructs a new <code>{{classname}}</code>.{{#description}}
* {{description}}{{/description}}
* @alias module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{classname}}
* @class{{#useInheritance}}{{#parent}}
* @extends {{#parentModel}}module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{classname}}{{/parentModel}}{{^parentModel}}{{#vendorExtensions.x-isArray}}Array{{/vendorExtensions.x-isArray}}{{#vendorExtensions.x-isMap}}Object{{/vendorExtensions.x-isMap}}{{/parentModel}}{{/parent}}{{#interfaces}}
* @implements module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{.}}{{/interfaces}}{{/useInheritance}}{{#vendorExtensions.x-all-required}}
* @param {{name}} {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=> {{#description}}{{{description}}}{{/description}}{{/vendorExtensions.x-all-required}}
*/
{{/emitJSDoc}}
constructor({{#vendorExtensions.x-all-required}}{{name}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-all-required}}) {
{{#parentModel}}
super({{#vendorExtensions.x-all-required}}{{name}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-all-required}});
{{/parentModel}}
{{#parent}}
{{^parentModel}}
{{#vendorExtensions.x-isArray}}
super();
{{/vendorExtensions.x-isArray}}
{{/parentModel}}
{{/parent}}
{{#useInheritance}}
{{#interfaceModels}}
{{classname}}.call(this{{#vendorExtensions.x-all-required}}, {{name}}{{/vendorExtensions.x-all-required}});
{{/interfaceModels}}
{{/useInheritance}}
{{#vars}}
{{#required}}
this.{{name}} = {{name}};
{{/required}}
{{/vars}}
}
{{#emitJSDoc}}
/**
* Constructs a <code>{{classname}}</code> from a plain JavaScript object, optionally creating a new instance.
* Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
* @param {Object} data The plain JavaScript object bearing properties of interest.
* @param {{=< >=}}{module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><classname>}<={{ }}=> obj Optional instance to populate.
* @return {{=< >=}}{module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><classname>}<={{ }}=> The populated <code>{{classname}}</code> instance.
*/
{{/emitJSDoc}}
static constructFromObject(data, obj) {
if (data){{! TODO: support polymorphism: discriminator property on data determines class to instantiate.}} {
switch(typeof data) {
case 'string':
obj = String(data);
break;
case 'number':
obj = Number(data);
break;
case 'boolean':
obj = Boolean(data);
break;
}
obj = obj || new {{classname}}();
{{#parent}}
{{^parentModel}}
ApiClient.constructFromObject(data, obj, '{{vendorExtensions.x-itemType}}');
{{/parentModel}}
{{/parent}}
{{#useInheritance}}
{{#parentModel}}
{{classname}}.constructFromObject(data, obj);
{{/parentModel}}
{{#interfaces}}
{{.}}.constructFromObject(data, obj);
{{/interfaces}}
{{/useInheritance}}
{{#vars}}
if (data.hasOwnProperty('{{baseName}}'))
obj.{{name}}{{{defaultValueWithParam}}}
{{/vars}}
}
return obj;
}
{{#emitModelMethods}}
{{#vars}}
{{#emitJSDoc}}
/**{{#description}}
* Returns {{{description}}}{{/description}}{{#minimum}}
* minimum: {{minimum}}{{/minimum}}{{#maximum}}
* maximum: {{maximum}}{{/maximum}}
* @return {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=>
*/
{{/emitJSDoc}}
{{getter}}() {
return this.{{name}};
}
{{#emitJSDoc}}
/**{{#description}}
* Sets {{{description}}}{{/description}}
* @param {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=> {{name}}{{#description}} {{{description}}}{{/description}}
*/
{{/emitJSDoc}}
{{setter}}({{name}}) {
this.{{name}} = {{name}};
}
{{/vars}}
{{/emitModelMethods}}
}
{{#hasVars}}
{{#vars}}
{{#isEnum}}
{{^isContainer}}
{{>partial_model_inner_enum}}
{{/isContainer}}
{{/isEnum}}
{{#items.isEnum}}
{{#items}}
{{^isContainer}}
{{>partial_model_inner_enum}}
{{/isContainer}}
{{/items}}
{{/items.isEnum}}
{{#emitJSDoc}}
/**{{#description}}
* {{{description}}}{{/description}}
* @member {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=> {{name}}{{#defaultValue}}
* @default {{{defaultValue}}}{{/defaultValue}}
*/
{{/emitJSDoc}}
{{classname}}.prototype.{{name}} = {{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}undefined{{/defaultValue}};
{{/vars}}
{{/hasVars}}
{{#useInheritance}}
{{#interfaceModels}}
// Implement {{classname}} interface:
{{#allVars}}
{{#emitJSDoc}}
/**{{#description}}
* {{{description}}}{{/description}}
* @member {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=> {{name}}{{#defaultValue}}
* @default {{{defaultValue}}}{{/defaultValue}}
*/
{{/emitJSDoc}}
{{classname}}.prototype.{{name}} = {{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}undefined{{/defaultValue}};
{{/allVars}}
{{/interfaceModels}}
{{/useInheritance}}

View File

@ -0,0 +1,13 @@
import { AppConfig } from '../app.config.mjs';
import { LwaAuthClient } from '../helper/LwaAuthClient.mjs';
import { SellersApi, ApiClient as SellersApiClient } from '../../sdk/src/sellers/index.js';
(async () => {
const lwaClient = new LwaAuthClient(AppConfig.lwaClientId, AppConfig.lwaClientSecret, AppConfig.lwaRefreshToken);
const sellerApiClient = new SellersApiClient(AppConfig.endpoint);
const sellerApi = new SellersApi(sellerApiClient);
sellerApiClient.applyXAmzAccessTokenToRequest(await lwaClient.getAccessToken());
const participations = await sellerApi.getMarketplaceParticipations();
console.log(JSON.stringify(participations) + "\n**********************************");
})();