.NET API Layer for Freshservice











up vote
0
down vote

favorite












Below is an class to act as API Layer for the Freshservice APIs.
Here's their docs:
https://api.freshservice.com/



Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?



Some of the objects used are "HelpdeskTicket", "Note", "Agent",
Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?



    Public Class FreshserviceAPI
Implements IFreshserviceAPI


Public Sub New(portalURL As String, username As String, password As String)
Me.PortalURL = portalURL
Me.UserName = username
Me.Password = password
End Sub

Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
Public Property Password As String = "" Implements IFreshserviceAPI.Password


Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket

Dim ticket As HelpdeskTicket = Nothing

Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Get,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password)
If response IsNot Nothing Then
ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
Return root.helpdesk_ticket
End Function)
End If

Return ticket

End Function

Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket

Dim createdTicket As HelpdeskTicket = Nothing

Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)

If response IsNot Nothing Then
createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
Return root.item.helpdesk_ticket
End Function)
End If

Return createdTicket

End Function

Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket

Dim updatedTicket As HelpdeskTicket = Nothing

Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Put,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)



If response IsNot Nothing Then
updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
Return root.ticket
End Function)
End If



Return updatedTicket

End Function

Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote

Throw New NotImplementedException()

End Function

Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote

Dim createdNote As Note = Nothing

Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=note.ToPostJson())
If response IsNot Nothing Then
createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
Return root.note
End Function)
End If

Return createdNote

End Function


Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment

Dim createdAttachment As Attachment = Nothing

Dim responseJson As String = ""

Using client = New HttpClient()
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
Using formData = New MultipartFormDataContent()

formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")

formData.Add(New ByteArrayContent(attachment.file_data),
name:="helpdesk_note[attachments][resource]",
fileName:=attachment.content_file_name)

Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
HttpUtil.SetSslProtocal()
Dim response = client.PostAsync(noteResourceURL, formData).Result
If response.IsSuccessStatusCode Then
Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
responseJson = streamReader.ReadToEnd()
End Using
End If
End Using
End Using

If Not String.IsNullOrWhiteSpace(responseJson) Then
Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
If noteRoot IsNot Nothing Then
Dim createdNote As Note = noteRoot.note
If createdNote IsNot Nothing Then
If createdNote.attachments?.Any() Then
attachment = createdNote.attachments.First()
End If
End If
End If
End If

Return attachment

End Function


Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser

Dim user As User = Nothing


If String.IsNullOrWhiteSpace(emailAddress) Then
'//Fresh will pull ALL agents if you pass a blank email address
'//we don't want that.
Return Nothing
End If

Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
method:=HttpMethod.Get)
If response IsNot Nothing Then

user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
If agentItems?.Any() Then
Dim agent = agentItems.First()
If agent IsNot Nothing Then
Return If(agent Is Nothing, Nothing, agent.agent.user)
End If
End If
Return Nothing
End Function)

End If


Return user

End Function




Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType

Dim item As ItemType = Nothing

Dim responseBodyJSON As String = ""
Using streamReader As New StreamReader(response.GetResponseStream())
responseBodyJSON = streamReader.ReadToEnd()
Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
item = itemExtractor(jsonRoot)
End Using

Return item

End Function


Here's the source of "HelpdeskTicket.vb"



 Public Class HelpdeskTicket


<JsonProperty("email")>
Public Property RequesterEmail As String

Public Property category As Object

Public Property cc_email As CcEmail

<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property created_at As DateTime?

Public Property deleted As Boolean?

Public Property department_id_value As Object

Public Property display_id As Integer?

<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property due_by As DateTime?

Public Property email_config_id As Object

<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property frDueBy As DateTime?

Public Property fr_escalated As Boolean?

Public Property group_id As Object

Public Property id As Long?

Public Property impact As Integer?

Public Property isescalated As Boolean?

Public Property item_category As Object

Public Property notes As List(Of NoteResponseRoot)

Public Property owner_id As Object

Public Property priority As Integer?

Public Property requester_id As Long?

Public Property responder_id As Object

Public Property source As Integer?

Public Property spam As Boolean?

Public Property status As Integer?

Public Property sub_category As Object

Public Property subject As String

Public Property ticket_type As String

Public Property to_email As Object

<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property updated_at As DateTime?

Public Property urgency As Integer?

Public Property description As String

Public Property description_html As String

Public Property status_name As String

Public Property requester_status_name As String

Public Property priority_name As String

