Skip to content

Commit 075c660

Browse files
author
Caitlin Bales (MSFT)
authored
Merge pull request #15 from microsoftgraph/response-headers
Return response headers for successful calls against the API
2 parents ac70b8d + de4b3cd commit 075c660

File tree

10 files changed

+110
-12
lines changed

10 files changed

+110
-12
lines changed

src/main/java/com/microsoft/graph/http/DefaultHttpProvider.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import java.io.BufferedInputStream;
3737
import java.io.BufferedOutputStream;
38+
import java.io.ByteArrayInputStream;
3839
import java.io.IOException;
3940
import java.io.InputStream;
4041
import java.io.OutputStream;
@@ -297,13 +298,13 @@ private <Result, Body, DeserializeType> Result sendRequestInternal(final IHttpRe
297298

298299
if (connection.getResponseCode() == HttpResponseCode.HTTP_NOBODY
299300
|| connection.getResponseCode() == HttpResponseCode.HTTP_NOT_MODIFIED) {
300-
logger.logDebug("Handling response with no body");
301-
return null;
301+
logger.logDebug("Handling response with no body");
302+
return handleEmptyResponse(connection.getResponseHeaders(), resultClass);
302303
}
303304

304305
if (connection.getResponseCode() == HttpResponseCode.HTTP_ACCEPTED) {
305306
logger.logDebug("Handling accepted response");
306-
return null;
307+
return handleEmptyResponse(connection.getResponseHeaders(), resultClass);
307308
}
308309

309310
in = new BufferedInputStream(connection.getInputStream());
@@ -313,7 +314,7 @@ private <Result, Body, DeserializeType> Result sendRequestInternal(final IHttpRe
313314
final String contentType = headers.get(CONTENT_TYPE_HEADER_NAME);
314315
if (contentType.contains(JSON_CONTENT_TYPE)) {
315316
logger.logDebug("Response json");
316-
return handleJsonResponse(in, resultClass);
317+
return handleJsonResponse(in, connection.getResponseHeaders(), resultClass);
317318
} else {
318319
logger.logDebug("Response binary");
319320
isBinaryStreamInput = true;
@@ -372,18 +373,33 @@ private InputStream handleBinaryStream(final InputStream in) {
372373
/**
373374
* Handles the cause where the response is a JSON object.
374375
*
375-
* @param in The input stream from the response.
376-
* @param clazz The class of the response object.
376+
* @param in The input stream from the response.
377+
* @param responseHeaders The response headers
378+
* @param clazz The class of the response object.
377379
* @param <Result> The type of the response object.
378380
* @return The JSON object.
379381
*/
380-
private <Result> Result handleJsonResponse(final InputStream in, final Class<Result> clazz) {
382+
private <Result> Result handleJsonResponse(final InputStream in, Map<String, List<String>> responseHeaders, final Class<Result> clazz) {
381383
if (clazz == null) {
382384
return null;
383385
}
384386

385387
final String rawJson = streamToString(in);
386-
return getSerializer().deserializeObject(rawJson, clazz);
388+
return getSerializer().deserializeObject(rawJson, clazz, responseHeaders);
389+
}
390+
391+
/**
392+
* Handles the case where the response body is empty.
393+
*
394+
* @param responseHeaders The response headers
395+
* @param clazz The type of the response object
396+
* @return The JSON object
397+
*/
398+
private <Result> Result handleEmptyResponse(Map<String, List<String>> responseHeaders, final Class<Result> clazz) {
399+
//Create an empty object to attach the response headers to
400+
InputStream in = new ByteArrayInputStream("{}".getBytes());
401+
402+
return handleJsonResponse(in, responseHeaders, clazz);
387403
}
388404

389405
/**

src/main/java/com/microsoft/graph/http/GraphServiceException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ public static <T> GraphServiceException createFromConnection(final IHttpRequest
283283
final String rawOutput = DefaultHttpProvider.streamToString(connection.getInputStream());
284284
GraphErrorResponse error;
285285
try {
286-
error = serializer.deserializeObject(rawOutput, GraphErrorResponse.class);
286+
error = serializer.deserializeObject(rawOutput, GraphErrorResponse.class, connection.getResponseHeaders());
287287
} catch (final Exception ex) {
288288
error = new GraphErrorResponse();
289289
error.error = new GraphError();

src/main/java/com/microsoft/graph/http/IConnection.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.io.IOException;
2626
import java.io.InputStream;
2727
import java.io.OutputStream;
28+
import java.util.List;
2829
import java.util.Map;
2930

3031
/**
@@ -90,6 +91,8 @@ public interface IConnection {
9091
* @return The map of headers.
9192
*/
9293
Map<String, String> getHeaders();
94+
95+
Map<String, List<String>> getResponseHeaders();
9396

9497
/**
9598
* Gets the HTTP request method.

src/main/java/com/microsoft/graph/http/UrlConnection.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import java.io.OutputStream;
3030
import java.net.HttpURLConnection;
3131
import java.net.ProtocolException;
32+
import java.util.ArrayList;
3233
import java.util.HashMap;
34+
import java.util.List;
3335
import java.util.Map;
3436

3537
/**
@@ -107,6 +109,23 @@ public int getContentLength() {
107109
public int getResponseCode() throws IOException {
108110
return connection.getResponseCode();
109111
}
112+
113+
public Map<String, List<String>> getResponseHeaders() {
114+
// Copy unmodifiable map to hashmap
115+
HashMap<String, List<String>> headerFields = new HashMap<>();
116+
headerFields.putAll(connection.getHeaderFields());
117+
118+
// Add the response code
119+
List<String> list = new ArrayList<>();
120+
try {
121+
list.add(String.format("%d", connection.getResponseCode()));
122+
} catch (IOException e) {
123+
throw new IllegalArgumentException("Invalid connection response code: could not connect to server", e);
124+
}
125+
126+
headerFields.put("responseCode", list);
127+
return headerFields;
128+
}
110129

111130
@Override
112131
public String getResponseMessage() throws IOException {

src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public DefaultSerializer(final ILogger logger) {
6767
*/
6868
@Override
6969
public <T> T deserializeObject(final String inputString, final Class<T> clazz) {
70+
return deserializeObject(inputString, clazz, null);
71+
}
72+
73+
@Override
74+
public <T> T deserializeObject(final String inputString, final Class<T> clazz, Map<String, java.util.List<String>> responseHeaders) {
7075
T jsonObject = gson.fromJson(inputString, clazz);
7176

7277
// Populate the JSON-backed fields for any annotations that are not in the object model
@@ -82,6 +87,12 @@ public <T> T deserializeObject(final String inputString, final Class<T> clazz) {
8287
}
8388

8489
jsonBackedObject.setRawObject(this, rawObject);
90+
91+
if (responseHeaders != null) {
92+
JsonElement convertedHeaders = gson.toJsonTree(responseHeaders);
93+
jsonBackedObject.additionalDataManager().put("graphResponseHeaders", convertedHeaders);
94+
}
95+
8596
jsonBackedObject.additionalDataManager().setAdditionalData(rawObject);
8697
} else {
8798
logger.logDebug("Deserializing a non-IJsonBackedObject type " + clazz.getSimpleName());

src/main/java/com/microsoft/graph/serializer/ISerializer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
package com.microsoft.graph.serializer;
2424

25+
import java.util.List;
26+
import java.util.Map;
27+
2528
/**
2629
* Serializes and deserializes items from strings into their types.
2730
*/
@@ -35,6 +38,15 @@ public interface ISerializer {
3538
* @return The deserialized item from the input string.
3639
*/
3740
<T> T deserializeObject(final String inputString, Class<T> clazz);
41+
42+
/**
43+
* Deserialize an object from the input string.
44+
* @param inputString The string that stores the representation of the item.
45+
* @param clazz The .class of the item to be deserialized.
46+
* @param <T> The type of the item to be deserialized.
47+
* @return The deserialized item from the input string.
48+
*/
49+
<T> T deserializeObject(final String inputString, Class<T> clazz, Map<String, List<String>> responseHeaders);
3850

3951
/**
4052
* Serializes an object into a string.

src/test/java/com/microsoft/graph/functional/TestBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private String GetAccessToken()
9898
conn.disconnect();
9999

100100
JsonObject res = new GsonBuilder().create().fromJson(jsonString.toString(), JsonObject.class);
101-
return res.get("access_token").toString();
101+
return res.get("access_token").toString().replaceAll("\"", "");
102102

103103
} catch (Exception e) {
104104
throw new Error("Error retrieving access token: " + e.getLocalizedMessage());

src/test/java/com/microsoft/graph/http/MockConnection.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.io.IOException;
66
import java.io.InputStream;
77
import java.io.OutputStream;
8+
import java.util.ArrayList;
89
import java.util.HashMap;
10+
import java.util.List;
911
import java.util.Map;
1012

1113
/**
@@ -76,4 +78,14 @@ public void setContentLength(int length) {
7678
// noop
7779
}
7880

81+
@Override
82+
public Map<String, List<String>> getResponseHeaders() {
83+
Map<String, List<String>> headers = new HashMap<String, List<String>>();
84+
ArrayList<String> headerValues = new ArrayList<String>();
85+
headerValues.add("value1");
86+
headers.put("header1", headerValues);
87+
88+
return headers;
89+
}
90+
7991
}

src/test/java/com/microsoft/graph/serializer/DefaultSeralizerTests.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
import static org.junit.Assert.*;
44

5-
import org.junit.After;
6-
import org.junit.Before;
75
import org.junit.Test;
86

97
import com.microsoft.graph.models.extensions.Drive;
8+
import com.microsoft.graph.models.extensions.User;
109
import com.microsoft.graph.models.extensions.FileAttachment;
1110
import com.microsoft.graph.models.generated.RecurrenceRangeType;
1211
import com.microsoft.graph.models.generated.BaseRecurrenceRange;
12+
import com.google.gson.JsonElement;
13+
import com.microsoft.graph.http.MockConnection;
1314
import com.microsoft.graph.logger.DefaultLogger;
1415
import com.microsoft.graph.models.extensions.Attachment;
1516
import com.microsoft.graph.models.extensions.DateOnly;
@@ -68,6 +69,21 @@ public void testRecurrenceRangeSerialization() throws Exception {
6869
}
6970

7071
@Test
72+
public void testResponseHeaders() throws Exception {
73+
MockConnection connection = new MockConnection(null);
74+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
75+
User user = serializer.deserializeObject("{\"id\":\"1\"}", User.class, connection.getResponseHeaders());
76+
77+
JsonElement responseHeaders = user.additionalDataManager().get("graphResponseHeaders");
78+
assertNotNull(responseHeaders);
79+
80+
JsonElement responseHeader = responseHeaders.getAsJsonObject().get("header1");
81+
assertNotNull(responseHeader);
82+
83+
assertEquals("value1", responseHeader.getAsJsonArray().get(0).getAsString());
84+
}
85+
86+
@Test
7187
public void testDeserializeDerivedType() throws Exception {
7288
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
7389
String source = "{\"@odata.context\": \"/attachments/$entity\",\"@odata.type\": \"#microsoft.graph.fileAttachment\",\"id\": \"AAMkAGQ0MjBmNWVkLTYxZjUtNDRmYi05Y2NiLTBlYjIwNzJjNmM1NgBGAAAAAAC6ff7latYeQqu_gLrhSAIhBwCF7iGjpaOmRqVwbZc-xXzwAAAAAAEMAACF7iGjpaOmRqVwbZc-xXzwAABQStA0AAABEgAQAFbGmeisbjtLnQdp7kC_9Fk=\",\"lastModifiedDateTime\": \"2018-01-23T21:50:22Z\",\"name\": \"Test Book.xlsx\",\"contentType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\"size\": 8457,\"isInline\": false,\"contentId\": null,\"contentLocation\": null,\"contentBytes\": \"bytedata\"}";

src/test/java/com/microsoft/graph/serializer/MockSerializer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
package com.microsoft.graph.serializer;
2424

25+
import java.util.List;
26+
import java.util.Map;
27+
2528
/**
2629
* Mock instance of the {@see ISerializer}
2730
*/
@@ -56,4 +59,10 @@ public <T> T deserializeObject(final String inputString, final Class<T> clazz) {
5659
public <T> String serializeObject(final T serializableObject) {
5760
return mSerializeReturn;
5861
}
62+
63+
@Override
64+
public <T> T deserializeObject(String inputString, Class<T> clazz, Map<String, List<String>> responseHeaders) {
65+
// TODO Auto-generated method stub
66+
return (T) mDeserializeReturn;
67+
}
5968
}

0 commit comments

Comments
 (0)