Skip to content

Commit

Permalink
Fixed next gen API error handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeMayo committed Aug 7, 2020
1 parent 3c58f49 commit c422bde
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ static void ShowMenu()

static async Task PerformRecentSearchRawAsync(TwitterContext twitterCtx)
{
string unencodedStatus = "LINQ to Twitter";
string unencodedStatus = "JoeMayo";
string encodedStatus = Uri.EscapeDataString(unencodedStatus);
string queryString = "tweets/search?q=" + encodedStatus;
string queryString = "tweets/search?query=" + encodedStatus;

string previousBaseUrl = twitterCtx.BaseUrl;
twitterCtx.BaseUrl = "https://api.twitter.com/labs/2/";
Expand Down
21 changes: 20 additions & 1 deletion src/LinqToTwitter6/LinqToTwitter/Common/TwitterQueryException.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using LinqToTwitter.Net;
using System;
using System.Net;

namespace LinqToTwitter.Common
{
/// <summary>
/// Use for errors returned from HTTP GET and POST to Twitter
/// </summary>
/// <remarks>
/// The properties commented as "assigned by Twitter" are error details from the Twitter API itself.
/// </remarks>
public class TwitterQueryException : InvalidQueryException
{
/// <summary>
Expand All @@ -31,11 +35,26 @@ public TwitterQueryException(string message)
public TwitterQueryException(string message, Exception inner)
: base(message, inner) { }

/// <summary>
/// Error title - assigned by Twitter
/// </summary>
public string Title { get; set; }

/// <summary>
/// Error details - assigned by Twitter
/// </summary>
public string? Details { get; set; }

/// <summary>
/// Type of error - assigned by Twitter
/// </summary>
public string? Type { get; set; }

/// <summary>
/// Specific errors - assigned by Twitter
/// </summary>
public Error[] Errors { get; set; }

/// <summary>
/// Http status code from Twitter response
/// </summary>
Expand Down
45 changes: 45 additions & 0 deletions src/LinqToTwitter6/LinqToTwitter/Net/TwitterErrorDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#nullable disable

using System.Collections.Generic;

namespace LinqToTwitter.Net
{
// This is the shape of any potential error coming from the new Twitter API
// TwitterErrorDetails
//{
// "errors": [
// {
// "parameters": {
// "query": []
// },
// "message": "Request parameter `query` can not be empty"
// },
// {
// "parameters": {
// "q": [
// "LINQ%20to%20Twitter"
// ]
// },
// "message": "[q] is not one of [query,start_time,end_time,since_id,until_id,max_results,next_token,expansions,tweet.fields,media.fields,poll.fields,place.fields,user.fields]"
// }
// ],
// "title": "Invalid Request",
// "detail": "One or more parameters to your request was invalid.",
// "type": "https://api.twitter.com/labs/2/problems/invalid-request"
//}

public class TwitterErrorDetails
{
public Error[] Errors { get; set; }
public string Title { get; set; }
public string Detail { get; set; }
public string Type { get; set; }
}


public class Error
{
public Dictionary<string, string[]> Parameters { get; set; }
public string Message { get; set; }
}
}
83 changes: 31 additions & 52 deletions src/LinqToTwitter6/LinqToTwitter/Net/TwitterErrorHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace LinqToTwitter.Net
{
class TwitterErrorHandler
partial class TwitterErrorHandler
{
public static async Task ThrowIfErrorAsync(HttpResponseMessage msg)
{
Expand Down Expand Up @@ -54,9 +54,12 @@ internal static async Task HandleTooManyRequestsAsync(HttpResponseMessage msg)
throw new TwitterQueryException(message)
{
HelpLink = L2TKeys.FaqHelpUrl,
Type = error.Type,
StatusCode = HttpStatusCode.SeeOther,
ReasonPhrase = msg.ReasonPhrase + " (HTTP 429 - Too Many Requests)"
ReasonPhrase = msg.ReasonPhrase + " (HTTP 429 - Too Many Requests)",
Title = error.Title,
Details = error.Detail,
Type = error.Type,
Errors = error.Errors
};
}

Expand All @@ -66,9 +69,12 @@ internal static void BuildAndThrowTwitterQueryException(string responseStr, Http

throw new TwitterQueryException(error.Title)
{
Type = error.Type,
StatusCode = msg.StatusCode,
ReasonPhrase = msg.ReasonPhrase
ReasonPhrase = msg.ReasonPhrase,
Title = error.Title,
Details = error.Detail,
Type = error.Type,
Errors = error.Errors
};
}

Expand All @@ -83,9 +89,12 @@ internal async static Task HandleUnauthorizedAsync(HttpResponseMessage msg)
throw new TwitterQueryException(message)
{
HelpLink = L2TKeys.FaqHelpUrl,
Type = error.Type,
StatusCode = HttpStatusCode.Unauthorized,
ReasonPhrase = msg.ReasonPhrase
ReasonPhrase = msg.ReasonPhrase,
Title = error.Title,
Details = error.Detail,
Type = error.Type,
Errors = error.Errors
};
}

Expand All @@ -96,26 +105,28 @@ internal static TwitterErrorDetails ParseTwitterErrorMessage(string responseStr)
var responseJson = JsonDocument.Parse(responseStr);
var root = responseJson.RootElement;

if (root.TryGetProperty("errors", out JsonElement errors))
if (IsErrorFormatRecognized(root))
{
JsonElement errorElement = errors.EnumerateArray().FirstOrDefault();

return new TwitterErrorDetails
{
Title = errorElement.GetProperty("title").GetString(),
Detail = errorElement.GetProperty("detail").GetString(),
Type = errorElement.GetProperty("type").GetString(),
Title = root.GetProperty("title").GetString(),
Detail = root.GetProperty("detail").GetString(),
Type = root.GetProperty("type").GetString(),
Errors =
(from error in errorElement.GetProperty("errors").EnumerateArray()
(from error in root.GetProperty("errors").EnumerateArray()
select new Error
{
Message = error.GetProperty("message").ToString(),
Parameters =
(from pram in error.GetProperty("parameters").EnumerateObject()
from key in pram.EnumerateObject()
select pram)
(from parm in error.GetProperty("parameters").EnumerateObject()
let vals =
(from val in parm.Value.EnumerateArray()
select val.GetString())
.ToArray()
select new { parm.Name, vals })
.ToDictionary(
key => key)
key => key.Name,
val => val.vals)
})
.ToArray()
};
Expand All @@ -125,41 +136,9 @@ from key in pram.EnumerateObject()
return new TwitterErrorDetails { Detail = responseStr };
}

// TwitterErrorDetails
//{
// "errors": [
// {
// "parameters": {
// "query": []
// },
// "message": "Request parameter `query` can not be empty"
// },
// {
// "parameters": {
// "q": [
// "LINQ%20to%20Twitter"
// ]
// },
// "message": "[q] is not one of [query,start_time,end_time,since_id,until_id,max_results,next_token,expansions,tweet.fields,media.fields,poll.fields,place.fields,user.fields]"
// }
// ],
// "title": "Invalid Request",
// "detail": "One or more parameters to your request was invalid.",
// "type": "https://api.twitter.com/labs/2/problems/invalid-request"
//}

public class TwitterErrorDetails
{
public Error[] Errors { get; set; }
public string Title { get; set; }
public string Detail { get; set; }
public string Type { get; set; }
}

public class Error
static bool IsErrorFormatRecognized(JsonElement root)
{
public Dictionary<string, string[]> Parameters { get; set; }
public string Message { get; set; }
return root.TryGetProperty("errors", out JsonElement errors);
}
}
}

0 comments on commit c422bde

Please sign in to comment.