Skip to content

Commit

Permalink
Add customOutputValidation to allow custom validation rules in endpoi…
Browse files Browse the repository at this point in the history
…nts. Update LWBAEndpoint with customOutputValidation to validate bid/mid/ask
  • Loading branch information
mjk90 committed Jul 4, 2024
1 parent 1a470a2 commit 515d607
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 2 deletions.
10 changes: 9 additions & 1 deletion src/adapter/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
makeLogger,
} from '../util'
import { Requester } from '../util/requester'
import { AdapterTimeoutError } from '../validation/error'
import { AdapterError, AdapterTimeoutError } from '../validation/error'
import { EmptyInputParameters } from '../validation/input-params'
import { AdapterEndpoint } from './endpoint'
import {
Expand Down Expand Up @@ -409,6 +409,14 @@ export class Adapter<CustomSettingsDefinition extends SettingsDefinitionMap = Se
}
}

validateOutput(req: AdapterRequest<EmptyInputParameters>, output: Readonly<AdapterResponse>): AdapterError | undefined {
const endpoint = this.endpointsMap[req.requestContext.endpointName]
if (endpoint.customOutputValidation) {
return endpoint.customOutputValidation(output)
}
return undefined
}

/**
* Function to serve as middleware to pass along the AdapterRequest to the appropriate Transport (acc. to the endpoint in the req.)
*
Expand Down
2 changes: 2 additions & 0 deletions src/adapter/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AdapterEndpointInterface,
AdapterEndpointParams,
CustomInputValidator,
CustomOutputValidator,
EndpointGenerics,
EndpointRateLimitingConfig,
RequestTransform,
Expand All @@ -30,6 +31,7 @@ export class AdapterEndpoint<T extends EndpointGenerics> implements AdapterEndpo
rateLimiting?: EndpointRateLimitingConfig | undefined
cacheKeyGenerator?: (data: TypeFromDefinition<T['Parameters']>) => string
customInputValidation?: CustomInputValidator<T>
customOutputValidation?: CustomOutputValidator<T['Response']> | undefined
requestTransforms: RequestTransform<T>[]
overrides?: Record<string, string> | undefined
customRouter?: (
Expand Down
20 changes: 20 additions & 0 deletions src/adapter/lwba.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TransportGenerics } from '../transports'
import { AdapterError } from '../validation/error'
import { AdapterEndpoint } from './endpoint'
import { AdapterEndpointParams, PriceEndpointInputParametersDefinition } from './index'

Expand Down Expand Up @@ -59,6 +60,25 @@ export class LwbaEndpoint<T extends LwbaEndpointGenerics> extends AdapterEndpoin
}
}

// All LWBA requests must have a mid, bid, and ask
// Response validation ensures that we meet the invariant: bid <= mid <= ask
params.customOutputValidation = (output) => {
const data = output.data as LwbaResponseDataFields['Data']
if (!data.mid || !data.bid || !data.ask) {
throw new AdapterError({
statusCode: 500,
message: `Invariant voilation. LWBA response must contain mid, bid and ask prices.`,
})
}
if (data.mid < data.bid || data.mid > data.ask) {
throw new AdapterError({
statusCode: 500,
message: `Invariant voilation. Mid price must be between bid and ask prices.`,
})
}

return undefined
}
super(params)
}
}
8 changes: 7 additions & 1 deletion src/adapter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Cache } from '../cache'
import { AdapterConfig, BaseAdapterSettings, SettingsDefinitionMap } from '../config'
import { AdapterRateLimitTier, RateLimiter } from '../rate-limiting'
import { Transport, TransportGenerics, TransportRoutes } from '../transports'
import { AdapterRequest, LoggerFactory, SubscriptionSetFactory } from '../util'
import { AdapterRequest, AdapterResponse, LoggerFactory, ResponseGenerics, SubscriptionSetFactory } from '../util'
import { Requester } from '../util/requester'
import { InputParameters } from '../validation'
import { AdapterError } from '../validation/error'
Expand Down Expand Up @@ -127,6 +127,10 @@ export type CustomInputValidator<T extends EndpointGenerics> = (
adapterSettings: T['Settings'],
) => AdapterError | undefined

export type CustomOutputValidator<T extends ResponseGenerics> = (

Check warning on line 130 in src/adapter/types.ts

View workflow job for this annotation

GitHub Actions / lint

'T' is defined but never used
output: Readonly<AdapterResponse>,
) => AdapterError | undefined

/**
* Structure to describe a specific endpoint in an [[Adapter]]
*/
Expand All @@ -149,6 +153,8 @@ export interface BaseAdapterEndpointParams<T extends EndpointGenerics> {
/** Custom input validation. Void function that should throw AdapterInputError on validation errors */
customInputValidation?: CustomInputValidator<T>

customOutputValidation?: CustomOutputValidator<T['Response']>

/** Transforms that will apply to the request before submitting it through the adapter request flow */
requestTransforms?: RequestTransform<T>[]

Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ async function buildRestApi(adapter: Adapter) {
req as AdapterRequest<EmptyInputParameters>,
reply as unknown as Promise<unknown>,
)

adapter.validateOutput(
req as AdapterRequest<EmptyInputParameters>,
response
)

return reply.code(response.statusCode || 200).send(response)
},
})
Expand Down

0 comments on commit 515d607

Please sign in to comment.