Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript - isomorphic setup, first set of middlewares #728

Merged
merged 46 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
fd28d27
adding client factory, context and middleware files
nikithauc Sep 1, 2021
1e1a966
Adding middlewarefactory
nikithauc Sep 2, 2021
476532d
introduce custom fetch
nikithauc Sep 14, 2021
5ddd92e
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Sep 20, 2021
0f4d006
removed middlewareoption getkey, httpclient factory,
nikithauc Sep 22, 2021
454f0a6
adding MiddlewareControl
nikithauc Sep 26, 2021
9b09cdc
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Oct 3, 2021
1528921
adding shims
nikithauc Oct 4, 2021
c3a31b5
adding fetch definitions
nikithauc Oct 6, 2021
02d5812
Adding dom.d.ts, url utils
nikithauc Oct 7, 2021
9b9c1b0
splitting tsconfig
nikithauc Oct 8, 2021
090c201
adding redirect and middlewareutil tests
nikithauc Oct 9, 2021
64640dc
add karma tests
nikithauc Oct 12, 2021
de1dfdc
installing rollup, http client tests node
nikithauc Oct 12, 2021
cf02bd8
setting the browser tests
nikithauc Oct 14, 2021
2929fb0
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Oct 14, 2021
5aaca76
adding abstraction tests
nikithauc Oct 15, 2021
a43fbe8
moving shims, import from node-fetch
nikithauc Oct 15, 2021
8c2f25e
adding eslint
nikithauc Oct 15, 2021
21be144
adding eslint to abstractions
nikithauc Oct 16, 2021
a3089a7
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Oct 16, 2021
ed1580f
middleware return type, getkey definition
nikithauc Oct 26, 2021
e6dcdce
updating tests
nikithauc Oct 28, 2021
b65651e
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Oct 28, 2021
f634353
adding url util
nikithauc Oct 28, 2021
4d2728c
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Nov 8, 2021
af9a3c8
removing url utils
nikithauc Nov 9, 2021
7decd35
minor updates
nikithauc Nov 9, 2021
472f924
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Feb 2, 2022
0274947
deleting the context
nikithauc Feb 2, 2022
2725c92
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Feb 4, 2022
d5acde3
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Feb 5, 2022
889c87a
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Mar 15, 2022
142b70f
removing url util abstractions
nikithauc Mar 15, 2022
e0992a8
using fetch definitions only when required
nikithauc Mar 15, 2022
970f6f6
splitting test src tsconfigs, adding null checks
nikithauc Mar 17, 2022
f4fc008
update tests
nikithauc Mar 18, 2022
3db1f8c
resetting abstractions
nikithauc Mar 18, 2022
e34194d
Apply suggestions from code review
nikithauc Mar 18, 2022
3f5b400
resetting abstractions
nikithauc Mar 18, 2022
c7c654b
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Mar 18, 2022
aead7b0
update version, use set, collapse function
nikithauc Mar 21, 2022
c3667ae
Merge branch 'main' into enhancement/nikithauc-client-middleware-setup
nikithauc Mar 21, 2022
a6fb496
update change logi=
nikithauc Mar 21, 2022
973a69c
Correct case
nikithauc Mar 21, 2022
be93925
version bump, case sensitive check
nikithauc Mar 21, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
adding MiddlewareControl
  • Loading branch information
nikithauc committed Sep 26, 2021
commit 454f0a62357e9947294c60124c01cbb935f0a738
36 changes: 0 additions & 36 deletions abstractions/typescript/src/FetchInitOptions.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export abstract class BaseBearerTokenAuthenticationProvider implements Authentic
throw new Error('Could not get an authorization token');
}
if(!request.headers) {
request.headers = new Map<string, string>();
//request.headers = new Map<string, string>();
}
request.headers?.set(BaseBearerTokenAuthenticationProvider.authorizationHeaderKey, `Bearer ${token}`);
}
Expand Down
3 changes: 1 addition & 2 deletions abstractions/typescript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ export * from "./nativeResponseWrapper";
export * from './serialization';
export * from './utils';
export * from './store';
export * from './middlewareOption';
export * from './FetchInitOptions';
export * from './middlewareOption';
14 changes: 0 additions & 14 deletions abstractions/typescript/src/requestDetails.ts

This file was deleted.

11 changes: 4 additions & 7 deletions abstractions/typescript/src/requestInformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { ReadableStream } from 'web-streams-polyfill/es2018';
import { Parsable } from "./serialization";
import { HttpCore } from "./httpCore";
import { MiddlewareOption } from "./middlewareOption";
import { RequestDetails } from "./requestDetails";
import { FetchOptions } from "./FetchInitOptions";

