This is part 2 of the REST API blogpost. In part1 we successfully setup two REST API endpoints using the UniversalDashboard PowerShell module. In this part we are going to create a simple module that support some CRUD operation against our API. As we are trying to keep things as simple as possible, we will not use any fancy framework (like Plaster) to build our module. We are also going to skip a very important step you should familiarize yourself with, Pester tests. Lets get to it.





The module

We will build a module called FilesAPI. The module folder will look like this:





In the functions folder I have already added the 2 helper functions from part 1, Get-AuthorizationHeader and ConvertTo-Base64. The other folders are just placeholders for important stuff like classes, private functions that you do not want to make available for the module consumer and tests for Pester tests. For such a small module that we are going to create, one could argue that it is much easier to just add the functions directly in the module definition file (psm1), however I strongly urge you to create a folder structure for your modules. It is a huge benefit to have each function, test and class in a separate file. If you use the folder structure, Visual Studio shines compared to ISE as your module grows. It will also make the transition to module frameworks like Plaster much easier.





Since we are using a single file for each function, this is what we will put in out module file:





$ModuleScript variable contains the script that will load each function file, class and private function in our folder structure. As we add functions to the folders, it will only export the functions in the functions folder. It is a generic template that I started to use quite recently. The inspiration came from Kieran Jacobsen and his Plaster template. Go ahead and execute the script to create the FilesApi.psm1 module file.



First API function – Get-FileApi

We are going to start with the first simple function and we will name it Get-FileApi. As you might recall from the first part, the API needs an Authorization header for all calls to our API, so we need that as an parameter for the function. It might also be a good idea to add a parameter for Name so we can filter on specific files. Below is my function:





Basically we are just wrapping Invoke-RestMethod supplying the URI, method and the header containing the Authorization key/hashtable. We target the Authorization parameter as mandatory and leave the Name parameter optional. Save this function in the functions directory and name the file Get-FileApi.ps1.





Second API function – Set-FileApi

Secondly we are now going to create a function for the POST method of the API. The endpoint accepts 3 parameters:

Authorization

FileName

Content

Our function needs to implement these parameters. Since this is a function uses the verb Set, we should be nice to the consumers of our module and implement WhatIf, more commonly know as SupportsShouldProcess. I really hate it when a destructive command do not implement the WhatIf parameter, here is looking at you Azure for PowerShell. Again we are marking the Authorization parameter as Mandatory for our function:





Pretty cool, with a few extra lines of code, our functions supports the WhatIf parameter and we have created 2 functions that talk to an API. Copy the function and save it in the functions folder as Set-FileApi.ps1.





Turning it up a notch

Now at this point, we have two working function, however this is not really how APIs work. UniversalDashboards helps us quite a bit since the objects returned from Invoke-RestMethod is converted to real PowerShell objects. Invoke-RestMethod usually returns a HtmlWebResponseObject which contains two important properties. Content and StatusCode. To make it a little more interesting, we will try and get as close as possible to a real API. We are going to update our endpoints to return an object containing 2 properties; Content and StatusCode. Content will contain a JSON string of the object previously returned from the API. StatusCode is an HTTP code indicating the status of our request, which we will set to 200 if authorization is okay. We are also going to add a Name header for our Endpoint to simulate server side filtering. After the modifications, the Endpoint definition looks like this:





Go ahead and register the new endpoint.





Running our Get-FileApi function now is resulting in this output:









We can see the statuscode and the Content property containing a JSON string which is what we are after. So we have to check the StatusCode to verify that the request was OK (200) and then we have to convert the content string to an object using ConvertFrom-Json. After the modifications we have the following:





Running the Get-FileApi function gives us a nice object and filtering by Name works to, even with wildcards:









Applying the same logic to our CreateFileEndpoint, we update the definition to this:





After registering the new endpoint definition and running the unmodified Set-FileApi function, we get the new respons from our API:









Updating the Set-FileApi function to convert the JSON string to an object, it should look something like this:





Trying the Set-FileApi function after updating, we again get a nice object ouput:









Final module work

If you have followed along until now, your functions directory should look like this:





Your root folder should just have the folders and a single file FilesApi.psm1 (we created that in the beginning):





Now we are going to create the FilesApi.psd1 or what is know as the manifest. Here is the script I will be using:





A couple of notes here. If you plan to run this script several times, like if you add more functions, best practice is to “keep” the GUID for the module. If you run this script, the manifest will have a new GUID each time. Also if you are checking the manifest into source control, it is always nice that the manifest is encoded in UTF8. The New-ModuleManifest encodes it in ASCII format, which you probably do not want. In the last two lines I am converting the module to UTF8. After you have created the manifest, you may go ahead and start a new PowerShell session and import the module:









Lets take it for a spin, first we need to create an authorization variable:





After getting an authorization object, we go ahead and run Get-FileApi with the parameter:









Well, I’ll be darned, it works. Who would have thought.





What is missing?

A couple of things really.





Help

As a best practice you should add help to your functions.





Test Driven Development, TDD for short, is something you might want to look into. In essence you write your unit tests before you create the function. As I have mentioned previously, you can use Pester for this. It it built-in and included with PowerShell as a module.





Different APIs have a couple of ways of adding authentication to the requests. I have only shown one method.



