Browse Source

Merge pull request #1 from ojizero/finalizing-api

Finalizing API
master
Ameer A 3 years ago committed by GitHub
parent
commit
fdced997db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .node-version
  2. 4
      README.md
  3. 8
      examples/sample-elasticsearch-client/README.md
  4. 2
      examples/sample-elasticsearch-client/index.js
  5. 3
      examples/sample-elasticsearch-client/package.json
  6. 3
      examples/sample-rest-api/README.md
  7. 589
      package-lock.json
  8. 10
      package.json
  9. 41
      src/index.ts
  10. 18
      src/resource.ts
  11. 8
      src/simplified-joi.ts

2
.node-version

@ -1 +1 @@ @@ -1 +1 @@
11.5.0
11.6.0

4
README.md

@ -66,6 +66,8 @@ Or if you're into Yarn @@ -66,6 +66,8 @@ Or if you're into Yarn
yarn add @ojizero/portal
```
<!-- We separate installation of `got` and `portal` to prepare for later support of multiple internal clients, mainly to support browsers using `ky` without introducing breaking changes. -->
## Usage
Aimed to be used as a building block for API client libraries
@ -274,7 +276,7 @@ export interface Response { @@ -274,7 +276,7 @@ export interface Response {
},
body: any,
headers: IncomingHttpHeaders,
_rawResponse: RawResponse,
[Symbol.for('portal:symbols:raw-response')]: RawResponse,
}
```

8
examples/sample-elasticsearch-client/README.md

@ -4,10 +4,6 @@ This is a sample client build for Elasticsearch using Portal, is provides an API @@ -4,10 +4,6 @@ This is a sample client build for Elasticsearch using Portal, is provides an API
## Usage
```
npm start # starts a docker container with elasticsearch instance
node ./index.js # run the sample code
npm stop # stop and remove the docker container
```bash
npm test # starts a docker image for elasticsearch, runs index.js then kill the container
```

2
examples/sample-elasticsearch-client/index.js

@ -55,6 +55,6 @@ if (require.main === module) { @@ -55,6 +55,6 @@ if (require.main === module) {
{"a":{"test":"bulkoperation"}}
`
})
console.log({ getDocument: { stringifiedResponse: JSON.stringify(response) } })
console.log({ bulkOperation: { stringifiedResponse: JSON.stringify(response) } })
})()
}

3
examples/sample-elasticsearch-client/package.json

@ -6,7 +6,8 @@ @@ -6,7 +6,8 @@
"main": "index.js",
"scripts": {
"start": "docker run --publish '9200:9200' --name elastic_portal_demo --detach elasticsearch:6.5.4 && while ! curl localhost:9200; do sleep 10; done",
"stop": "docker kill elastic_portal_demo && docker rm elastic_portal_demo"
"stop": "docker kill elastic_portal_demo && docker rm elastic_portal_demo",
"test": "npm start && node index.js && npm stop"
},
"license": "MIT",
"dependencies": {

3
examples/sample-rest-api/README.md

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
# Portal sample client - Generic rest API
> TODO:

589
package-lock.json generated

File diff suppressed because it is too large Load Diff

10
package.json

@ -25,25 +25,25 @@ @@ -25,25 +25,25 @@
},
"homepage": "https://github.com/ojizero/portal#readme",
"dependencies": {
"got": "^9.5.0",
"joi": "^14.3.0",
"got": "^9.6.0",
"joi": "^14.3.1",
"lodash.defaultsdeep": "^4.6.0"
},
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/expect": "^1.20.3",
"@types/got": "^9.2.2",
"@types/got": "^9.3.0",
"@types/joi": "^14.0.1",
"@types/lodash.defaultsdeep": "^4.6.4",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"@types/sinon": "^7.0.2",
"@types/sinon": "^7.0.3",
"@types/sinon-chai": "^3.2.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
"nyc": "^13.3.0",
"sinon": "^7.2.2",
"sinon-chai": "^3.3.0",
"ts-node": "^7.0.1",

41
src/index.ts