/** This class represents an abstract HTTP request. */
export class RequestInformation implements RequestDetails{
export class RequestInformation{
/** The URI of the request. */
public URI?: RequestInfo;
public URI?: string;
/**
* Sets the URI of the request.
* @param currentPath the current path (scheme, host, port, path, query parameters) of the request.
Expand Down Expand Up @@ -45,9 +43,8 @@ export class RequestInformation implements RequestDetails{
public queryParameters: Map<string, string | number | boolean | undefined> = new Map<string, string | number | boolean | undefined>(); //TODO: case insensitive
/** The Request Headers. */
public headers: Headers = new Headers(); //TODO: case insensitive


public options?: FetchOptions;

public options?: Map<string,unknown>;

private _middlewareOptions = new Map<string, MiddlewareOption>(); //TODO: case insensitive
/** Gets the middleware options for the request. */
Expand Down
5 changes: 5 additions & 0 deletions http/typescript/fetch/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions http/typescript/fetch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@microsoft/kiota-abstractions": "file:../../../abstractions/typescript",
"@types/node-fetch": "^3.0.3",
"cross-fetch": "^3.1.4",
"tslib": "^2.3.1",
"web-streams-polyfill": "^3.1.1"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions http/typescript/fetch/src/httpClient.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Middleware } from "./middlewares/middleware";
import { MiddlewareContext } from "./middlewareContext";
import { MiddlewareContext } from "./middlewares/middlewareContext";
import { FetchHandler } from "./middlewares/fetchHandler";
import { MiddlewareFactory } from "./middlewares/middlewareFactory";

/** Default fetch client with options and a middleware pipleline for requests execution. */
export class HttpClient {
private middleware: Middleware
private middleware: Middleware;
/**
* Instantiates a new HttpClient.
* @param middlewares middlewares to be used for requests execution.
Expand Down
108 changes: 57 additions & 51 deletions http/typescript/fetch/src/httpCore.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { AuthenticationProvider, BackingStoreFactory, BackingStoreFactorySingleton, HttpCore as IHttpCore, Parsable, ParseNodeFactory, RequestInformation, ResponseHandler, ParseNodeFactoryRegistry, enableBackingStoreForParseNodeFactory, SerializationWriterFactoryRegistry, enableBackingStoreForSerializationWriterFactory, SerializationWriterFactory } from '@microsoft/kiota-abstractions';
import { ReadableStream } from 'web-streams-polyfill';
import { ReadableStream } from 'web-streams-polyfill/es2018';
import { URLSearchParams } from 'url';
import { HttpClient } from './httpClient';
import {Headers as crossHeaders} from "cross-fetch"

import { MiddlewareContext } from './middlewares/middlewareContext';

import { MiddlewareContext } from './middlewareContext';
export class HttpCore implements IHttpCore {
public getSerializationWriterFactory(): SerializationWriterFactory {
return this.serializationWriterFactory;
Expand All @@ -16,86 +18,83 @@ export class HttpCore implements IHttpCore {
* @param httpClient the http client to use to execute requests.
*/
public constructor(public readonly authenticationProvider: AuthenticationProvider, private parseNodeFactory: ParseNodeFactory = ParseNodeFactoryRegistry.defaultInstance, private serializationWriterFactory: SerializationWriterFactory = SerializationWriterFactoryRegistry.defaultInstance, private readonly httpClient: HttpClient = new HttpClient()) {
if(!authenticationProvider) {
if (!authenticationProvider) {
throw new Error('authentication provider cannot be null');
}
if(!parseNodeFactory) {
if (!parseNodeFactory) {
throw new Error('parse node factory cannot be null');
}
if(!serializationWriterFactory) {
if (!serializationWriterFactory) {
throw new Error('serialization writer factory cannot be null');
}
if(!httpClient) {
if (!httpClient) {
throw new Error('http client cannot be null');
}
}
private getResponseContentType = (response: Response): string | undefined => {
const header = response.headers.get("content-type")?.toLowerCase();
if(!header) return undefined;
if (!header) return undefined;
const segments = header.split(';');
if(segments.length === 0) return undefined;
if (segments.length === 0) return undefined;
else return segments[0];
}
public sendCollectionAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: new() => ModelType, responseHandler: ResponseHandler | undefined): Promise<ModelType[]> => {
if(!requestInfo) {
public sendCollectionAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: new () => ModelType, responseHandler: ResponseHandler | undefined): Promise<ModelType[]> => {
if (!requestInfo) {
throw new Error('requestInfo cannot be null');
}
await this.authenticationProvider.authenticateRequest(requestInfo);

const request = this.getRequestFromRequestInformation(requestInfo);

const response = await this.httpClient.executeFetch(this.createContext(requestInfo));
if(responseHandler) {
if (responseHandler) {
return await responseHandler.handleResponseAsync(response);
} else {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if(!responseContentType)
if (!responseContentType)
throw new Error("no response content type found for deserialization");

const rootNode = this.parseNodeFactory.getRootParseNode(responseContentType, payload);
const result = rootNode.getCollectionOfObjectValues(type);
return result as unknown as ModelType[];
}
}
public sendAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: new() => ModelType, responseHandler: ResponseHandler | undefined): Promise<ModelType> => {
if(!requestInfo) {
public sendAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: new () => ModelType, responseHandler: ResponseHandler | undefined): Promise<ModelType> => {
if (!requestInfo) {
throw new Error('requestInfo cannot be null');
}
await this.authenticationProvider.authenticateRequest(requestInfo);

const request = this.getRequestFromRequestInformation(requestInfo);

const response = await this.httpClient.executeFetch(this.createContext(requestInfo));
if(responseHandler) {
if (responseHandler) {
return await responseHandler.handleResponseAsync(response);
} else {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if(!responseContentType)
if (!responseContentType)
throw new Error("no response content type found for deserialization");

const rootNode = this.parseNodeFactory.getRootParseNode(responseContentType, payload);
const result = rootNode.getObjectValue(type);
return result as unknown as ModelType;
}
}
public sendPrimitiveAsync = async <ResponseType>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date" | "ReadableStream", responseHandler: ResponseHandler | undefined): Promise<ResponseType> => {
if(!requestInfo) {
if (!requestInfo) {
throw new Error('requestInfo cannot be null');
}
await this.authenticationProvider.authenticateRequest(requestInfo);

const request = this.getRequestFromRequestInformation(requestInfo);

const response = await this.httpClient.executeFetch(this.createContext(requestInfo));
if(responseHandler) {
if (responseHandler) {
return await responseHandler.handleResponseAsync(response);
} else {
switch(responseType) {
switch (responseType) {
case "ReadableStream":
const buffer = await response.arrayBuffer();
const buffer = await response.arrayBuffer();
let bufferPulled = false;
const stream = new ReadableStream({
pull: (controller) => {
if(!bufferPulled) {
if (!bufferPulled) {
controller.enqueue(buffer.slice(0))
bufferPulled = true;
}
Expand All @@ -108,15 +107,15 @@ export class HttpCore implements IHttpCore {
case 'Date':
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if(!responseContentType)
if (!responseContentType)
throw new Error("no response content type found for deserialization");

const rootNode = this.parseNodeFactory.getRootParseNode(responseContentType, payload);
if(responseType === 'string') {
if (responseType === 'string') {
return rootNode.getStringValue() as unknown as ResponseType;
} else if (responseType === 'number') {
return rootNode.getNumberValue() as unknown as ResponseType;
} else if(responseType === 'boolean') {
} else if (responseType === 'boolean') {
return rootNode.getBooleanValue() as unknown as ResponseType;
} else if (responseType === 'Date') {
return rootNode.getDateValue() as unknown as ResponseType;
Expand All @@ -127,38 +126,44 @@ export class HttpCore implements IHttpCore {
}
}
public sendNoResponseContentAsync = async (requestInfo: RequestInformation, responseHandler: ResponseHandler | undefined): Promise<void> => {
if(!requestInfo) {
if (!requestInfo) {
throw new Error('requestInfo cannot be null');
}
await this.authenticationProvider.authenticateRequest(requestInfo);

const request = this.getRequestFromRequestInformation(requestInfo);
const response = await this.httpClient.executeFetch(this.createContext(requestInfo));
if(responseHandler) {
if (responseHandler) {
return await responseHandler.handleResponseAsync(response);
}
}
public enableBackingStore = (backingStoreFactory?: BackingStoreFactory | undefined): void => {
this.parseNodeFactory = enableBackingStoreForParseNodeFactory(this.parseNodeFactory);
this.serializationWriterFactory = enableBackingStoreForSerializationWriterFactory(this.serializationWriterFactory);
if(!this.serializationWriterFactory || !this.parseNodeFactory)
if (!this.serializationWriterFactory || !this.parseNodeFactory)
throw new Error("unable to enable backing store");
if(backingStoreFactory) {
if (backingStoreFactory) {
BackingStoreFactorySingleton.instance = backingStoreFactory;
}
}
private getRequestFromRequestInformation = (requestInfo: RequestInformation): RequestInit => {
const request :RequestInit = {
const request = {
method: requestInfo.httpMethod?.toString(),
headers: new Headers(),
headers: new crossHeaders(),
body: requestInfo.content,
}
} as RequestInit;

requestInfo.headers?.forEach((v, k) => (request.headers as Headers).set(k, v));

requestInfo.options?.forEach((v, k) => {
if (k in request) {
request[k] = v;
}
}
);
return request;
}
private getRequestUrl = (requestInfo: RequestInformation) : string => {
private getRequestUrl (requestInfo: RequestInformation): string {
let url = requestInfo.URI ?? '';
if(requestInfo.queryParameters?.size ?? -1 > 0) {
if (requestInfo.queryParameters?.size ?? -1 > 0) {
const queryParametersBuilder = new URLSearchParams();
requestInfo.queryParameters?.forEach((v, k) => {
queryParametersBuilder.append(k, `${v}`);
Expand All @@ -168,14 +173,15 @@ export class HttpCore implements IHttpCore {
return url;
}

private createContext (requestInformation : RequestInformation): MiddlewareContext{
private createContext(requestInformation: RequestInformation): MiddlewareContext {

const context:MiddlewareContext = {
request: this.getRequestUrl(requestInformation),
options: requestInformation.headers,
middlewareOptions: requestInformation.getMiddlewareOptions()
const url = this.getRequestUrl(requestInformation);
const context: MiddlewareContext = {
request: url,
options: this.getRequestFromRequestInformation(requestInformation),
//middlewareControl //set from middleware options
}
return context;
}

}
}
}
Loading