Add initial PIS route
This commit is contained in:
11
package.json
11
package.json
@@ -2,7 +2,16 @@
|
|||||||
"name": "owlboard-ts",
|
"name": "owlboard-ts",
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"description": "TypeScript API Library to interact with the OwlBoard API (> v3.0.0)",
|
"description": "TypeScript API Library to interact with the OwlBoard API (> v3.0.0)",
|
||||||
"main": "index.js",
|
"main": "./dist/index.js",
|
||||||
|
"type": "module",
|
||||||
|
"sideEffects": false,
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
|
|||||||
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * from './lib/base.js';
|
||||||
|
export * from './lib/client.js';
|
||||||
|
export * from './lib/errors.js';
|
||||||
|
|
||||||
|
export * from './modules/pis.js';
|
||||||
46
src/lib/base.ts
Normal file
46
src/lib/base.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { ApiError } from "./errors.js";
|
||||||
|
import type { ApiErrorCode } from "./errors.js";
|
||||||
|
import type { ApiEnvelope } from "@owlboard/api-schema-types";
|
||||||
|
|
||||||
|
export interface ApiResult<T> {
|
||||||
|
data: T;
|
||||||
|
producedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BaseClient {
|
||||||
|
constructor(
|
||||||
|
protected readonly baseUrl: string,
|
||||||
|
protected readonly apiKey?: string
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the Envelope logic
|
||||||
|
*/
|
||||||
|
public async request<T>(path: string, options: RequestInit = {}): Promise<ApiResult<T>> {
|
||||||
|
const url = `${this.baseUrl}${path}`;
|
||||||
|
|
||||||
|
const headers = new Headers(options.headers);
|
||||||
|
headers.set('Content-Type', 'application/json');
|
||||||
|
if (this.apiKey) headers.set('X-OWL-KEY', this.apiKey);
|
||||||
|
|
||||||
|
const response = await fetch(url, { ...options, headers });
|
||||||
|
|
||||||
|
if (!response.ok && !response.headers.get('content-type')?.includes('application/json')) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse raw envelope
|
||||||
|
const envelope = (await response.json()) as ApiEnvelope.Envelope;
|
||||||
|
|
||||||
|
if (envelope.e !== undefined && envelope.e !== null) {
|
||||||
|
throw new ApiError(envelope.e || {}, response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: envelope.d as T,
|
||||||
|
|
||||||
|
// Convert seconds to milliseconds before parsing date
|
||||||
|
producedAt: new Date(Number(envelope.t) * 1000)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/lib/client.ts
Normal file
12
src/lib/client.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { BaseClient } from "./base.js";
|
||||||
|
import { PisModule } from "../modules/pis.js";
|
||||||
|
|
||||||
|
export class OwlBoardClient extends BaseClient {
|
||||||
|
public readonly pis: PisModule;
|
||||||
|
|
||||||
|
constructor(baseUrl: string, apiKey?: string) {
|
||||||
|
super(baseUrl, apiKey);
|
||||||
|
|
||||||
|
this.pis = new PisModule(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/lib/errors.ts
Normal file
17
src/lib/errors.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { ApiEnvelope } from "@owlboard/api-schema-types";
|
||||||
|
|
||||||
|
type RawErrorObject = NonNullable<ApiEnvelope.Envelope["e"]>;
|
||||||
|
export type ApiErrorCode = NonNullable<RawErrorObject['code']>
|
||||||
|
|
||||||
|
export class ApiError extends Error {
|
||||||
|
public readonly code: ApiErrorCode;
|
||||||
|
public readonly status: number;
|
||||||
|
|
||||||
|
constructor(errorObj: RawErrorObject, status: number) {
|
||||||
|
super(errorObj.msg || 'An unknown error occurred');
|
||||||
|
this.name = 'ApiError';
|
||||||
|
this.status = status;
|
||||||
|
// cast fallback to ensure it satisfies union
|
||||||
|
this.code = errorObj.code || ("SERVER" as ApiErrorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/modules/pis.ts
Normal file
14
src/modules/pis.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { ApiPisObject } from '@owlboard/api-schema-types';
|
||||||
|
import type { BaseClient, ApiResult } from '../lib/base.js';
|
||||||
|
|
||||||
|
export class PisModule {
|
||||||
|
constructor(private client: BaseClient) {}
|
||||||
|
|
||||||
|
async getByStartEndCrs(startCrs: string, endCrs: string): Promise<ApiResult<ApiPisObject.PisObjects>> {
|
||||||
|
const path = `/pis/route/${encodeURIComponent(startCrs.toUpperCase())}/${encodeURIComponent(endCrs.toUpperCase())}`;
|
||||||
|
|
||||||
|
return this.client.request<ApiPisObject.PisObjects>(path, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,15 @@
|
|||||||
// Visit https://aka.ms/tsconfig to read more about this file
|
// Visit https://aka.ms/tsconfig to read more about this file
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// File Layout
|
// File Layout
|
||||||
// "rootDir": "./src",
|
"rootDir": "./src",
|
||||||
// "outDir": "./dist",
|
"outDir": "./dist",
|
||||||
|
|
||||||
// Environment Settings
|
// Environment Settings
|
||||||
// See also https://aka.ms/tsconfig/module
|
// See also https://aka.ms/tsconfig/module
|
||||||
"module": "nodenext",
|
"module": "esnext",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"baseUrl": ".",
|
||||||
"types": [],
|
"types": [],
|
||||||
// For nodejs:
|
// For nodejs:
|
||||||
// "lib": ["esnext"],
|
// "lib": ["esnext"],
|
||||||
@@ -40,5 +42,6 @@
|
|||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
}
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user