@ -1,23 +1,56 @@ @@ -1,23 +1,56 @@
import PortalClient, { Client, Config } from './client'
import PortalClient, { Client, ClientFn, Config as ClientConfig } from './client'
import methodGenerator, { MethodFactory } from './method'
import resrouceGenerator, { ResourceFactory } from './resource'
// let got: ClientFn
// try {
// got = require('got')
// } catch (_) {}
import got from 'got'
// function forNode (clientType: ClientType | undefined): clientType is NodeClient {
// return typeof clientType === 'undefined' || (clientType.type === 'node' || clientType.type === 'got')
// }
// function getClient (config: PortalConfig): ClientFn {
// if (forNode(config.client)) return got
// throw new Error(`Unspported client config ${config.client}`)
// }
// export interface ClientType {
// type: 'node' | 'got', // | 'browser' | 'ky' | 'custom',
// }
// export interface NodeClient extends ClientType {
// type: 'node' | 'got',
// }
export interface PortalConfig {
// client?: NodeClient,
}
export type Config = ClientConfig & PortalConfig
export const clientSymbol = Symbol.for('portal:symbols:client')
export interface Portal {
route: MethodFactory,
resource: ResourceFactory,
_client: Client,
[clientSymbol]: Client,
}
export function createPortalClient (config: Config): Portal {
const client = new PortalClient(got, config)
const clientFn = got // getClient(config)
const client = new PortalClient(clientFn, config)
const portal: Portal = {
route: methodGenerator(client),
resource: resrouceGenerator(client),
_client: client,
[clientSymbol]: client,
}
return portal

18
src/resource.ts

@ -66,7 +66,7 @@ export class Resource { @@ -66,7 +66,7 @@ export class Resource {
Object.defineProperty(this, route, {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
enumerable: true,
})
// Add is aliased as set
@ -74,7 +74,7 @@ export class Resource { @@ -74,7 +74,7 @@ export class Resource {
Object.defineProperty(this, 'set', {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
enumerable: true,
})
}
// Del is aliased as delete
@ -82,7 +82,7 @@ export class Resource { @@ -82,7 +82,7 @@ export class Resource {
Object.defineProperty(this, 'delete', {
value: routeMethod,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
enumerable: true,
})
}
})
@ -108,18 +108,24 @@ export class Resource { @@ -108,18 +108,24 @@ export class Resource {
return method(this.client)
}
setExtraMethods (extraMethods?: { [k:string]: any }) {
setExtraMethods (extraMethods?: { [k:string]: MethodSpec }) {
if (!extraMethods) return
Object.entries(extraMethods)
.forEach(([method, spec]) => {
// TODO: should it be prefixed by basePath ?
const sep = spec.path.startsWith('/') ? '' : '/'
spec = {
...spec,
path: `${this.baseRoute}${sep}${spec.path}`,
}
const fn = this.methodFactory(spec)
Object.defineProperty(this, method, {
value: fn,
writable: false,
enumerable: true, // TODO: is it okay to have them enumerable ?
enumerable: true,
})
})
}

8
src/simplified-joi.ts

@ -12,6 +12,10 @@ const JOI_MAPPING: { [k: string]: SchemaLike } = { @@ -12,6 +12,10 @@ const JOI_MAPPING: { [k: string]: SchemaLike } = {
// array: Joi.array(),
}
const isNotRequiredRegex = /notrequired/i
const isNotRequired = isNotRequiredRegex.test.bind(isNotRequiredRegex)
function isObject (value: any): value is { [k: string]: any } {
return !!value && typeof value === 'object'
}
@ -45,15 +49,13 @@ export function transformSchema (schema: any): SchemaLike { @@ -45,15 +49,13 @@ export function transformSchema (schema: any): SchemaLike {
const [schemaName, schemaOptions = ''] = (schema as string).split('|', 2)
const isNotRequired = /notrequired/i
schema = JOI_MAPPING[schemaName]
if (typeof schema === 'undefined') {
throw new Error(`Requested Joi validator ${schema} unsupported or undefined.`)
}
return isNotRequired.test(schemaOptions) ? schema : schema.required()
return isNotRequired(schemaOptions) ? schema : schema.required()
}
export default transformSchema

Loading…
Cancel
Save