Skip to content

Commit

Permalink
Change HttpRequest to return an object with http response metadata
Browse files Browse the repository at this point in the history
{
    statusCode: 201
    reasonPhrase: "Accepted",
    headers: {...response headers...}
    content: object|string
}
  • Loading branch information
Tom Laird-McConnell committed Aug 21, 2019
1 parent a3ffe1a commit 284ad73
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 156 deletions.
2 changes: 2 additions & 0 deletions installbf.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
set npm_config_registry=https://botbuilder.myget.org/F/botframework-cli/auth/da91578f-5b61-4224-9c46-cb2522c66033/npm/
npm install -g @microsoft/botframework-cli@4.5.0-preview.76135
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
Expand All @@ -17,12 +20,54 @@
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
{
/// <summary>
/// Action for HttpRequests
/// Action for performing an HttpRequest.
/// </summary>
public class HttpRequest : DialogAction
{
private static readonly HttpClient client = new HttpClient();

/// <summary>
/// Result data of the the http operation.
/// </summary>
public class Result
{
public Result()
{
}

public Result(HttpHeaders headers)
{
foreach (var header in headers)
{
this.Headers[header.Key] = header.Value.FirstOrDefault();
}
}

/// <summary>
/// Gets or sets the status code from the response to the http operation.
/// </summary>
[JsonProperty("statusCode")]
public int StatusCode { get; set; }

/// <summary>
/// Gets or sets the reason phrase from the response to the http operation.
/// </summary>
[JsonProperty("reasonPhrase")]
public string ReasonPhrase { get; set; }

/// <summary>
/// Gets the headers from the response to the http operation.
/// </summary>
[JsonProperty("headers")]
public Dictionary<string, object> Headers { get; } = new Dictionary<string, object>();

/// <summary>
/// Gets or sets the content body from the response to the http operation.
/// </summary>
[JsonProperty("content")]
public object Content { get; set; }
}

public enum ResponseTypes
{
/// <summary>
Expand Down Expand Up @@ -84,8 +129,13 @@ protected override string OnComputeId()
public ResponseTypes ResponseType { get; set; } = ResponseTypes.Json;

/// <summary>
/// Property which is bidirectional property for input and output. Example: user.age will be passed in, and user.age will be set when the dialog completes
/// Gets or sets The property to store the result of the HTTP call in.
/// </summary>
/// <remarks>
/// The result will have 4 properties from the http response:
/// [statusCode|reasonPhrase|content|headers]
/// If the content is json it will be an deserialized object, otherwise it will be a string.
/// </remarks>
public string Property
{
get
Expand All @@ -95,17 +145,15 @@ public string Property

set
{
InputBindings[DialogContextState.DIALOG_VALUE] = value;
OutputBinding = value;
}
}

public HttpRequest(HttpMethod method, string url, string property, Dictionary<string, string> headers = null, JObject body = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
public HttpRequest(HttpMethod method, string url, string inputProperty, Dictionary<string, string> headers = null, JObject body = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{
this.RegisterSourceLocation(callerPath, callerLine);
this.Method = method;
this.Url = url ?? throw new ArgumentNullException(nameof(url));
this.Property = property;
this.Headers = headers;
this.Body = body;
}
Expand Down Expand Up @@ -244,37 +292,49 @@ private async Task ReplaceJTokenRecursively(DialogContext dc, JToken token)
break;
}

object result = (object)await response.Content.ReadAsStringAsync();
Result requestResult = new Result(response.Headers)
{
StatusCode = (int)response.StatusCode,
ReasonPhrase = response.ReasonPhrase,
};

object content = (object)await response.Content.ReadAsStringAsync();

switch (this.ResponseType)
{
case ResponseTypes.Activity:
var activity = JsonConvert.DeserializeObject<Activity>((string)result);
var activity = JsonConvert.DeserializeObject<Activity>((string)content);
requestResult.Content = activity;
await dc.Context.SendActivityAsync(activity, cancellationToken: cancellationToken).ConfigureAwait(false);
return await dc.EndDialogAsync(cancellationToken: cancellationToken);
break;

case ResponseTypes.Activities:
var activities = JsonConvert.DeserializeObject<Activity[]>((string)result);
var activities = JsonConvert.DeserializeObject<Activity[]>((string)content);
requestResult.Content = activities;
await dc.Context.SendActivitiesAsync(activities, cancellationToken: cancellationToken).ConfigureAwait(false);
return await dc.EndDialogAsync(cancellationToken: cancellationToken);
break;

case ResponseTypes.Json:
// Try set with JOjbect for further retreiving
try
{
result = JToken.Parse((string)result);
content = JToken.Parse((string)content);
}
catch
{
result = result.ToString();
content = content.ToString();
}

return await dc.EndDialogAsync(result, cancellationToken: cancellationToken);
requestResult.Content = content;
break;

case ResponseTypes.None:
default:
return await dc.EndDialogAsync(cancellationToken: cancellationToken);
break;
}

// return the actionResult as the result of this operation
return await dc.EndDialogAsync(result: requestResult, cancellationToken: cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"property": {
"$role": "expression",
"title": "Property",
"description": "The property to store the result of the HTTP call in (as object or string)",
"description": "The property to store the result of the HTTP call in. The result will have 4 properties from the http response: statusCode|reasonPhrase|content|headers. If the content is json it will be an deserialized object, otherwise it will be a string",
"examples": [
"dialog.contosodata"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
},
{
"$type": "Microsoft.SendActivity",
"activity": "Done! You have added a pet named \"{dialog.postResponse.name}\" with id \"{dialog.postResponse.id}\""
"activity": "Done! You have added a pet named \"{dialog.postResponse.content.name}\" with id \"{dialog.postResponse.content.id}\""
},
{
"$type": "Microsoft.TextInput",
Expand All @@ -65,7 +65,7 @@
},
{
"$type": "Microsoft.SendActivity",
"activity": "Great! I found your pet named \"{dialog.getResponse.name}\""
"activity": "Great! I found your pet named \"{dialog.getResponse.content.name}\""
}
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Show
- You have following issues : \n {join(foreach(dialog.getResponse, x, showSingleUrl(x)), '\n')}
- You have following issues : \n {join(foreach(dialog.getResponse.content, x, showSingleUrl(x)), '\n')}

# showSingleUrl(x)
- ```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
}
//{
// "$type": "Microsoft.SendActivity",
// "activity": "response: {user.acceptResponse}"
// "activity": "response: {user.acceptResponse.content}"
//}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
}
//{
// "$type": "Microsoft.SendActivity",
// "activity": "response: {user.createResponse}"
// "activity": "response: {user.createResponse.content}"
//}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
{
"$type": "Microsoft.SendActivity",
"activity": "response: {user.declineResponse}"
"activity": "response: {user.declineResponse.content}"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
{
"$schema": "../../../../app.schema",
"$type": "Microsoft.AdaptiveDialog",
"events": [
{
"$type": "Microsoft.OnBeginDialog",
"actions": [
"$schema": "../../../../app.schema",
"$type": "Microsoft.AdaptiveDialog",
"events": [
{
"$type": "Microsoft.IfCondition",
"condition": "dialog.token == null",
"actions": [
{
"$type": "Microsoft.OAuthPrompt",
"connectionName": "msgraph",
"title": "Log in",
"text": "Please log in to your Microsoft account",
"property": "dialog.token"
}
]
},
{
"$type": "Microsoft.HttpRequest",
"url": "https://graph.microsoft.com/v1.0/me/contacts?$filter=startswith(displayName,'{user.email}')",
"method": "GET",
"headers": {
"Authorization": "Bearer {dialog.token.Token}"
},
"property": "dialog.getResponse"
},
{
"$type": "Microsoft.SendActivity",
"activity": "The contact you find is {dialog.getResponse.value[0].displayName}, email address is {dialog.getResponse.value[0].emailAddresses[0].address}."
},
{
"$type": "Microsoft.SetProperty",
"value": "dialog.getResponse.value[0].emailAddresses[0].address",
"property": "user.email"
"$type": "Microsoft.OnBeginDialog",
"actions": [
{
"$type": "Microsoft.IfCondition",
"condition": "dialog.token == null",
"actions": [
{
"$type": "Microsoft.OAuthPrompt",
"connectionName": "msgraph",
"title": "Log in",
"text": "Please log in to your Microsoft account",
"property": "dialog.token"
}
]
},
{
"$type": "Microsoft.HttpRequest",
"url": "https://graph.microsoft.com/v1.0/me/contacts?$filter=startswith(displayName,'{user.email}')",
"method": "GET",
"headers": {
"Authorization": "Bearer {dialog.token.Token}"
},
"property": "dialog.getResponse"
},
{
"$type": "Microsoft.SendActivity",
"activity": "The contact you find is {dialog.getResponse.content.value[0].displayName}, email address is {dialog.getResponse.content.value[0].emailAddresses[0].address}."
},
{
"$type": "Microsoft.SetProperty",
"value": "dialog.getResponse.content.value[0].emailAddresses[0].address",
"property": "user.email"
}
]
}
]
}
]
]
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{
"$schema": "../../app.schema",
"$type": "Microsoft.AdaptiveDialog",
"actions": [
{
"$type": "Microsoft.IfCondition",
"condition": "dialog.token == null",
"actions": [
"$schema": "../../app.schema",
"$type": "Microsoft.AdaptiveDialog",
"actions": [
{
"$type": "Microsoft.OAuthPrompt",
"ConnectionName": "msgraph",
"Title": "Log in",
"Text": "Please log in to your calendar account",
"Property": "dialog.token"
"$type": "Microsoft.IfCondition",
"condition": "dialog.token == null",
"actions": [
{
"$type": "Microsoft.OAuthPrompt",
"ConnectionName": "msgraph",
"Title": "Log in",
"Text": "Please log in to your calendar account",
"Property": "dialog.token"
}
]
},
{
"$type": "Microsoft.HttpRequest",
"url": "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={utcNow()}&enddatetime={addDays(utcNow(), 1)}",
"method": "GET",
"header": {
"Authorization": "Bearer {dialog.token.Token}"
},
"Property": "user.getGraphMeetings"
}
]
},
{
"$type": "Microsoft.HttpRequest",
"url": "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={utcNow()}&enddatetime={addDays(utcNow(), 1)}",
"method": "GET",
"header": {
"Authorization": "Bearer {dialog.token.Token}"
},
"Property": "user.getGraphMeetings"
}
//,{
// "$type": "Microsoft.SendActivity",
// "activity": "{user.getGraphMeetings}"
//}
]
//,{
// "$type": "Microsoft.SendActivity",
// "activity": "{user.getGraphMeetings.content}"
//}
]
}
Loading

0 comments on commit 284ad73

Please sign in to comment.