Simplest VB.NET WebApi2 client for RESTful microServices documented by Swagger/OpenAPI.
- 1. What is Swagger API
- 2. Base class - my WebApi2 client of JSON Web Token (JWT) microServices.
- 3. Extend base class.
- 4. Other way to expand WebApi Client.
- 5. What is JWT OpenID authentication and how it working.
1. What is Swagger API
Too many fashion word is appearing in IT in couple last years. But it means some simple principles what existing in our world during many-many years. One of stupid word (looks as new) is webServices and microDervices. And to emphasize stupidity this worlds need to write in lowerCamelCase instead UpperCamelCase. Stupid young programmer don't understand than microServices and webServices has written by any VB.NET programmers every days since 2002 year. I wrote article (for example) about this two word - How classic ASP.NET programmers has realized WEB.API since 2005 year. And similar means carry any another fashion word in IT, for example during more then 10 years all VB WEB programmers has been write various Web Services, for example this is second reincarnation WebServices Типовий SOAP/WSDL сервіс.. This services has been documented by DISCO-file. Modern analogue of DISCO-file is Swagger-type of documentation WebServices.
So Swagger UI is JavaScript/CSS UI intended to documentation of RESTful API, its contains some parts (services and definition of structure used by service) and look as below. Commented version is an my ancient historical version this same API with JavaScriptSerializer.
And code below is no more then modern reincarnation of stupid, advertised and not workable WCF Client. Any self-respecting programmer has own implementation of this simplest idea - this is my own first synchronous version as replacement WCF Client - WCF_CLIENT - клиент Web-сервиса, WCF_CLIENT - клиент Web-сервиса and this is part of my asynchronous library - Multithreading Parsers with Parallel, CsQuery, Newtonsoft.Json, OfficeOpenXml and IAsyncResult/AsyncCallback.
2. Base class - my WebApi2 client of JSON Web Token (JWT) microServices.
Below I publish synchronous part of my WebApi2 client of JSON Web Token (JWT) microServices.
1: Imports System.Net
2: Imports System.Net.Http
3: Imports System.Net.Http.Headers
4: Imports System.Runtime.CompilerServices
5: Imports System.Text
6: Imports System.Web.Script.Serialization
7: Imports Newtonsoft.Json
8: Imports Newtonsoft.Json.Converters
9: Imports Newtonsoft.Json.Linq
10:
11: Public Class WebApi2Result
12: Property IsSuccess As Boolean
13: Property Result As String
14: Property Headers As HttpResponseHeaders
15: Property Status As HttpStatusCode
16: Public Sub New(Response As HttpResponseMessage)
17: If Response.Content IsNot Nothing Then
18: Result = Response.Content.ReadAsStringAsync().Result 'sync, Await without .Result
19: End If
20: Headers = Response.Headers
21: Status = Response.StatusCode
22: If Response.IsSuccessStatusCode Then
23: IsSuccess = True
24: Else
25: IsSuccess = False
26: End If
27: End Sub
28:
29: Public Function HeaderToString() As String
30: Dim Str1 As New StringBuilder
31: If Headers IsNot Nothing Then
32: For Each One In Headers
33: Str1.AppendLine()
34: Str1.Append(One.Key & " : ")
35: For Each Val As String In One.Value
36: Str1.Append(Val & ",")
37: Next
38: Str1.Length = Str1.Length - 1
39: Next
40: Return Str1.ToString
41: Else
42: Return ""
43: End If
44:
45: End Function
46:
47: End Class
48:
49: Public Class WebApi2
50:
51: Dim BaseApiURL As String
52: Dim Client As HttpClient
53: Public Shared Property DoubleNumericFormaterSerializerSettings = New JsonSerializerSettings With {.Converters = {New FormatNumbersAsTextConverter()}}
54: Public Shared Property JavascriptTimestampMicrosecondSerializerSettings = New JsonSerializerSettings With {.Converters = {New JavascriptTimestampMicrosecondConverter()}}
55:
56: Public Sub New()
57: BaseApiURL = My.Settings.BaseApiURL
58: Client = New HttpClient()
59: Client.BaseAddress = New Uri(BaseApiURL)
60: Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
61: 'Serializer = New JavaScriptSerializer()
62: End Sub
63:
64: Public Sub New(BaseURL As String)
65: BaseApiURL = BaseURL
66: Client = New HttpClient()
67: Client.BaseAddress = New Uri(BaseApiURL)
68: Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
69: End Sub
70:
71: Function Err1(Ex As Exception, Response As HttpResponseMessage) As WebApi2Result
72: Dim Ret1 As New WebApi2Result(New HttpResponseMessage(HttpStatusCode.SeeOther))
73: Ret1.IsSuccess = False
74: If Response IsNot Nothing Then
75: Ret1.Status = Response.StatusCode
76: Ret1.Headers = Response.Headers
77: End If
78: Ret1.Result = Ex.Message
79: If Ex.InnerException IsNot Nothing Then
80: Ret1.Result = Ex.Message & vbCrLf & Ex.InnerException.ToString
81: End If
82: Return Ret1
83: End Function
84:
85: Public Function GetWithoutAU(ApiPoint As String) As WebApi2Result
86: Dim Response As HttpResponseMessage
87: Try
88: Response = Client.GetAsync(ApiPoint).Result 'sync, Await without .Result
89: Return New WebApi2Result(Response)
90: Catch ex As Exception
91: Return Err1(ex, Response)
92: End Try
93: End Function
94:
95: Public Function Post(ApiPoint As String, InputJsonObject As Object) As WebApi2Result
96: Dim Response As HttpResponseMessage
97: Try
98: 'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
99: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
100: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
101: Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
102: Return New WebApi2Result(Response)
103: Catch ex As Exception
104: Return Err1(ex, Response)
105: End Try
106: End Function
107:
108: Public Function GetWithBearerHeader(ApiPoint As String, BearerToken As String) As WebApi2Result
109: Dim Response As HttpResponseMessage
110: Try
111: Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
112: Response = Client.GetAsync(ApiPoint).Result 'sync, Await without .Result
113: Return New WebApi2Result(Response)
114: Catch ex As Exception
115: Return Err1(ex, Response)
116: End Try
117: End Function
118:
119: Public Function PostWithBearerHeader(ApiPoint As String, BearerToken As String) As WebApi2Result
120: Dim Response As HttpResponseMessage
121: Try
122: Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
123: Response = Client.PostAsync(ApiPoint, New StringContent("")).Result 'sync, Await without .Result
124: Return New WebApi2Result(Response)
125: Catch ex As Exception
126: Return Err1(ex, Response)
127: End Try
128: End Function
129:
130: Public Function PostWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
131: Dim Response As HttpResponseMessage
132: Try
133: Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
134: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
135: 'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
136: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
137: Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
138: Return New WebApi2Result(Response)
139: Catch ex As Exception
140: Return Err1(ex, Response)
141: End Try
142: End Function
143:
144: Public Function PutWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
145: Dim Response As HttpResponseMessage
146: Try
147: Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
148: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
149: 'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
150: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
151: Response = Client.PutAsync(ApiPoint, Content).Result 'sync, Await without .Result
152: Return New WebApi2Result(Response)
153: Catch ex As Exception
154: Return Err1(ex, Response)
155: End Try
156: End Function
157:
158: Public Function DeleteWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
159: Dim Response As HttpResponseMessage
160: Try
161: Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
162: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
163: 'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
164: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
165: Response = Client.SendAsync(New HttpRequestMessage(HttpMethod.Delete, ApiPoint) With {.Content = Content}).Result
166: Return New WebApi2Result(Response)
167: Catch ex As Exception
168: Return Err1(ex, Response)
169: End Try
170: End Function
171:
172: Public Function GetWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String) As WebApi2Result
173: Dim Response As HttpResponseMessage
174: Try
175: Client.DefaultRequestHeaders.Clear()
176: Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
177: Response = Client.GetAsync(ApiPoint).Result 'sync, Await without .Result
178: Return New WebApi2Result(Response)
179: Catch ex As Exception
180: Return Err1(ex, Response)
181: End Try
182: End Function
183:
184: Public Function PutWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
185: Dim Response As HttpResponseMessage
186: Try
187: Client.DefaultRequestHeaders.Clear()
188: Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
189: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
190: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
191: Response = Client.PutAsync(ApiPoint, Content).Result 'sync, Await without .Result
192: Return New WebApi2Result(Response)
193: Catch ex As Exception
194: Return Err1(ex, Response)
195: End Try
196: End Function
197:
198: Public Function PostWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
199: Dim Response As HttpResponseMessage
200: Try
201: Client.DefaultRequestHeaders.Clear()
202: Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
203: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
204: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
205: Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
206: Return New WebApi2Result(Response)
207: Catch ex As Exception
208: Return Err1(ex, Response)
209: End Try
210: End Function
211:
212: Public Function DeleteWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
213: Dim Response As HttpResponseMessage
214: Try
215: Client.DefaultRequestHeaders.Clear()
216: Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
217: Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
218: Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
219: Response = Client.SendAsync(New HttpRequestMessage(HttpMethod.Delete, ApiPoint) With {.Content = Content}).Result
220: Return New WebApi2Result(Response)
221: Catch ex As Exception
222: Return Err1(ex, Response)
223: End Try
224: End Function
3. Extend base class.
This is a way to extend base class by extension function.
1: Imports System.Runtime.CompilerServices
2: Imports System.Text
3: Imports Newtonsoft.Json
4: Imports Newtonsoft.Json.Linq
5:
6: Public Module BinanceAPIExtension
7:
8: <Extension()>
9: Public Function BinanceApiTrades(Binance As WebApi2, Symbol As String, ByRef BinanceTrades As List(Of TradeModel)) As Boolean
10: Dim Trades = Binance.GetWithoutAU("/api/v3/trades?symbol=" & Symbol)
11: If Trades.IsSuccess Then
12: Dim TradesArr1 As JArray = JArray.Parse(Trades.Result)
13: BinanceTrades = JsonConvert.DeserializeObject(Of List(Of TradeModel))(TradesArr1.ToString)
14: Return True
15: Else
16: MsgBox(Trades.Result & vbCrLf & Trades.Status.ToString & vbCrLf & FormatObjForPrint(Trades.Result) & vbCrLf & Trades.HeaderToString, MsgBoxStyle.Critical, "/api/v3/trades Error")
17: Return False
18: End If
19: End Function
20:
21: <Extension()>
22: Public Function BinanceApiExchangeInfo(Binance As WebApi2, ByRef BinanceExchangeSymbols As List(Of BinanceExchangeSymbol)) As Boolean
23: Dim Info = Binance.GetWithoutAU("/api/v3/exchangeInfo")
24: If Info.IsSuccess Then
25: Dim TradesArr1 As JArray = JArray.Parse(Info.Result)
26: BinanceExchangeSymbols = JsonConvert.DeserializeObject(Of List(Of BinanceExchangeSymbol))(TradesArr1.ToString)
27: Return True
28: Else
29: MsgBox(Info.Result & vbCrLf & Info.Status.ToString & vbCrLf & Info.HeaderToString, MsgBoxStyle.Critical, "/api/v3/exchangeInfo Error")
30: Return False
31: End If
32: End Function
33:
34:
4. Other way to expand WebApi Client.
This is a simplest WebApi2 client, in reality it can be expanded by many future, for example by various converters Customize Newtonsoft.Json Serializer/Deserializer to convert Javascript Datetime and Number to .NET datatype.
5. What is JWT OpenID authentication and how it working.
But, how to use this API in practice to implement JWT OpenID authentication? Please, look at my code below.
1: Imports System.IdentityModel.Tokens.Jwt
2: Imports System.Net.Http
3: Imports Newtonsoft.Json
4: Imports Newtonsoft.Json.Linq
5:
6: Public Class StartForm
7:
8: Public WithEvents LoginTimer1 As New Timer
9: Dim Folex As WebApi2
10: Dim CurrentLoginToken As LoginToken
...
17: Private Sub StartForm_Load(sender As Object, e As EventArgs) Handles Me.Load
18: Folex = New WebApi2
19: Text &= " (" & My.Application.Info.Version.ToString & ")"
20: LoginTimer1.Interval = 1000
21: End Sub
22:
23: Private Sub LoginButton1_Click(sender As Object, e As EventArgs) Handles LoginButton1.Click
24:
25: Dim LoginPhase1 = Folex.Post("/api/auth/login", New With {.login = LoginTextBox1.Text, .password = PassTextBox1.Text, .isAdmin = False})
26: If LoginPhase1.IsSuccess Then
27:
28: Dim ResponseJson As JObject = JObject.Parse(LoginPhase1.Result)
29: Dim Token As String = ResponseJson("tempToken").Value(Of String)
30: Dim TwoFAuKey As String = InputBox("Get 2FA Key", "Login", "000000")
31:
32: If TwoFAuKey = "000000" Then
33: Exit Sub
34: Else
35: Dim LoginPhase2 = Folex.Post("/api/auth/twoFactorAuthCodeLogin", New With {.code = TwoFAuKey, .tempToken = Token, .isAdmin = False})
36: If LoginPhase2.IsSuccess Then
37: If Not LoginPhase2.Result.Contains("errorMsg") Then
38: CurrentLoginToken = JsonConvert.DeserializeObject(Of LoginToken)(LoginPhase2.Result)
39: AutoClosingMessageBox.Show(FormatLoginToken, "Login success")
40: LoginTokenTextBox.Text = FormatLoginToken()
41: LoginTimer1.Start()
42: KeysButton.Enabled = True
43: BalanceButton.Enabled = True
44: DynamicRateButton.Enabled = True
45: Else
46: MsgBox(LoginPhase2.Result, MsgBoxStyle.Critical, "TwoFAu Error")
47: End If
48: Else
49: MsgBox(LoginPhase2.Result, MsgBoxStyle.Critical, "TwoFAu Error")
50: End If
51: End If
52: Else
53: MsgBox(LoginPhase1.Result, MsgBoxStyle.Critical, "Login Error")
54: End If
55: End Sub
56:
57: Private Sub LoginTimer1_Tick(sender As Object, e As EventArgs) Handles LoginTimer1.Tick
58: Dim RestTime As Double = (CurrentLoginToken.expire_token - DateTime.UtcNow).TotalSeconds
59: If RestTime < 10 Then
60: Dim RefreshToken = Folex.PostWithBearerHeader("/api/auth/refresh", CurrentLoginToken.refresh_token)
61: If RefreshToken.IsSuccess Then
62: If Not RefreshToken.Result.Contains("errorMsg") Then
63: CurrentLoginToken = JsonConvert.DeserializeObject(Of LoginToken)(RefreshToken.Result)
64: LoginTimer1.Stop()
65: LoginTimer1.Start()
66: AutoClosingMessageBox.Show(FormatLoginToken, "Refresh token success")
67: Else
68: LoginTimer1.Stop()
69: MsgBox(RefreshToken.Result, MsgBoxStyle.Critical, "Refresh token Error")
70: End If
71: Else
72: LoginTimer1.Stop()
73: MsgBox(RefreshToken.Result, MsgBoxStyle.Critical, "Refresh token Error")
74: End If
75: Else
76: Me.InvokeOnUiThreadIfRequired(Sub() ToolStripStatusLabel1.Text = "Online " & CInt(RestTime))
77: Me.InvokeOnUiThreadIfRequired(Sub() ToolStripContainer1.Refresh())
78: End If
79:
80: End Sub
...
164: Public Class LoginToken
165: Property login As String
166: Property access_token As String
167: Property expire_token As DateTime
168: Property refresh_token As String
169: End Class
170:
...
This my program pass Two Form Authentication and show Refresh and Access token.
Exactly in the same way is use any modern JacaScript environment, like Angular, where you can see headers Authorization: Bearer XXXXXXX.XXXX.XXXX
|