Kenton's API v1
Tags: azure, cloudresumechallenge, node
Published: 2022-05-27 15:48:04

Hello, In this blog post I will be talking about how I set up my Cloud Resume Challenge website to include REST API functionality.

As a bit of preface, I always viewed REST APIs as a gateway for my Powershell skills to be able to reach out and interact with the internet. When Powershell was first presented to me, it was described as a tool to make Windows administration tasks quicker and more efficient. It's very useful for Windows server and specifically Server Core but what good is a modern computer if it can't connect to the internet? 

First it was web scraping with Invoke-Webrequest but this didn't give the exact information that I wanted. There was too much HTML included after drilling down past the status codes and raw content.  In came Invoke-Restmethod. What a game changer, I could interact with HTTP endpoints in a familiar way and chain other commands based on information from those endpoints.

I drummed up some ideas about what information would be relevant to provide by JSON. To me, my resume made the most sense.

What are the steps that I need for this?
1. Node js and Express js to host the REST API
     * Endpoints
     * JSON file for Resume
     * Basic Authentication

2. Host on Github for CI/CD

3. Host on Azure to have a public endpoint

#Node js and Express js to host the REST API

What did I need to do to set this up?
I used Javascript in the main Cloud Resume Challenge so I started there, maybe there was a framework that had REST API functionality that would be built in?

I found it, Express js on top of Node js.

##Endpoints

After following a couple guides I was able to spin up a local instance of Node js that I could make an invoke-Restmethod call to and get the information that I set up to serve.

```
app.get('/api', (req, res) => {

res.send('🔥🔥🔥');

})

```

##JSON file for Resume

What's next? Well, Let's find a template for my resume in JSON.

I copied from the [jsonresume.org](https://jsonresume.org/schema/) schema and made some tweaks to get them more inline with my skills.

I needed to add that JSON as an endpoint. Instead of putting the whole JSON in the response, everywhere I looked said to have a separate file and have the main file reference the JSON file.

Two things needed to be added for that, fs and the path as a const.

```
const fs = require("fs")

const resume = require("./resume.json")

```
```
app.get('/resume', (req, res) => {
    res.header("Content-Type",'application/json');
    res.sendFile('resume.json' , {root :__dirname});   
}); 
```


The JSON template included a place to put a picture. I knew that pictures can't exactly be served by JSON but I figured that I could have an endpoint that shows a picture if you go to it in a browser.

I first thought about adding the image to the Github repo but then I realized that the image is already in Azure Blob storage. What if I just have a separate page that linked back to that image.

With some research I determined that an endpoint can just be linked to a different HTML page. From that HTML page we can display the linked picture.

```
app.get('/resume/image', (req, res) => {
    res.sendFile(__dirname + '/image.html');
});
```

```
<img src="https://azureresumekm.blob.core.windows.net/$web/images/km.jfif" alt="My_Picture"></img>
```

There I am and accessible at the /resume/image endpoint.

##Basic Authentication

One last piece of the puzzle to make this unique, Authentication.
Previously, I was able to host a REST API but I didn't like that you could just go to the website and see the information. I wanted there to be *a* hoop to jump through to access the information. I understand that Basic authentication isn't used that much and putting it right in the code that is going on Github is insecure but this is only to demonstrate.

That said, I set up a couple Basic authentication accounts in the index file that will kick back a 401 if the credentials are not inputted correctly. I have also added a challenge so that if the website is visited by a browser and doesn't include credentials it will ask for them.

```
app.use(basicAuth({
    users: {'user': "resume" },
    challenge: true
}))
```

So I have all my files ready, I run `node .` on my VSCode instance and try the endpoints. Success, At least on localhost. I also try accessing through Powershell but I hit a bump. Invoke-restmethod wouldn't work with basic authentication. I do some research and find the official documentation for the command and it has the -authentication parameter. I didn't see that available in my version of Powershell so I decided to give the shell an update.
Right after the update we were able to use the -cred, -authentication and the -allowunencryptedauthentication parameters to initiate a call.

```
Invoke-RestMethod http://localhost:8080/resume -cred resume 
-authentication Basic -AllowUnencryptedAuthentication
```
#Host on Github for CI/CD

From what I could recall from the original CRC and website, getting the Github repo set up for this shouldn't have been an issue. 
`git init`
`git add -A`
`git commit -m "first commit"`
`git push`

Looking back, I'm not sure that anything past the init was necessary but I was lost in VSCode and doing all the commands didn't hurt.

Next, I used a Github tutorial that had the proper az cli commands to get started and had the correct YAML file to make the connection.

I had a bit of trouble with the first run of Github actions, The npm test was failing and I wasn't sure why. I looked into it and my package.json file literally had an error code built in.
"test": "echo \"Error: no test specified\" && exit 1"
I'm not sure the purpose of it but the complete removal of the test attribute seemed to work.

I ran into another issue, I copied over the secret key like the guide suggested but I noticed that I copied in the name that didn't match the YAML file. I corrected that and I was able to make a connection with Github Actions.

#Hosting on Azure

Through the Github tutorial I used the az cli to create a new app service plan and web app to host the node app. From there I wanted to add a custom domain. In the past when I tried hosting an endpoint on my website I had trouble with the static web app. The specific limitation I ran into was that only the 'index' page was accessible, I couldn't find a way to have a /resume added onto this web app. Instead of migrating away from the static web app, I decided to implement a sub domain.

rest.kmcloud.tech

This is something I will probably change in the future, When I look up best practices for REST APIs I see that it makes more sense to have endpoints be on the root of the webpage.

#Conclusion

Finally, All the pieces are working together to serve my resume in JSON to anyone on the internet.

`curl rest.kmcloud.tech/resume -u user:resume`

`Invoke-RestMethod http://rest.kmcloud.tech/resume -cred user 
-authentication Basic -AllowUnencryptedAuthentication`

Through Github actions I can also make changes locally, quickly test them and push them all the way to Azure. There’s no tinkering with files or settings, it just works.

The Github repo for this project is here.
https://github.com/Kenseventy/Resume-API

In the future I hope implement a ‘counter’ just like the website and also a ‘guestbook’ of some sort that stores actual responses in a database.

Thanks for checking out this blog post, I know it’s long and maybe has some incorrect information but I see this blog as a place to write down my thoughts and record some of my work. 

If this helps even one person that would be great.


Thanks,
-Kenton