Public Property source_name As String

Public Property requester_name As String

Public Property responder_name As String

Public Property to_emails As Object

Public Property department_name As Object

Public Property assoc_problem_id As Object

Public Property assoc_change_id As Object

Public Property assoc_change_cause_id As Object

Public Property assoc_asset_id As Object

Public Property urgency_name As String

Public Property impact_name As String

Public Property attachments As List(Of Object)

Public Property custom_field As Dictionary(Of String, Object)

Public Property tags As List(Of Object)
End Class


Public Class CcEmail

Public Property cc_emails As List(Of String)

Public Property fwd_emails As List(Of Object)

Public Property reply_cc As List(Of String)

Public Property tkt_cc As List(Of String)
End Class


Public Class TicketResponseRoot

Public Property helpdesk_ticket As HelpdeskTicket
End Class

Public Class TicketPostResponseRoot

Public Property redirect As Object

Public Property item As TicketResponseRoot

End Class

Public Class TicketPutttResponseRoot

Public Property ticket As HelpdeskTicket

End Class


HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:



Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports System.Security.Authentication
Imports System.Text

Namespace HttpUtils

Public Class HttpUtil

Public Shared Function SubmitHttpRequest(resourceURL As String,
method As HttpMethod,
basicAuthUser As String,
basicAuthPassword As String,
Optional requestBodyContent As String = Nothing) As HttpWebResponse

Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
httpWebrequest.Method = method.Method
httpWebrequest.Accept = "application/json"
httpWebrequest.ContentType = "application/json"
httpWebrequest.Timeout = 25000
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)


If requestBodyContent IsNot Nothing Then
Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
writer.Write(requestBodyContent)
End Using
End If


Dim httpResponse As HttpWebResponse = Nothing
Try
SetSslProtocal()
httpResponse = httpWebrequest.GetResponse()
Catch WebEx As WebException
Throw New HttpApiException(requestBody:=requestBodyContent,
message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
innerException:=WebEx)
End Try

Return httpResponse

End Function


