Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ npm install paynl-sdk --save
## Examples
Some of the basic examples are listed here, for the full list of examples, please take a look at the examples directory [here](https://github.com/paynl/nodejs-sdk/tree/master/src/examples).

All examples start with importing the `paynl-sdk` and creating a client using the API token.
All examples start with importing the `paynl-sdk` and creating a client using the AT token as username and the API token as password.

```typescript
import { createPayNLClient } from 'paynl-sdk';

const payNL = createPayNLClient({ apiToken: '****************************************' });
const payNL = createPayNLClient({ username: 'AT-####-####', password: '****************************************' });
```

## Service Config
Expand Down
8 changes: 5 additions & 3 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ All notable (breaking) changes to this project will be documented in this file.

## From 1.2.0 to 2.0.0

As of version 2.0.0, the `serviceId` option has been removed from `createPayNLClient()` and is required to be passed
with `payNL.Orders.create({ serviceId: 'SL-####-####' })` and `payNL.DirectDebit.createMandate({ serviceId: 'SL-####-####' })`.
As of version 2.0.0, the options passed to `createPayNLClient()` have been changed.
* The `apiToken` has been renamed to `password`
* The `serviceId` option has been removed and is required to be passed to
`payNL.Orders.create({ serviceId: 'SL-####-####' })` and `payNL.DirectDebit.createMandate({ serviceId: 'SL-####-####' })`.

The SDK can no longer create or update transactions using the old REST API.
All orders need to be created using the new [order API](https://developer.pay.nl/reference/api_create_order-1).
Expand All @@ -21,7 +23,7 @@ To upgrade, all calls to the following methods need to be replaced with new Orde
* `payNL.Instore.getTerminals()`

The following have different in- and outputs:
* `payNL.PaymentMethods.all()` (previously called `payNL.Paymentmethods.getList()`)
* `payNL.Core.PaymentMethods()` (previously called `payNL.Paymentmethods.getList()`)
* `payNL.DirectDebit.add()`
* `payNL.DirectDebit.get()`

Expand Down
2 changes: 1 addition & 1 deletion examples/abortOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
2 changes: 1 addition & 1 deletion examples/addPayment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
2 changes: 1 addition & 1 deletion examples/cancelOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
2 changes: 1 addition & 1 deletion examples/createOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient, ApiError } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

try {
const order = await payNL.Orders.create({
Expand Down
5 changes: 1 addition & 4 deletions examples/directDebit.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({
apiToken: 'your-api-token',
ATCode: 'AT-1234-5678',
});
const payNL = createPayNLClient({ username: 'AT-1234-5678', password: 'your-api-token' });

const mandate = await payNL.DirectDebit.createMandate({
serviceId: 'SL-1234-5678',
Expand Down
2 changes: 1 addition & 1 deletion examples/fetchOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
7 changes: 2 additions & 5 deletions examples/getPaymentMethods.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({
apiToken: 'your-api-token',
ATCode: 'AT-1234-5678',
});
const payNL = createPayNLClient({ username: 'AT-1234-5678', password: 'your-api-token' });

const methods = await payNL.PaymentMethods.all('nl_NL');
const methods = await payNL.Core.PaymentMethods('nl_NL');

console.log(methods.paymentMethods);
2 changes: 1 addition & 1 deletion examples/orderStatus.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
2 changes: 1 addition & 1 deletion examples/serviceConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const config = await payNL.Service.getConfig('SL-1234-5678');

Expand Down
2 changes: 1 addition & 1 deletion examples/updateOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
2 changes: 1 addition & 1 deletion examples/verifyOrder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPayNLClient } from '../src';

const payNL = createPayNLClient({ apiToken: 'your-api-token' });
const payNL = createPayNLClient({ password: 'your-api-token' });

const orderId = '00000000-1111-2222-3333-000000000000';

Expand Down
7 changes: 5 additions & 2 deletions src/ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import { ApiError } from './ApiError';
import { RestApiRequest } from './RestApiRequest';

export type ClientOptions = {
apiToken: string;
ATCode?: string;
/**
* This should be a token code formatted like `AT-1234-5678`
*/
username?: string;
password: string;
};

type ApiRequest = ConnectApiRequest | RestApiRequest;
Expand Down
11 changes: 10 additions & 1 deletion src/ConnectApiRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,26 @@ export class ConnectApiRequest {

getRequestInit(options: ClientOptions): RequestInit {
const { json, ...fetchOptions } = this.fetchOptions;

return {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${options.apiToken}`,
Authorization: this.getAuthorization(options),
},
body: json ? JSON.stringify(json) : undefined,
...fetchOptions,
};
}

getAuthorization(options: ClientOptions): string {
if (!options.username) {
return `Bearer ${options.password}`;
}

return `Basic ${btoa(`${options.username}:${options.password}`)}`;
}

getUrl(): string {
return this.url;
}
Expand Down
4 changes: 2 additions & 2 deletions src/PayNLProvider.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { OrderApi } from './order/OrderApi';
import { ApiClientInterface } from './ApiClient';
import { PaymentMethodsApi } from './core/PaymentMethodsApi';
import { CoreApi } from './core/CoreApi';
import { DirectDebitApi } from './directdebit/DirectDebitApi';
import { ServiceApi } from './service/ServiceApi';

export type PayNLProvider = {
Orders: OrderApi;
Client: ApiClientInterface;
Core: CoreApi;
Service: ServiceApi;
PaymentMethods: PaymentMethodsApi;
DirectDebit: DirectDebitApi;
};
6 changes: 3 additions & 3 deletions src/RestApiRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ export class RestApiRequest {
getRequestInit(options: ClientOptions): RequestInit {
const { json, headers, ...fetchOptions } = this.fetchOptions;

if (!options.ATCode) {
if (!options.username) {
throw new Error(
'Initialising the PayNL client with an ATCode is required to access the REST API.',
'Initialising the PayNL client with a username is required to access the REST API.',
);
}

return {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${options.ATCode}:${options.apiToken}`)}`,
Authorization: `Basic ${btoa(`${options.username}:${options.password}`)}`,
...headers,
},
body: json ? JSON.stringify(json) : undefined,
Expand Down
8 changes: 4 additions & 4 deletions src/core/PaymentMethodsApi.ts → src/core/CoreApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { RestApiRequest } from '../RestApiRequest';
import { PaymentMethod } from './PaymentMethod';
import { LocaleCode } from '../shared';

type AllResponse = {
type AllPaymentMethodsResponse = {
total: number;
paymentMethods: PaymentMethod[];
};

export class PaymentMethodsApi {
export class CoreApi {
constructor(private readonly apiClient: ApiClientInterface) {}

/**
* Get all payment methods.
* @see https://developer.pay.nl/reference/payment_method_payment_methods_get
*/
async all(locale: LocaleCode = 'en_GB') {
async PaymentMethods(locale: LocaleCode = 'en_GB') {
const response = await this.apiClient.request(
new RestApiRequest('v2/paymentmethods', {
headers: {
Expand All @@ -24,6 +24,6 @@ export class PaymentMethodsApi {
}),
);

return await response.body<AllResponse>();
return await response.body<AllPaymentMethodsResponse>();
}
}
4 changes: 2 additions & 2 deletions src/createPayNLClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ClientOptions, ApiClient } from './ApiClient';
import { PayNLProvider } from './PayNLProvider';
import { OrderApi } from './order/OrderApi';
import { PaymentMethodsApi } from './core/PaymentMethodsApi';
import { CoreApi } from './core/CoreApi';
import { DirectDebitApi } from './directdebit/DirectDebitApi';
import { ServiceApi } from './service/ServiceApi';

Expand All @@ -11,8 +11,8 @@ export function createPayNLClient(options: ClientOptions): PayNLProvider {
return {
Client: apiClient,
Orders: new OrderApi(apiClient),
Core: new CoreApi(apiClient),
Service: new ServiceApi(apiClient),
PaymentMethods: new PaymentMethodsApi(apiClient),
DirectDebit: new DirectDebitApi(apiClient),
};
}
26 changes: 23 additions & 3 deletions tests/ConnectApiRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('ConnectApiRequest', () => {
method: 'PATCH',
headers: {
Accept: 'application/json',
Authorization: 'Bearer :api-token:',
Authorization: 'Basic QVQtMTIzNC01Njc4OjphcGktdG9rZW46',
'Content-Type': 'application/json',
},
};
Expand All @@ -28,7 +28,7 @@ describe('ConnectApiRequest', () => {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: 'Bearer :api-token:',
Authorization: 'Basic QVQtMTIzNC01Njc4OjphcGktdG9rZW46',
'Content-Type': 'application/json',
},
body: JSON.stringify({ foo: 'bar' }),
Expand All @@ -38,6 +38,26 @@ describe('ConnectApiRequest', () => {
expect(subject.getRequestInit(mockClientOptions)).toEqual(expectedOptions);
});

it('can send request with only password', () => {
const subject = new ConnectApiRequest('v1/create-json', {
method: 'POST',
json: { foo: 'bar' },
});

const expectedOptions = {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: 'Bearer :api-token:',
'Content-Type': 'application/json',
},
body: JSON.stringify({ foo: 'bar' }),
};

expect(subject.getUrl()).toBe('https://connect.pay.nl/v1/create-json');
expect(subject.getRequestInit({ password: ':api-token:' })).toEqual(expectedOptions);
});

it('can send form data in body', () => {
const subject = new ConnectApiRequest('v1/create-form', {
method: 'POST',
Expand All @@ -48,7 +68,7 @@ describe('ConnectApiRequest', () => {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: 'Bearer :api-token:',
Authorization: 'Basic QVQtMTIzNC01Njc4OjphcGktdG9rZW46',
'Content-Type': 'application/json',
},
body: new FormData(),
Expand Down
4 changes: 2 additions & 2 deletions tests/RestApiRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ describe('RestApiRequest', () => {

await expect(async () =>
subject.getRequestInit({
apiToken: ':api-token:',
password: ':api-token:',
}),
).rejects.toThrow(
new Error(
'Initialising the PayNL client with an ATCode is required to access the REST API.',
'Initialising the PayNL client with a username is required to access the REST API.',
),
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ApiClientMock } from '../support/ApiClientMock';
import { PaymentMethodsApi } from '../../src/core/PaymentMethodsApi';
import { CoreApi } from '../../src/core/CoreApi';
import { fakePaymentMethod } from '../support/fakePaymentMethods';

describe('PaymentMethodsApi', () => {
it('should return a list of all payment methods', async () => {
const clientMock = new ApiClientMock();
const subject = new PaymentMethodsApi(clientMock.getMock());
const subject = new CoreApi(clientMock.getMock());

clientMock.mockResponse({ total: 1, paymentMethods: [fakePaymentMethod] });

const response = await subject.all('nl_NL');
const response = await subject.PaymentMethods('nl_NL');

expect(response.paymentMethods).toEqual([fakePaymentMethod]);
expect(clientMock.getRequest()).toEqual({
Expand Down
4 changes: 2 additions & 2 deletions tests/createPayNLClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { ClientOptions, createPayNLClient } from '../src';
describe('createPayNLClient', () => {
it('should return a client class with the given options', () => {
const givenOptions: ClientOptions = {
apiToken: 'your-api-token',
password: 'your-api-token',
};
const expectedOptions = {
apiToken: 'your-api-token',
password: 'your-api-token',
};

const result = createPayNLClient(givenOptions);
Expand Down
2 changes: 0 additions & 2 deletions tests/service/ServiceApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { ApiClientMock } from '../support/ApiClientMock';
import { fakeConfig } from '../support/fakeConfig';
import { ServiceApi } from '../../src/service/ServiceApi';

jest.mock('request');

describe('ServiceApi', () => {
it('can fetch service location config', async () => {
const clientMock = new ApiClientMock();
Expand Down
4 changes: 2 additions & 2 deletions tests/support/mockClientOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ClientOptions } from '../../src';

export const mockClientOptions: ClientOptions = {
apiToken: ':api-token:',
ATCode: 'AT-1234-5678',
username: 'AT-1234-5678',
password: ':api-token:',
};