Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion lib/graph-js-sdk-web.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion lib/src/GraphRequest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ export declare class GraphRequest {
del(callback?: GraphRequestCallback): Promise<any>;
get(callback?: GraphRequestCallback): Promise<any>;
private routeResponseToPromise;
private handleFetch;
private routeResponseToCallback;
private sendRequestAndRouteResponse;
getStream(callback: GraphRequestCallback): void;
putStream(stream: any, callback: Function): void;
putStream(stream: any, callback: GraphRequestCallback): void;
private getDefaultRequestHeaders;
private configureRequest;
query(queryDictionaryOrString: string | {
[key: string]: string | number;
Expand Down
84 changes: 51 additions & 33 deletions lib/src/GraphRequest.js

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

2 changes: 1 addition & 1 deletion lib/src/GraphRequest.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions lib/src/common.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export interface URLComponents {
[key: string]: string | number;
};
}
export interface DefaultRequestHeaders {
Authorization: string;
SdkVersion: string;
}
export interface GraphRequestCallback {
(error: GraphError, response: any, rawResponse?: any): void;
}
Expand Down
2 changes: 2 additions & 0 deletions samples/node/node-sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const MicrosoftGraph = require("../../lib/src/index.js").Client;

const secrets = require("./secrets");

const fs = require("fs");

const client = MicrosoftGraph.init({
defaultVersion: 'v1.0',
debugLogging: true,
Expand Down
26 changes: 26 additions & 0 deletions spec/types/miscellaneous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import { assert } from 'chai'
import { getClient, randomString } from "./test-helper"
import * as fs from "fs";


declare const describe, it;
Expand Down Expand Up @@ -188,6 +189,31 @@ describe('Test for GET and PUT binary data', function () {
});
});

describe("Test for PUT and GET streams", function () {
this.timeout(10 * 1000);
beforeEach((done) => {
setTimeout(function () {
done();
}, 1000);
});
const imageFileName = `stream-image-${randomString()}.png`;
it("Uploading drive item as a stream", (done) => {
let stream = fs.createReadStream('./sample.png');
return getClient().api(`/me/drive/root/children/${imageFileName}/content`).putStream(stream, (err) => {
assert.isTrue(err === null);
done();
});
});

it("GET drive item as a stream", (done) => {
return getClient().api(`/me/drive/root:${imageFileName}:/content`).getStream((err, stream) => {
let writeStream = fs.createWriteStream(`./${imageFileName}`);
stream.pipe(writeStream).on('error', assert.fail);
done();
})
});
});




101 changes: 58 additions & 43 deletions src/GraphRequest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Promise } from 'es6-promise'
import 'isomorphic-fetch';

import { Options, URLComponents, GraphError, oDataQueryNames, GraphRequestCallback, PACKAGE_VERSION } from "./common"
import { Options, URLComponents, GraphError, oDataQueryNames, GraphRequestCallback, PACKAGE_VERSION, DefaultRequestHeaders } from "./common"
import { ResponseHandler } from "./ResponseHandler"
import { RequestMethod } from './RequestMethod';
import { GraphHelper } from './GraphHelper';
Expand Down Expand Up @@ -269,8 +269,6 @@ export class GraphRequest {
);
}


