Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding AS types & grant requests support to open-payments client #727

Merged
merged 19 commits into from
Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
32 changes: 24 additions & 8 deletions packages/open-payments/scripts/generate-types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import fs from 'fs'
import openapiTS from 'openapi-typescript'
import config from '../src/config'

const generateTypesFromOpenApi = async (
specUrl: string,
outputFileName: string
) => {
const generatedTypesOutput = await openapiTS(specUrl)

fs.writeFile(outputFileName, generatedTypesOutput, (error) => {
if (error) {
console.log(`Error when writing types to ${outputFileName}`, { error })
}
})
}

;(async () => {
try {
const output = await openapiTS(config.OPEN_PAYMENTS_OPEN_API_URL)
const fileName = 'src/generated/types.ts'
const rootFolder = `src/generated`

fs.writeFile(fileName, output, (error) => {
if (error) {
console.log(`Error when writing types to ${fileName}`, { error })
}
})
try {
await generateTypesFromOpenApi(
config.OPEN_PAYMENTS_RS_OPEN_API_URL,
`${rootFolder}/resource-server-types.ts`
)
await generateTypesFromOpenApi(
config.OPEN_PAYMENTS_AS_OPEN_API_URL,
`${rootFolder}/auth-server-types.ts`
)
} catch (error) {
console.log('Error when generating types', {
error
Expand Down
28 changes: 28 additions & 0 deletions packages/open-payments/src/client/grant.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createGrantRoutes } from './grant'
import { OpenAPI, HttpMethod, createOpenAPI } from 'openapi'
import config from '../config'
import { defaultAxiosInstance, silentLogger } from '../test/helpers'

describe('grant', (): void => {
let openApi: OpenAPI

beforeAll(async () => {
openApi = await createOpenAPI(config.OPEN_PAYMENTS_AS_OPEN_API_URL)
})

const axiosInstance = defaultAxiosInstance
const logger = silentLogger

describe('createGrantRoutes', (): void => {
test('creates response validator for grant requests', async (): Promise<void> => {
jest.spyOn(openApi, 'createResponseValidator')

createGrantRoutes({ axiosInstance, openApi, logger })
expect(openApi.createResponseValidator).toHaveBeenCalledTimes(1)
expect(openApi.createResponseValidator).toHaveBeenCalledWith({
path: '/',
method: HttpMethod.POST
})
})
})
})
41 changes: 41 additions & 0 deletions packages/open-payments/src/client/grant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { HttpMethod } from 'openapi'
import { RouteDeps } from '.'
import {
getASPath,
InteractiveGrant,
NonInteractiveGrant,
GrantRequest
} from '../types'
import { post } from './requests'

interface RequestGrantArgs {
url: string
request: GrantRequest
}

export interface GrantRoutes {
requestGrant(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
requestGrant(
request(

or

Suggested change
requestGrant(
requestAccess(

https://datatracker.ietf.org/doc/html/draft-ietf-gnap-core-protocol#section-2

Copy link
Contributor Author

@mkurapov mkurapov Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, had request in my follow-up PR, will do it here instead

args: RequestGrantArgs
): Promise<InteractiveGrant | NonInteractiveGrant>
}

export const createGrantRoutes = (deps: RouteDeps): GrantRoutes => {
const requestGrantValidator = deps.openApi.createResponseValidator<
InteractiveGrant | NonInteractiveGrant
>({
path: getASPath('/'),
method: HttpMethod.POST
})
return {
requestGrant: (args: RequestGrantArgs) =>
post(deps, { url: args.url, body: args.request }, requestGrantValidator)
}
}

export const isInteractiveGrant = (
grant: InteractiveGrant | NonInteractiveGrant
): grant is InteractiveGrant => !!(grant as InteractiveGrant).interact

export const isNonInteractiveGrant = (
grant: InteractiveGrant | NonInteractiveGrant
): grant is NonInteractiveGrant => !!(grant as NonInteractiveGrant).access_token
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('ilp-stream-connection', (): void => {
let openApi: OpenAPI

beforeAll(async () => {
openApi = await createOpenAPI(config.OPEN_PAYMENTS_OPEN_API_URL)
openApi = await createOpenAPI(config.OPEN_PAYMENTS_RS_OPEN_API_URL)
})

const axiosInstance = defaultAxiosInstance
Expand Down
10 changes: 5 additions & 5 deletions packages/open-payments/src/client/ilp-stream-connection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpMethod } from 'openapi'
import { ClientDeps } from '.'
import { getPath, ILPStreamConnection } from '../types'
import { RouteDeps } from '.'
import { getRSPath, ILPStreamConnection } from '../types'
import { get } from './requests'

interface GetArgs {
Expand All @@ -12,13 +12,13 @@ export interface ILPStreamConnectionRoutes {
}

export const createILPStreamConnectionRoutes = (
clientDeps: ClientDeps
deps: RouteDeps
): ILPStreamConnectionRoutes => {
const { axiosInstance, openApi, logger } = clientDeps
const { axiosInstance, openApi, logger } = deps

const getILPStreamConnectionValidator =
openApi.createResponseValidator<ILPStreamConnection>({
path: getPath('/connections/{id}'),
path: getRSPath('/connections/{id}'),
method: HttpMethod.GET
})

Expand Down
2 changes: 1 addition & 1 deletion packages/open-payments/src/client/incoming-payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('incoming-payment', (): void => {
let openApi: OpenAPI

beforeAll(async () => {
openApi = await createOpenAPI(config.OPEN_PAYMENTS_OPEN_API_URL)
openApi = await createOpenAPI(config.OPEN_PAYMENTS_RS_OPEN_API_URL)
})

const axiosInstance = defaultAxiosInstance
Expand Down
14 changes: 7 additions & 7 deletions packages/open-payments/src/client/incoming-payment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpMethod, ResponseValidator } from 'openapi'
import { ClientDeps } from '.'
import { IncomingPayment, getPath } from '../types'
import { BaseDeps, RouteDeps } from '.'
import { IncomingPayment, getRSPath } from '../types'
import { get } from './requests'

interface GetArgs {
Expand All @@ -13,13 +13,13 @@ export interface IncomingPaymentRoutes {
}

export const createIncomingPaymentRoutes = (
clientDeps: ClientDeps
deps: RouteDeps
): IncomingPaymentRoutes => {
const { axiosInstance, openApi, logger } = clientDeps
const { axiosInstance, openApi, logger } = deps

const getIncomingPaymentOpenApiValidator =
openApi.createResponseValidator<IncomingPayment>({
path: getPath('/incoming-payments/{id}'),
path: getRSPath('/incoming-payments/{id}'),
method: HttpMethod.GET
})

Expand All @@ -34,11 +34,11 @@ export const createIncomingPaymentRoutes = (
}

export const getIncomingPayment = async (
clientDeps: Pick<ClientDeps, 'axiosInstance' | 'logger'>,
deps: BaseDeps,
args: GetArgs,
validateOpenApiResponse: ResponseValidator<IncomingPayment>
) => {
const { axiosInstance, logger } = clientDeps
const { axiosInstance, logger } = deps
const { url } = args

const incomingPayment = await get(
Expand Down
70 changes: 60 additions & 10 deletions packages/open-payments/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,19 @@ import {
} from './payment-pointer'
import { createAxiosInstance } from './requests'
import { AxiosInstance } from 'axios'
import { createGrantRoutes, GrantRoutes } from './grant'

export interface ClientDeps {
export interface BaseDeps {
axiosInstance: AxiosInstance
logger: Logger
}

interface ClientDeps extends BaseDeps {
resourceServerOpenApi: OpenAPI
authServerOpenApi: OpenAPI
}

export interface RouteDeps extends BaseDeps {
axiosInstance: AxiosInstance
openApi: OpenAPI
logger: Logger
Expand All @@ -32,9 +43,19 @@ const createDeps = async (
requestTimeoutMs:
args?.requestTimeoutMs ?? config.DEFAULT_REQUEST_TIMEOUT_MS
})
const openApi = await createOpenAPI(config.OPEN_PAYMENTS_OPEN_API_URL)
const resourceServerOpenApi = await createOpenAPI(
config.OPEN_PAYMENTS_RS_OPEN_API_URL
)
const authServerOpenApi = await createOpenAPI(
config.OPEN_PAYMENTS_AS_OPEN_API_URL
)
const logger = args?.logger ?? createLogger()
return { axiosInstance, openApi, logger }
return {
axiosInstance,
resourceServerOpenApi,
authServerOpenApi,
logger
}
}

export interface CreateUnauthenticatedClientArgs {
Expand All @@ -50,11 +71,21 @@ export interface UnauthenticatedClient {
export const createUnauthenticatedClient = async (
args: CreateUnauthenticatedClientArgs
): Promise<UnauthenticatedClient> => {
const deps = await createDeps(args)
const { axiosInstance, resourceServerOpenApi, logger } = await createDeps(
args
)

return {
ilpStreamConnection: createILPStreamConnectionRoutes(deps),
paymentPointer: createPaymentPointerRoutes(deps)
ilpStreamConnection: createILPStreamConnectionRoutes({
axiosInstance,
openApi: resourceServerOpenApi,
logger
}),
paymentPointer: createPaymentPointerRoutes({
axiosInstance,
openApi: resourceServerOpenApi,
logger
})
}
}

Expand All @@ -66,16 +97,35 @@ export interface CreateAuthenticatedClientArgs

export interface AuthenticatedClient extends UnauthenticatedClient {
incomingPayment: IncomingPaymentRoutes
grant: GrantRoutes
}

export const createAuthenticatedClient = async (
args: CreateAuthenticatedClientArgs
): Promise<AuthenticatedClient> => {
const deps = await createDeps(args)
const { axiosInstance, resourceServerOpenApi, authServerOpenApi, logger } =
await createDeps(args)

return {
incomingPayment: createIncomingPaymentRoutes(deps),
ilpStreamConnection: createILPStreamConnectionRoutes(deps),
paymentPointer: createPaymentPointerRoutes(deps)
incomingPayment: createIncomingPaymentRoutes({
axiosInstance,
openApi: resourceServerOpenApi,
logger
}),
ilpStreamConnection: createILPStreamConnectionRoutes({
axiosInstance,
openApi: resourceServerOpenApi,
logger
}),
paymentPointer: createPaymentPointerRoutes({
axiosInstance,
openApi: resourceServerOpenApi,
logger
}),
grant: createGrantRoutes({
axiosInstance,
openApi: authServerOpenApi,
logger
})
}
}
2 changes: 1 addition & 1 deletion packages/open-payments/src/client/payment-pointer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('payment-pointer', (): void => {
let openApi: OpenAPI

beforeAll(async () => {
openApi = await createOpenAPI(config.OPEN_PAYMENTS_OPEN_API_URL)
openApi = await createOpenAPI(config.OPEN_PAYMENTS_RS_OPEN_API_URL)
})

const axiosInstance = defaultAxiosInstance
Expand Down
10 changes: 5 additions & 5 deletions packages/open-payments/src/client/payment-pointer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HttpMethod } from 'openapi'
import { ClientDeps } from '.'
import { PaymentPointer, getPath } from '../types'
import { RouteDeps } from '.'
import { PaymentPointer, getRSPath } from '../types'
import { get } from './requests'

interface GetArgs {
Expand All @@ -12,13 +12,13 @@ export interface PaymentPointerRoutes {
}

export const createPaymentPointerRoutes = (
clientDeps: ClientDeps
deps: RouteDeps
): PaymentPointerRoutes => {
const { axiosInstance, openApi, logger } = clientDeps
const { axiosInstance, openApi, logger } = deps

const getPaymentPaymentValidator =
openApi.createResponseValidator<PaymentPointer>({
path: getPath('/'),
path: getRSPath('/'),
method: HttpMethod.GET
})

Expand Down
Loading