OK. We know how to convert objects to and from JSON. That's important to this project because any web API is mostly about sending and receiving JSON objects.
I like to work in layers. To log in, I need to send some particular JSON to the server, and it's going to give me some JSON back. I don't want to muck about with HTTP types every time I do that. So I'm going to write a "RestClient" class to handle the HTTP bits for me. Let's have a look at the first draft:
Code:
Imports System.IO
Imports System.Net
Public Class RestClient
Public Function Post(ByVal url As String, ByVal payload As String) As String
' Configure the request headers.
Dim request As HttpWebRequest = CType(HttpWebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.ContentType = "application/json"
' Send the request plus the JSON payload.
Using requestStream As Stream = request.GetRequestStream()
Using writer As New StreamWriter(requestStream, Text.Encoding.UTF8)
writer.Write(payload)
End Using
End Using
' Read the response and its JSON payload.
Using response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
If response.StatusCode <> HttpStatusCode.OK Then
' This needs to be more sophisticated, you can flesh it out later.
Throw New ApplicationException("There was an error with the request.")
End If
Using responseStream As Stream = response.GetResponseStream()
Using reader As New StreamReader(responseStream, Text.Encoding.UTF8)
Return reader.ReadToEnd()
End Using
End Using
End Using
End Function
End Class
This method takes the URL and some JSON. It sets up an HTTP POST request and sends the JSON along with it. It then reads the response, throws an exception if there was an error, or returns the JSON payload of the response.
Why am I leaving the JSON as a string here? Why am I not using objects? Life is easiest if each method does only one thing. This method "sends a request and returns the response". That's about as close to "one thing" as an HTTP exchange can get. If I made a more generic version that worked with objects, it would, "Serialize an object to JSON, then send it as part of a REST request, then attempt to deserialize the response and return the deserialized object." That's more complicated. More complicated things are more likely to fail, and when they fail they're harder to debug.
So I've got this RestClient class. How's this help me do something with the API? Well, I want to make using the API pretty easy. So I'd like a class that doesn't look like HTTP at all, and instead works with the objects I need to make to represent the JSON. When I look at the /login endpoint, I can describe it as "a function that takes some credentials and returns a JWT". In VB terms:
Code:
Public Function Login(ByVal credentials As TvDbCredentials) As String
But wait. The '/login/ endpoint doesn't return a String. It returns a JSON string representing an object with a 'token' property (unless there's an error.) So I need to make an object to represent it:
Code:
Public Class LoginResult
Public Property token As String
End Class
Armed with that, I can write a function that converts the TvDbCredentials to JSON, sends it to the /login endpoint, and returns the token from the result:
Code:
Imports Newtonsoft.Json
Public Class TvDbApi
Public Function Login(ByVal credentials As TvDbCredentials) As String
Dim restClient As New RestClient()
Dim url As String = "https://example.com/login"
Dim payloadJson As String = JsonConvert.SerializeObject(credentials)
Dim responseJson As String = restClient.Post(url, payloadJson)
Dim responseObject As LoginResult = JsonConvert.DeserializeObject(Of LoginResult)(responseJson)
Return responseObject.token
End Function
End Class
See how small, neat, and easy to understand it is with the HTTP logic removed? At this point you ought to be able to get a JWT with a small test application:
Code:
Module Module1
Sub Main()
Dim credentials As New TvDbCredentials()
credentials.apikey = "apikey asdf"
credentials.username = "username asdf"
credentials.userkey = "userkey asdf"
Dim tvDbApi As New TvDbApi()
Dim jwt As String = tvDbApi.Login(credentials)
Console.WriteLine(jwt)
End Sub
End Module
See the layers at work? You can log in and get the JWT without thinking about JSON or HTTP now. This is another good place for me to stop. Try this out. Make sure to change the URL from 'example.com' to the right one for TvDb, and make sure you know if you should be using https or just http. If the program prints a JWT, you're doing great and can continue. If there is an error, we have to fix that before moving on.
The next post is going to try out a random entry point to demonstrate how we can take the code we already have and adjust it to include a JWT.