// Given the built SuperAgentRequest, get an auth token from the authProvider, make the request and return a promise
private routeResponseToPromise(request: Request) {
return new Promise((resolve, reject) => {
this.routeResponseToCallback(request, (err, body) => {
Expand All @@ -283,19 +281,26 @@ export class GraphRequest {
});
}

// Given the built SuperAgentRequest, get an auth token from the authProvider, make the request and invoke the callback
// Given the Request object, make the request and invoke callback
private handleFetch(request: Request | string, callback: GraphRequestCallback, options?: any) {
((request.constructor.name === "Request") ? fetch(request) : fetch(request, options)).then((response) => {
this.convertResponseType(response).then((responseValue) => {
ResponseHandler.init(response, undefined, responseValue, callback);
}).catch((error) => {
ResponseHandler.init(response, error, undefined, callback)
});
}).catch((error) => {
ResponseHandler.init(undefined, error, undefined, callback)
});
}

// Given the Request object, get an auth token from the authProvider, make the fetch call
private routeResponseToCallback(request: Request, callback: GraphRequestCallback) {
this.config.authProvider((err, accessToken) => {
let self = this;
self.config.authProvider((err, accessToken) => {
if (err == null && accessToken != null) {
fetch(this.configureRequest(request, accessToken)).then((response) => {
this.convertResponseType(response).then((responseValue) => {
ResponseHandler.init(response, undefined, responseValue, callback);
}).catch((error) => {
ResponseHandler.init(response, error, undefined, callback)
});
}).catch((error) => {
ResponseHandler.init(undefined, error, undefined, callback)
});
request = self.configureRequest(request, accessToken);
self.handleFetch(request, callback);
} else {
callback(err, null, null);
}
Expand All @@ -316,48 +321,55 @@ export class GraphRequest {
}

getStream(callback: GraphRequestCallback) {
this.config.authProvider((err, accessToken) => {
let self = this;
self.config.authProvider((err, accessToken) => {
if (err === null && accessToken !== null) {
let url = this.buildFullUrl();
callback(null, this.configureRequest(
new Request(url, { method: RequestMethod.GET, headers: new Headers() }),
accessToken));
let url = self.buildFullUrl();
let options = {
method: RequestMethod.GET,
headers: self.getDefaultRequestHeaders(accessToken)
};
self.responseType("stream");
Object.keys(self._headers).forEach((key) => options.headers[key] = self._headers[key] as string);
self.handleFetch(url, callback, options);
} else {
callback(err, null);
}
});
}

putStream(stream: any, callback: Function) {
this.config.authProvider((err, accessToken) => {
putStream(stream: any, callback: GraphRequestCallback) {
let self = this;
self.config.authProvider((err, accessToken) => {
if (err === null && accessToken !== null) {
let url = this.buildFullUrl();
let req: Request = this.configureRequest(
new Request(
url,
{
method: RequestMethod.PUT,
headers: new Headers({ 'Content-Type': 'application/octet-stream' })
}),
accessToken
);
stream
.pipe(req)
.on('error', function (err) {
callback(err, null)
})
.on('end', function () {
callback(null)
});
let url = self.buildFullUrl();
let options = {
method: RequestMethod.PUT,
headers: {
'Content-Type': 'application/octet-stream',
},
body: stream
}
let defaultHeaders = self.getDefaultRequestHeaders(accessToken);
Object.keys(defaultHeaders).forEach((key) => options.headers[key] = defaultHeaders[key] as string);
Object.keys(self._headers).forEach((key) => options.headers[key] = self._headers[key] as string);
self.handleFetch(url, callback, options);
}
});
}

private configureRequest(request: Request, accessToken: string): Request {
request.headers.append('Authorization', 'Bearer ' + accessToken);
request.headers.append('SdkVersion', "graph-js-" + PACKAGE_VERSION);
private getDefaultRequestHeaders(accessToken: string): DefaultRequestHeaders {
return {
Authorization: `Bearer ${accessToken}`,
SdkVersion: `graph-js-${PACKAGE_VERSION}`
}
}

Object.keys(this._headers).forEach((key) => request.headers.set(key, this._headers[key] as string));
private configureRequest(request: Request, accessToken: string): Request {
let self = this,
defaultHeaders = self.getDefaultRequestHeaders(accessToken);
Object.keys(defaultHeaders).forEach((key) => request.headers.set(key, defaultHeaders[key] as string));
Object.keys(self._headers).forEach((key) => request.headers.set(key, self._headers[key] as string));
return request;
}

Expand Down Expand Up @@ -424,6 +436,9 @@ export class GraphRequest {
case "text":
responseValue = response.text();
break;
case "stream":
responseValue = Promise.resolve(response.body);
break;
default:
responseValue = response.json();
break;
Expand Down
7 changes: 6 additions & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export interface URLComponents {
otherURLQueryParams:{ [key: string] : string|number; }
}

export interface DefaultRequestHeaders {
Authorization: string
SdkVersion: string
}

export interface GraphRequestCallback {
(error: GraphError, response: any, rawResponse?: any): void
}
Expand All @@ -45,4 +50,4 @@ export interface GraphError {
requestId: string, // "ca269f81-55d7-483f-a9e6-2b04a2a2d0e2"
date: Date, // new Date(2016-11-17T18:49:59)
body: string // original graph response
}
}