1- //import { resolve, parse } from "url";
2- //import { join } from "path";
3-
4- import { unique } from './misc.ts' ;
1+ import { unique } from './misc' ;
2+ import statusCodes from './codes' ;
53
64export type ItemId = string ;
75
@@ -27,6 +25,15 @@ export type ApiErrorHelper = {
2725 links ?: string [ ] ;
2826} ;
2927
28+ export type KVM = { [ k : string ] : string } ;
29+
30+ export type RequestOptions < T = unknown > = {
31+ url : string ;
32+ method ?: 'GET' | 'POST' | 'PATCH' | 'DELETE' ;
33+ headers ?: KVM ;
34+ body ?: T ;
35+ } ;
36+
3037export class ApiError extends Error {
3138 jti : string = '' ;
3239 url : string = '' ;
@@ -75,6 +82,13 @@ export class ApiError extends Error {
7582 this . url = url ;
7683 return this ;
7784 }
85+
86+ static fromJson ( opts : RequestOptions , json : ApiError , statusCode = 500 ) {
87+ return new ApiError ( json . message )
88+ . withCode ( statusCode )
89+ . withTags ( json . tags )
90+ . withUrl ( opts . url ) ;
91+ }
7892}
7993
8094export class NginxError extends ApiError {
@@ -85,42 +99,87 @@ export class NginxError extends ApiError {
8599 return this ;
86100 }
87101
88- static fromHtml ( resp = '' , statusCode = 500 ) {
102+ static fromHtml ( opts : RequestOptions , resp = '' , statusCode = 500 ) {
89103 let [ , title = 'Unknown nginx errror' ] = / < t i t l e > ( .* ?) < \/ t i t l e > / gi. exec ( resp ) || [ ] ;
90104 title = title . replace ( statusCode . toString ( ) , '' ) . trim ( ) ;
91105
92- // return new NginxError(http.STATUS_CODES[statusCode])
93- // .withCode(statusCode)
94- // .withTitle(title);
106+ return new NginxError ( statusCodes [ statusCode ] )
107+ . withCode ( statusCode )
108+ . withTitle ( title )
109+ . withUrl ( opts . url ) ;
95110 }
96111}
97112
98- type KVM = { [ k : string ] : string } ;
113+ export function nodeReq < Q = unknown , S = unknown > ( opts : RequestOptions < Q > ) : Promise < S > {
114+ const { protocol, hostname, port, pathname } = new URL ( opts . url ) ;
99115
100- export interface RequestOptions {
101- method ?: 'GET' | 'POST' | 'PATCH' | 'DELETE' ;
102- headers ?: KVM ;
103- }
116+ const proto = protocol === 'https:' ? require ( 'https' ) : require ( 'http' ) ;
104117
105- export async function req < T , U = unknown > (
106- url : string ,
107- opts : RequestOptions = { } ,
108- data ?: U
109- ) {
110- const resp = await fetch ( url , {
118+ const options = {
119+ method : 'GET' ,
120+ host : hostname ,
121+ port : + port ,
122+ path : pathname ,
111123 ...opts
124+ } ;
125+
126+ if ( ! port ) {
127+ options . port = protocol === 'https:' ? 443 : 80 ;
128+ }
129+
130+ return new Promise ( ( resolve , reject ) => {
131+ const req = proto . request ( options , ( res ) => {
132+ let resp = '' ;
133+ res . on ( 'data' , ( chunk ) => ( resp += chunk . toString ( ) ) ) ;
134+ res . on ( 'end' , ( ) => {
135+ try {
136+ /*
137+ * most nginx upstream errors should be handled by ingress default-backend
138+ * but who knows ...
139+ */
140+ if ( resp . startsWith ( '<html>' ) && resp . includes ( 'nginx' ) ) {
141+ return reject ( NginxError . fromHtml ( opts , resp , res . statusCode ) ) ;
142+ }
143+ const json = JSON . parse ( resp ) ;
144+ if ( res . statusCode >= 400 ) {
145+ return reject ( ApiError . fromJson ( opts , json , res . statusCode ) ) ;
146+ }
147+ resolve ( json ) ;
148+ } catch ( err ) {
149+ console . log ( resp ) ;
150+ reject ( err ) ;
151+ }
152+ } ) ;
153+ } ) ;
154+
155+ req . on ( 'error' , ( err ) => reject ( err ) ) ;
156+
157+ if ( opts . body ) {
158+ let send = opts . body as any ;
159+ if ( typeof send === 'object' ) {
160+ send = JSON . stringify ( opts . body ) ;
161+ }
162+ req . write ( send ) ;
163+ }
164+ req . end ( ) ;
112165 } ) ;
166+ }
113167
114- const json = await resp . json ( ) ;
168+ export async function req < Q = unknown , S = unknown > ( opts : RequestOptions < Q > ) : Promise < S > {
169+ if ( typeof fetch !== 'function' ) {
170+ return nodeReq ( opts ) ;
171+ }
115172
116- console . log ( '.xxx' , resp . status ) ;
173+ const resp = await fetch ( opts . url , {
174+ headers : opts . headers ,
175+ method : opts . method || 'GET' ,
176+ body : < any > opts . body || null
177+ } ) ;
117178
118- if ( resp . status >= 300 ) {
119- throw new ApiError ( json . message )
120- . withHelper ( json . helper )
121- . withTags ( json . tags )
122- . withCode ( resp . status )
123- . withUrl ( url ) ;
179+ const json = await resp . json ( ) ;
180+
181+ if ( resp . status >= 400 ) {
182+ throw ApiError . fromJson ( opts , json , resp . status ) ;
124183 }
125184
126185 return json ;
@@ -158,28 +217,33 @@ export class Client {
158217 get < T = unknown > ( path : string , query = { } ) : Promise < T > {
159218 const url = new URL ( path , this . url ) ;
160219 const headers = this . getDefaultHeaders ( ) ;
161- return req ( url . toString ( ) , { method : 'GET' , headers } ) ;
220+ return req ( { url : url . toString ( ) , method : 'GET' , headers } ) ;
162221 }
163222
164223 post < T = unknown > ( path : string , data : Partial < T > = { } ) : Promise < T > {
165224 const url = new URL ( path , this . url ) ;
166225 const headers = this . getDefaultHeaders ( ) ;
167- return req ( url . toString ( ) , { method : 'POST' , headers } , data ) ;
226+ return req ( { url : url . toString ( ) , method : 'POST' , headers, body : data } ) ;
168227 }
169228
170229 patch < T = unknown > ( path : string , data : Partial < T > = { } ) : Promise < T > {
171230 const url = new URL ( path , this . url ) ;
172231 const headers = this . getDefaultHeaders ( ) ;
173- return req ( url . toString ( ) , { method : 'PATCH' , headers } , data ) ;
232+ return req ( { url : url . toString ( ) , method : 'PATCH' , headers, body : data } ) ;
174233 }
175234
176235 delete < T = unknown > ( path : string ) : Promise < T > {
177236 const url = new URL ( path , this . url ) ;
178237 const headers = this . getDefaultHeaders ( ) ;
179- return req ( url . toString ( ) , { method : 'DELETE' , headers } ) ;
238+ return req ( { url : url . toString ( ) , method : 'DELETE' , headers } ) ;
180239 }
181240
182241 with ( opts : ClientOpts = { } ) {
183242 return new Client ( { ...( this . _opts || { } ) , ...opts } ) ;
184243 }
185244}
245+
246+ export default new Client ( {
247+ url : process . env [ 'RIC_URL' ] || 'https://dev.rightech.io/' ,
248+ token : process . env [ 'RIC_TOKEN' ]
249+ } ) ;
0 commit comments