Browse Source

headache causing types

modified-method-api
ojizero 4 years ago
parent
commit
72d117bb31
No known key found for this signature in database
GPG Key ID: FEBB7097845B0C7E
  1. 68
      src/client.ts
  2. 23
      src/method.ts
  3. 115
      test/client.spec.ts
  4. 2
      test/method.spec.ts

68
src/client.ts

@ -3,9 +3,10 @@ import querystring from 'querystring' @@ -3,9 +3,10 @@ import querystring from 'querystring'
import { IncomingHttpHeaders } from 'http';
import { OutgoingHttpHeaders } from 'http'
import defaultsDeep from 'lodash.defaultsdeep'
import { RequestOptions } from 'https';
import { RequestOptions as HttpsRequestOptions } from 'https';
export enum AuthenticationTypes {
None = 'none',
BasicAuth = 'basic',
// TokenAuth = 'token',
// ApiKeyAuth = 'key',
@ -30,6 +31,13 @@ interface AuthSpec { @@ -30,6 +31,13 @@ interface AuthSpec {
export type Seconds = number
export interface RawResponse {
body: any,
statusCode?: number,
statusMessage?: string,
headers: IncomingHttpHeaders,
}
export interface Response {
status: {
code?: number,
@ -37,7 +45,17 @@ export interface Response { @@ -37,7 +45,17 @@ export interface Response {
},
body: any,
headers: IncomingHttpHeaders,
_rawResponse: got.Response<any>, // raw string response
_rawResponse: RawResponse,
}
// Add compatibility with Got type
export interface RequestOptions extends HttpsRequestOptions {
baseUrl: string,
url: string,
json: boolean,
body: string,
retries?: number,
throwHttpErrors: boolean,
}
export interface Config {
@ -46,16 +64,14 @@ export interface Config { @@ -46,16 +64,14 @@ export interface Config {
// port?: number,
headers?: OutgoingHttpHeaders,
authentication?: Authentication,
retries?: number,
timeout?: Seconds,
retries?: number, // available from RequestOptions
timeout?: Seconds, // available from HttpsRequestOptions
onError?: 'reject' | 'resolve',
}
export type RawResponse = got.Response<any>
export type ClientFn = (options: RequestOptions) => Promise<RawResponse>
// export type RequestOptions = Config & RequestConfig // TODO:
export interface RequestConfig extends RequestOptions, Config {}
export interface Client {
request (method: string, path: string, payload: {}, options: any): Promise<Response>
@ -70,23 +86,15 @@ export class PortalClient implements Client { @@ -70,23 +86,15 @@ export class PortalClient implements Client {
this.config = config
}
async request (method: string, path: string, payload: {}, options: any): Promise<Response> {
async request (method: string, path: string, payload: {}, options: RequestConfig): Promise<Response> {
const requestOptions = this.constructRequestOptions(method, path, payload, options)
const response = await this.client(requestOptions)
return {
status: {
code: response.statusCode,
word: response.statusMessage,
},
body: response.body, // TODO: should it be parsed if needed ?
headers: response.headers,
_rawResponse: response,
}
return this.transformResponse(response)
}
constructRequestOptions (method: string, path: string, payload: { [k: string]: any }, options: any): { [s: string]: any } {
constructRequestOptions (method: string, path: string, payload: { [k: string]: any }, options: RequestConfig): RequestOptions {
const {
baseUrl,
headers,
@ -98,7 +106,7 @@ export class PortalClient implements Client { @@ -98,7 +106,7 @@ export class PortalClient implements Client {
// port: 443,
retries: 0,
headers: {},
timeout: 30_000,
timeout: 30,
onError: 'reject',
// protocol: 'https',
}, this.config, options)
@ -143,6 +151,15 @@ export class PortalClient implements Client { @@ -143,6 +151,15 @@ export class PortalClient implements Client {
setupAuthentication (auth: Authentication): AuthSpec {
switch (auth.type) {
case AuthenticationTypes.None: {
return {
useHeader: false,
usePayload: false,
useQueryString: false,
key: '',
value: '',
}
}
case AuthenticationTypes.BasicAuth: {
const token = Buffer.from(`${auth.username}:${auth.password}`).toString('base64')
@ -156,7 +173,6 @@ export class PortalClient implements Client { @@ -156,7 +173,6 @@ export class PortalClient implements Client {
}
case AuthenticationTypes.BearerAuth: {
return {
useHeader: true,
usePayload: false,
@ -169,6 +185,18 @@ export class PortalClient implements Client { @@ -169,6 +185,18 @@ export class PortalClient implements Client {
throw new Error('TODO: givem me a meangingful error')
}
transformResponse(response: RawResponse): Response {
return {
status: {
code: response.statusCode,
word: response.statusMessage,
},
body: response.body, // TODO: should it be parsed if needed ?
headers: response.headers,
_rawResponse: response,
}
}
}
export default PortalClient

23
src/method.ts

@ -28,7 +28,7 @@ export function method (client: Client): MethodFactory { @@ -28,7 +28,7 @@ export function method (client: Client): MethodFactory {
return function methodGenerator (spec: MethodSpec): RouteFunction {
const {
path,
method = 'GET',
method: _method = 'GET',
params = undefined,
body = undefined,
queryString = undefined,
@ -36,6 +36,8 @@ export function method (client: Client): MethodFactory { @@ -36,6 +36,8 @@ export function method (client: Client): MethodFactory {
accept = applicationJson,
} = spec
const method = _method.toUpperCase()
const defaultOptions = {
headers: {
'Accept': accept,
@ -60,15 +62,26 @@ export function method (client: Client): MethodFactory { @@ -60,15 +62,26 @@ export function method (client: Client): MethodFactory {
payload = args[length - 1]
args = args.slice(0, length - 1)
length -= 1
} else if (typeof options !== 'undefined') {
payload = options
options = undefined
} else if (
// TODO: ??? does this make sense ?
(typeof body !== 'undefined' || method === 'POST' || method === 'PUT')
&& typeof options !== 'undefined'
) {
const optionsHasPayload = 'payload' in options
payload = optionsHasPayload ? options.payload : options
options = optionsHasPayload ? options : undefined
}
if (typeof queryString !== 'undefined' && typeof args[length - 1] === 'object') {
if (typeof args[length - 1] === 'object') {
query = args[length - 1]
args = args.slice(0, length - 1)
length -= 1
} else if (typeof queryString !== 'undefined' && typeof options !== 'undefined') {
const optionsHasQueryString = 'queryString' in options
query = optionsHasQueryString ? options.queryString : options
options = optionsHasQueryString ? options : undefined
} else if (typeof queryString !== 'undefined' && typeof payload !== 'undefined') {
query = payload
payload = undefined

115
test/client.spec.ts

@ -1,9 +1,116 @@ @@ -1,9 +1,116 @@
import Client from '../src/client'
/// <reference path='typings/globals.d.ts' />
import Client, { Config, RawResponse, Authentication, AuthenticationTypes, ClientFn, Response } from '../src/client'
const mockRawResponse: RawResponse = {
body: 'any',
headers: { some: 'header' },
statusCode: 200,
statusMessage: 'OK',
}
const mockTransformedResponse: Response = {
status: {
code: 200,
word: 'OK',
},
body: 'any',
headers: { some: 'header' },
_rawResponse: mockRawResponse,
}
const mockConfig: Config = {
baseUrl: 'https://dummy.domain',
}
const mockBearerAuthConfig: Authentication = {
type: AuthenticationTypes.BearerAuth,
authToken: 'some-token-value'
}
const mockBasicAuthConfig: Authentication = {
type: AuthenticationTypes.BasicAuth,
username: 'some-username',
password: 'some-password',
}
const mockAuthConfigNotSupported /*: Authentication*/ = {
type: 'invalid type'
}
describe('Client', () => {
let client
let rawClient: ClientFn
let client: Client
describe('Construct request options', () => {
before(() => {
rawClient = sinon.spy()
client = new Client(rawClient, mockConfig)
})
it('transforms request parameters with all defaults', () => {
//
})
it('adds additional headers from options', () => {
//
})
describe('Authentication setup', () => {
before(() => {
rawClient = sinon.spy()
client = new Client(rawClient, mockConfig)
})
it('adds basic authentication', () => {
//
})
it('adds bearer authentication', () => {
//
})
})
})
describe('Setup authentication', () => {
before(() => {
rawClient = sinon.spy()
client = new Client(rawClient, mockConfig)
})
it('throws for non-supported types', () => {
// TODO: unable to test it as Typescript won't allow me to even compile it
// expect(() => client.setupAuthentication(mockAuthConfigNotSupported))
// .to.throw()
})
it('transforms authentication spec for basic auth', () => {
expect(client.setupAuthentication(mockBasicAuthConfig))
.to.deep.equal({
key: 'Authorization',
useHeader: true,
usePayload: false,
useQueryString: false,
value: 'Basic c29tZS11c2VybmFtZTpzb21lLXBhc3N3b3Jk',
})
})
it('transforms authentication spec for bearer auth', () => {
expect(client.setupAuthentication(mockBearerAuthConfig))
.to.deep.equal({
key: 'Authorization',
useHeader: true,
usePayload: false,
useQueryString: false,
value: 'Bearer some-token-value',
})
})
})
it('transform raw response', () => {
client = new Client(sinon.spy(), mockConfig)
before(() => {
// client = new Client()
expect(client.transformResponse(mockRawResponse))
.to.deep.equal(mockTransformedResponse)
})
})

2
test/method.spec.ts

@ -50,7 +50,7 @@ describe('Method', async () => { @@ -50,7 +50,7 @@ describe('Method', async () => {
let methodFunction
before(() => {
client = { request (method, path, options) { return Promise.resolve() } }
client = { request: sinon.spy() }
})
it('accepts client and returns generator function', async () => {

Loading…
Cancel
Save