''' <summary>
''' Sets the Security Protocal to avoid error:
''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
''' (Authentication failed because remote party has closed the transport stream)
''' See: https://stackoverflow.com/a/47517067/614263
''' </summary>
Public Shared Sub SetSslProtocal()
Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
SecurityProtocolType)
ServicePointManager.SecurityProtocol = Tls12
End Sub


End Class


End Namespace









share|improve this question




























    up vote
    0
    down vote

    favorite












    Below is an class to act as API Layer for the Freshservice APIs.
    Here's their docs:
    https://api.freshservice.com/



    Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?



    Some of the objects used are "HelpdeskTicket", "Note", "Agent",
    Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?



        Public Class FreshserviceAPI
    Implements IFreshserviceAPI


    Public Sub New(portalURL As String, username As String, password As String)
    Me.PortalURL = portalURL
    Me.UserName = username
    Me.Password = password
    End Sub

    Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
    Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
    Public Property Password As String = "" Implements IFreshserviceAPI.Password


    Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket

    Dim ticket As HelpdeskTicket = Nothing

    Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
    Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
    method:=HttpMethod.Get,
    basicAuthUser:=Me.UserName,
    basicAuthPassword:=Me.Password)
    If response IsNot Nothing Then
    ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
    Return root.helpdesk_ticket
    End Function)
    End If

    Return ticket

    End Function

    Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket

    Dim createdTicket As HelpdeskTicket = Nothing

    Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
    Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
    method:=HttpMethod.Post,
    basicAuthUser:=Me.UserName,
    basicAuthPassword:=Me.Password,
    requestBodyContent:=ticket.ToPostJson)

    If response IsNot Nothing Then
    createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
    Return root.item.helpdesk_ticket
    End Function)
    End If

    Return createdTicket

    End Function

    Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket

    Dim updatedTicket As HelpdeskTicket = Nothing

    Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
    Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
    method:=HttpMethod.Put,
    basicAuthUser:=Me.UserName,
    basicAuthPassword:=Me.Password,
    requestBodyContent:=ticket.ToPostJson)



    If response IsNot Nothing Then
    updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
    Return root.ticket
    End Function)
    End If



    Return updatedTicket

    End Function

    Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote

    Throw New NotImplementedException()

    End Function

    Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote

    Dim createdNote As Note = Nothing

    Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
    Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
    method:=HttpMethod.Post,
    basicAuthUser:=Me.UserName,
    basicAuthPassword:=Me.Password,
    requestBodyContent:=note.ToPostJson())
    If response IsNot Nothing Then
    createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
    Return root.note
    End Function)
    End If

    Return createdNote

    End Function


    Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment

    Dim createdAttachment As Attachment = Nothing

    Dim responseJson As String = ""

    Using client = New HttpClient()
    Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
    client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
    Using formData = New MultipartFormDataContent()

    formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")

    formData.Add(New ByteArrayContent(attachment.file_data),
    name:="helpdesk_note[attachments][resource]",
    fileName:=attachment.content_file_name)

    Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
    HttpUtil.SetSslProtocal()
    Dim response = client.PostAsync(noteResourceURL, formData).Result
    If response.IsSuccessStatusCode Then
    Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
    responseJson = streamReader.ReadToEnd()
    End Using
    End If
    End Using
    End Using

    If Not String.IsNullOrWhiteSpace(responseJson) Then
    Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
    If noteRoot IsNot Nothing Then
    Dim createdNote As Note = noteRoot.note
    If createdNote IsNot Nothing Then
    If createdNote.attachments?.Any() Then
    attachment = createdNote.attachments.First()
    End If
    End If
    End If
    End If

    Return attachment

    End Function


    Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser

    Dim user As User = Nothing


    If String.IsNullOrWhiteSpace(emailAddress) Then
    '//Fresh will pull ALL agents if you pass a blank email address
    '//we don't want that.
    Return Nothing
    End If

    Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
    Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
    basicAuthUser:=Me.UserName,
    basicAuthPassword:=Me.Password,
    method:=HttpMethod.Get)
    If response IsNot Nothing Then

    user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
    If agentItems?.Any() Then
    Dim agent = agentItems.First()
    If agent IsNot Nothing Then
    Return If(agent Is Nothing, Nothing, agent.agent.user)
    End If
    End If
    Return Nothing
    End Function)

    End If


    Return user

    End Function




    Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
    itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType

    Dim item As ItemType = Nothing

    Dim responseBodyJSON As String = ""
    Using streamReader As New StreamReader(response.GetResponseStream())
    responseBodyJSON = streamReader.ReadToEnd()
    Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
    item = itemExtractor(jsonRoot)
    End Using

    Return item

    End Function


    Here's the source of "HelpdeskTicket.vb"



     Public Class HelpdeskTicket


    <JsonProperty("email")>
    Public Property RequesterEmail As String

    Public Property category As Object

    Public Property cc_email As CcEmail

    <JsonConverter(GetType(IsoDateTimeConverter))>
    Public Property created_at As DateTime?

    Public Property deleted As Boolean?

    Public Property department_id_value As Object

    Public Property display_id As Integer?

    <JsonConverter(GetType(IsoDateTimeConverter))>
    Public Property due_by As DateTime?

    Public Property email_config_id As Object

    <JsonConverter(GetType(IsoDateTimeConverter))>
    Public Property frDueBy As DateTime?

    Public Property fr_escalated As Boolean?

    Public Property group_id As Object

    Public Property id As Long?

    Public Property impact As Integer?

    Public Property isescalated As Boolean?

    Public Property item_category As Object

    Public Property notes As List(Of NoteResponseRoot)

    Public Property owner_id As Object

    Public Property priority As Integer?

    Public Property requester_id As Long?

    Public Property responder_id As Object

    Public Property source As Integer?

    Public Property spam As Boolean?

    Public Property status As Integer?

    Public Property sub_category As Object

    Public Property subject As String

    Public Property ticket_type As String

    Public Property to_email As Object

    <JsonConverter(GetType(IsoDateTimeConverter))>
    Public Property updated_at As DateTime?

    Public Property urgency As Integer?

    Public Property description As String

    Public Property description_html As String

    Public Property status_name As String

    Public Property requester_status_name As String

    Public Property priority_name As String

    Public Property source_name As String

    Public Property requester_name As String

    Public Property responder_name As String

    Public Property to_emails As Object

    Public Property department_name As Object

    Public Property assoc_problem_id As Object

    Public Property assoc_change_id As Object

    Public Property assoc_change_cause_id As Object

    Public Property assoc_asset_id As Object

    Public Property urgency_name As String

    Public Property impact_name As String

    Public Property attachments As List(Of Object)

    Public Property custom_field As Dictionary(Of String, Object)

    Public Property tags As List(Of Object)
    End Class


    Public Class CcEmail

    Public Property cc_emails As List(Of String)

    Public Property fwd_emails As List(Of Object)

    Public Property reply_cc As List(Of String)

    Public Property tkt_cc As List(Of String)
    End Class


    Public Class TicketResponseRoot

    Public Property helpdesk_ticket As HelpdeskTicket
    End Class

    Public Class TicketPostResponseRoot

    Public Property redirect As Object

    Public Property item As TicketResponseRoot

    End Class

    Public Class TicketPutttResponseRoot

    Public Property ticket As HelpdeskTicket

    End Class


    HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:



    Imports System.IO
    Imports System.Net
    Imports System.Net.Http
    Imports System.Security.Authentication
    Imports System.Text

    Namespace HttpUtils

    Public Class HttpUtil

    Public Shared Function SubmitHttpRequest(resourceURL As String,
    method As HttpMethod,
    basicAuthUser As String,
    basicAuthPassword As String,
    Optional requestBodyContent As String = Nothing) As HttpWebResponse

    Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
    httpWebrequest.Method = method.Method
    httpWebrequest.Accept = "application/json"
    httpWebrequest.ContentType = "application/json"
    httpWebrequest.Timeout = 25000
    Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
    httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)


    If requestBodyContent IsNot Nothing Then
    Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
    writer.Write(requestBodyContent)
    End Using
    End If


    Dim httpResponse As HttpWebResponse = Nothing
    Try
    SetSslProtocal()
    httpResponse = httpWebrequest.GetResponse()
    Catch WebEx As WebException
    Throw New HttpApiException(requestBody:=requestBodyContent,
    message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
    innerException:=WebEx)
    End Try

    Return httpResponse

    End Function


    ''' <summary>
    ''' Sets the Security Protocal to avoid error:
    ''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
    ''' (Authentication failed because remote party has closed the transport stream)
    ''' See: https://stackoverflow.com/a/47517067/614263
    ''' </summary>
    Public Shared Sub SetSslProtocal()
    Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
    Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
    SecurityProtocolType)
    ServicePointManager.SecurityProtocol = Tls12
    End Sub


    End Class


    End Namespace









    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      Below is an class to act as API Layer for the Freshservice APIs.
      Here's their docs:
      https://api.freshservice.com/



      Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?



      Some of the objects used are "HelpdeskTicket", "Note", "Agent",
      Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?



          Public Class FreshserviceAPI
      Implements IFreshserviceAPI


      Public Sub New(portalURL As String, username As String, password As String)
      Me.PortalURL = portalURL
      Me.UserName = username
      Me.Password = password
      End Sub

      Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
      Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
      Public Property Password As String = "" Implements IFreshserviceAPI.Password


      Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket

      Dim ticket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Get,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password)
      If response IsNot Nothing Then
      ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
      Return root.helpdesk_ticket
      End Function)
      End If

      Return ticket

      End Function

      Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket

      Dim createdTicket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Post,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=ticket.ToPostJson)

      If response IsNot Nothing Then
      createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
      Return root.item.helpdesk_ticket
      End Function)
      End If

      Return createdTicket

      End Function

      Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket

      Dim updatedTicket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Put,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=ticket.ToPostJson)



      If response IsNot Nothing Then
      updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
      Return root.ticket
      End Function)
      End If



      Return updatedTicket

      End Function

      Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote

      Throw New NotImplementedException()

      End Function

      Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote

      Dim createdNote As Note = Nothing

      Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
      method:=HttpMethod.Post,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=note.ToPostJson())
      If response IsNot Nothing Then
      createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
      Return root.note
      End Function)
      End If

      Return createdNote

      End Function


      Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment

      Dim createdAttachment As Attachment = Nothing

      Dim responseJson As String = ""

      Using client = New HttpClient()
      Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
      client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
      Using formData = New MultipartFormDataContent()

      formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")

      formData.Add(New ByteArrayContent(attachment.file_data),
      name:="helpdesk_note[attachments][resource]",
      fileName:=attachment.content_file_name)

      Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
      HttpUtil.SetSslProtocal()
      Dim response = client.PostAsync(noteResourceURL, formData).Result
      If response.IsSuccessStatusCode Then
      Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
      responseJson = streamReader.ReadToEnd()
      End Using
      End If
      End Using
      End Using

      If Not String.IsNullOrWhiteSpace(responseJson) Then
      Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
      If noteRoot IsNot Nothing Then
      Dim createdNote As Note = noteRoot.note
      If createdNote IsNot Nothing Then
      If createdNote.attachments?.Any() Then
      attachment = createdNote.attachments.First()
      End If
      End If
      End If
      End If

      Return attachment

      End Function


      Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser

      Dim user As User = Nothing


      If String.IsNullOrWhiteSpace(emailAddress) Then
      '//Fresh will pull ALL agents if you pass a blank email address
      '//we don't want that.
      Return Nothing
      End If

      Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      method:=HttpMethod.Get)
      If response IsNot Nothing Then

      user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
      If agentItems?.Any() Then
      Dim agent = agentItems.First()
      If agent IsNot Nothing Then
      Return If(agent Is Nothing, Nothing, agent.agent.user)
      End If
      End If
      Return Nothing
      End Function)

      End If


      Return user

      End Function




      Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
      itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType

      Dim item As ItemType = Nothing

      Dim responseBodyJSON As String = ""
      Using streamReader As New StreamReader(response.GetResponseStream())
      responseBodyJSON = streamReader.ReadToEnd()
      Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
      item = itemExtractor(jsonRoot)
      End Using

      Return item

      End Function


      Here's the source of "HelpdeskTicket.vb"



       Public Class HelpdeskTicket


      <JsonProperty("email")>
      Public Property RequesterEmail As String

      Public Property category As Object

      Public Property cc_email As CcEmail

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property created_at As DateTime?

      Public Property deleted As Boolean?

      Public Property department_id_value As Object

      Public Property display_id As Integer?

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property due_by As DateTime?

      Public Property email_config_id As Object

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property frDueBy As DateTime?

      Public Property fr_escalated As Boolean?

      Public Property group_id As Object

      Public Property id As Long?

      Public Property impact As Integer?

      Public Property isescalated As Boolean?

      Public Property item_category As Object

      Public Property notes As List(Of NoteResponseRoot)

      Public Property owner_id As Object

      Public Property priority As Integer?

      Public Property requester_id As Long?

      Public Property responder_id As Object

      Public Property source As Integer?

      Public Property spam As Boolean?

      Public Property status As Integer?

      Public Property sub_category As Object

      Public Property subject As String

      Public Property ticket_type As String

      Public Property to_email As Object

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property updated_at As DateTime?

      Public Property urgency As Integer?

      Public Property description As String

      Public Property description_html As String

      Public Property status_name As String

      Public Property requester_status_name As String

      Public Property priority_name As String

      Public Property source_name As String

      Public Property requester_name As String

      Public Property responder_name As String

      Public Property to_emails As Object

      Public Property department_name As Object

      Public Property assoc_problem_id As Object

      Public Property assoc_change_id As Object

      Public Property assoc_change_cause_id As Object

      Public Property assoc_asset_id As Object

      Public Property urgency_name As String

      Public Property impact_name As String

      Public Property attachments As List(Of Object)

      Public Property custom_field As Dictionary(Of String, Object)

      Public Property tags As List(Of Object)
      End Class


      Public Class CcEmail

      Public Property cc_emails As List(Of String)

      Public Property fwd_emails As List(Of Object)

      Public Property reply_cc As List(Of String)

      Public Property tkt_cc As List(Of String)
      End Class


      Public Class TicketResponseRoot

      Public Property helpdesk_ticket As HelpdeskTicket
      End Class

      Public Class TicketPostResponseRoot

      Public Property redirect As Object

      Public Property item As TicketResponseRoot

      End Class

      Public Class TicketPutttResponseRoot

      Public Property ticket As HelpdeskTicket

      End Class


      HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:



      Imports System.IO
      Imports System.Net
      Imports System.Net.Http
      Imports System.Security.Authentication
      Imports System.Text

      Namespace HttpUtils

      Public Class HttpUtil

      Public Shared Function SubmitHttpRequest(resourceURL As String,
      method As HttpMethod,
      basicAuthUser As String,
      basicAuthPassword As String,
      Optional requestBodyContent As String = Nothing) As HttpWebResponse

      Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
      httpWebrequest.Method = method.Method
      httpWebrequest.Accept = "application/json"
      httpWebrequest.ContentType = "application/json"
      httpWebrequest.Timeout = 25000
      Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
      httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)


      If requestBodyContent IsNot Nothing Then
      Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
      writer.Write(requestBodyContent)
      End Using
      End If


      Dim httpResponse As HttpWebResponse = Nothing
      Try
      SetSslProtocal()
      httpResponse = httpWebrequest.GetResponse()
      Catch WebEx As WebException
      Throw New HttpApiException(requestBody:=requestBodyContent,
      message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
      innerException:=WebEx)
      End Try

      Return httpResponse

      End Function


      ''' <summary>
      ''' Sets the Security Protocal to avoid error:
      ''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
      ''' (Authentication failed because remote party has closed the transport stream)
      ''' See: https://stackoverflow.com/a/47517067/614263
      ''' </summary>
      Public Shared Sub SetSslProtocal()
      Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
      Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
      SecurityProtocolType)
      ServicePointManager.SecurityProtocol = Tls12
      End Sub


      End Class


      End Namespace









      share|improve this question















      Below is an class to act as API Layer for the Freshservice APIs.
      Here's their docs:
      https://api.freshservice.com/



      Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?



      Some of the objects used are "HelpdeskTicket", "Note", "Agent",
      Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?



          Public Class FreshserviceAPI
      Implements IFreshserviceAPI


      Public Sub New(portalURL As String, username As String, password As String)
      Me.PortalURL = portalURL
      Me.UserName = username
      Me.Password = password
      End Sub

      Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
      Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
      Public Property Password As String = "" Implements IFreshserviceAPI.Password


      Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket

      Dim ticket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Get,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password)
      If response IsNot Nothing Then
      ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
      Return root.helpdesk_ticket
      End Function)
      End If

      Return ticket

      End Function

      Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket

      Dim createdTicket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Post,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=ticket.ToPostJson)

      If response IsNot Nothing Then
      createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
      Return root.item.helpdesk_ticket
      End Function)
      End If

      Return createdTicket

      End Function

      Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket

      Dim updatedTicket As HelpdeskTicket = Nothing

      Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
      method:=HttpMethod.Put,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=ticket.ToPostJson)



      If response IsNot Nothing Then
      updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
      Return root.ticket
      End Function)
      End If



      Return updatedTicket

      End Function

      Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote

      Throw New NotImplementedException()

      End Function

      Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote

      Dim createdNote As Note = Nothing

      Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
      method:=HttpMethod.Post,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      requestBodyContent:=note.ToPostJson())
      If response IsNot Nothing Then
      createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
      Return root.note
      End Function)
      End If

      Return createdNote

      End Function


      Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment

      Dim createdAttachment As Attachment = Nothing

      Dim responseJson As String = ""

      Using client = New HttpClient()
      Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
      client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
      Using formData = New MultipartFormDataContent()

      formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")

      formData.Add(New ByteArrayContent(attachment.file_data),
      name:="helpdesk_note[attachments][resource]",
      fileName:=attachment.content_file_name)

      Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
      HttpUtil.SetSslProtocal()
      Dim response = client.PostAsync(noteResourceURL, formData).Result
      If response.IsSuccessStatusCode Then
      Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
      responseJson = streamReader.ReadToEnd()
      End Using
      End If
      End Using
      End Using

      If Not String.IsNullOrWhiteSpace(responseJson) Then
      Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
      If noteRoot IsNot Nothing Then
      Dim createdNote As Note = noteRoot.note
      If createdNote IsNot Nothing Then
      If createdNote.attachments?.Any() Then
      attachment = createdNote.attachments.First()
      End If
      End If
      End If
      End If

      Return attachment

      End Function


      Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser

      Dim user As User = Nothing


      If String.IsNullOrWhiteSpace(emailAddress) Then
      '//Fresh will pull ALL agents if you pass a blank email address
      '//we don't want that.
      Return Nothing
      End If

      Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
      Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
      basicAuthUser:=Me.UserName,
      basicAuthPassword:=Me.Password,
      method:=HttpMethod.Get)
      If response IsNot Nothing Then

      user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
      If agentItems?.Any() Then
      Dim agent = agentItems.First()
      If agent IsNot Nothing Then
      Return If(agent Is Nothing, Nothing, agent.agent.user)
      End If
      End If
      Return Nothing
      End Function)

      End If


      Return user

      End Function




      Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
      itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType

      Dim item As ItemType = Nothing

      Dim responseBodyJSON As String = ""
      Using streamReader As New StreamReader(response.GetResponseStream())
      responseBodyJSON = streamReader.ReadToEnd()
      Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
      item = itemExtractor(jsonRoot)
      End Using

      Return item

      End Function


      Here's the source of "HelpdeskTicket.vb"



       Public Class HelpdeskTicket


      <JsonProperty("email")>
      Public Property RequesterEmail As String

      Public Property category As Object

      Public Property cc_email As CcEmail

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property created_at As DateTime?

      Public Property deleted As Boolean?

      Public Property department_id_value As Object

      Public Property display_id As Integer?

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property due_by As DateTime?

      Public Property email_config_id As Object

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property frDueBy As DateTime?

      Public Property fr_escalated As Boolean?

      Public Property group_id As Object

      Public Property id As Long?

      Public Property impact As Integer?

      Public Property isescalated As Boolean?

      Public Property item_category As Object

      Public Property notes As List(Of NoteResponseRoot)

      Public Property owner_id As Object

      Public Property priority As Integer?

      Public Property requester_id As Long?

      Public Property responder_id As Object

      Public Property source As Integer?

      Public Property spam As Boolean?

      Public Property status As Integer?

      Public Property sub_category As Object

      Public Property subject As String

      Public Property ticket_type As String

      Public Property to_email As Object

      <JsonConverter(GetType(IsoDateTimeConverter))>
      Public Property updated_at As DateTime?

      Public Property urgency As Integer?

      Public Property description As String

      Public Property description_html As String

      Public Property status_name As String

      Public Property requester_status_name As String

      Public Property priority_name As String

      Public Property source_name As String

      Public Property requester_name As String

      Public Property responder_name As String

      Public Property to_emails As Object

      Public Property department_name As Object

      Public Property assoc_problem_id As Object

      Public Property assoc_change_id As Object

      Public Property assoc_change_cause_id As Object

      Public Property assoc_asset_id As Object

      Public Property urgency_name As String

      Public Property impact_name As String

      Public Property attachments As List(Of Object)

      Public Property custom_field As Dictionary(Of String, Object)

      Public Property tags As List(Of Object)
      End Class


      Public Class CcEmail

      Public Property cc_emails As List(Of String)

      Public Property fwd_emails As List(Of Object)

      Public Property reply_cc As List(Of String)

      Public Property tkt_cc As List(Of String)
      End Class


      Public Class TicketResponseRoot

      Public Property helpdesk_ticket As HelpdeskTicket
      End Class

      Public Class TicketPostResponseRoot

      Public Property redirect As Object

      Public Property item As TicketResponseRoot

      End Class

      Public Class TicketPutttResponseRoot

      Public Property ticket As HelpdeskTicket

      End Class


      HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:



      Imports System.IO
      Imports System.Net
      Imports System.Net.Http
      Imports System.Security.Authentication
      Imports System.Text

      Namespace HttpUtils

      Public Class HttpUtil

      Public Shared Function SubmitHttpRequest(resourceURL As String,
      method As HttpMethod,
      basicAuthUser As String,
      basicAuthPassword As String,
      Optional requestBodyContent As String = Nothing) As HttpWebResponse

      Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
      httpWebrequest.Method = method.Method
      httpWebrequest.Accept = "application/json"
      httpWebrequest.ContentType = "application/json"
      httpWebrequest.Timeout = 25000
      Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
      httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)


      If requestBodyContent IsNot Nothing Then
      Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
      writer.Write(requestBodyContent)
      End Using
      End If


      Dim httpResponse As HttpWebResponse = Nothing
      Try
      SetSslProtocal()
      httpResponse = httpWebrequest.GetResponse()
      Catch WebEx As WebException
      Throw New HttpApiException(requestBody:=requestBodyContent,
      message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
      innerException:=WebEx)
      End Try

      Return httpResponse

      End Function


      ''' <summary>
      ''' Sets the Security Protocal to avoid error:
      ''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
      ''' (Authentication failed because remote party has closed the transport stream)
      ''' See: https://stackoverflow.com/a/47517067/614263
      ''' </summary>
      Public Shared Sub SetSslProtocal()
      Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
      Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
      SecurityProtocolType)
      ServicePointManager.SecurityProtocol = Tls12
      End Sub


      End Class


      End Namespace






      api vb.net rest client






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 13 mins ago









      Heslacher

      44.8k460155




      44.8k460155










      asked Apr 6 at 15:39









      unnknown

      15316




      15316



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191418%2fnet-api-layer-for-freshservice%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191418%2fnet-api-layer-for-freshservice%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Quarter-circle Tiles

          build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

          Mont Emei