New weekend project! I’ve been playing Phantasy Star Online 2 a lot recently. The game has events that occur periodically throughout the day, where it’s something I might want to log on to play. On the game’s official website they post the times when these events happen. But there’s a problem: I am incredibly lazy. I cannot be bothered to go to a website and look at a table of times. What I want is Alexa to tell me when the next one is.
No problem, I can just take one of my existing Alexa skills I wrote for Warframe and modify it for this game… except there’s no API for this game! Well… crap. Guess I have to design my own.
Everyone knows APIs are the lifeblood of everything on the interwebs. I love working with them! Once I discover I can get some JSON with a simple GET request, I’m all over that. The lights in my house are running on a Python interface I made to a RESTful API. I’ve built a professional career on consuming and improving RESTful APIs.
But something I’ve never done before is make my own brand new API from the ground up. I don’t really know where to begin, to be honest. So this blog post is going to document my process, from where my Google-fu takes me, to wherever this project ends up. Here are my key goals:
- Failure – Wait, failure is a goal? Oh yes. This is first and foremost a learning process, and I need to expect whatever I make here to end in disaster. In all probability, I’ll have to throw it away. And that’s okay! The fear of failure is what stops people from learning new things. I know a lot of people who don’t cook because they’re afraid they’ll screw it up. Of course you will! Throw that burned mess in the trash and try again! In the end, you’ll be able to make something tasty.
- Try New Technologies – I’ve been a mobile developer by trade for a long time. Most recently for me, that means Swift and C++. When I was focused on Android development, Java 8 was the new hotness. And Android’s moved on to Kotlin. Wikipedia tells me the non-mobile world has moved on to Java 14?! Crazy! That’s very much not a language I opt to use in my own personal projects. Let’s try that. And let’s do it on AWS, because I don’t use that much either. (Apart from Alexa Lambda functions, in Python. But that’s very much a self-contained system these days.)
- Maybe make something? – I guess it’d be nice to have an API I can call to find out when the next Urgent Quest is happening. Pfft, as if anyone writes code to accomplish tasks.
Okay, let’s get started! The first place all learning begins is Google!
Let’s try “create a rest api on aws“and see where that takes us.
Hmm… that’s a lot of stuff. Amazon has tons of tutorials about everything, but it can be pretty overwhelming.
Google’s Featured Snippet™ isn’t very useful – it’s halfway through a tutorial that extensively covers a massive number of subjects – all important, but I’m approaching this from the perspective of setting out to solve a specific problem, and solving the challenges that pop up in the order they pop up. I’m almost certainly not taking everything into account that will need to be, and this tutorial likely does. But I’m more likely to learn by solving the problems that are impacting me now, not just clicking on the box the tutorial tells me to. This tutorial is not for me.
The second link is more definition of terms than a tutorial. That’s pretty boring, let’s move on.
The third link looks much more like what we want. It’s a straightforward tutorial that covers an entire process. Let’s start this tutorial by opening up the AWS Management Console and… oh… what’s this?
Well, forget the hours of tutorials, let’s just do this!
We’ll Do It Live!
This approach starts you off creating a Lambda function and filling out some basic fields like names and roles. Like everyone else, I don’t want to think about security so I’ll just make this an open and publicly accessible API. What could possibly go wrong!
(Joking aside, if this project is completed, I wouldn’t be opposed to sharing this API with the world. Maybe someone will build some cool PSO2 stuff with it?)
In any case, fill out the info and click create.
Uh… What Now?
Okay, we’ve got a thing created. The topmost widget is the Designer that shows a Lambda function and a gateway.
There’s a bunch of widgets below this, and I don’t think I need to care about those. The default code looks like it’s doing something with DynamoDB, and clearly that’ll need to get replaced. Good new: I can indeed replace this with another language, though it looks like Node is the only language with a working code sample provided?
The next thing I want to do is test this thing. If I understand things correctly, it should give us some sort of REST response if we hit the gateway. Click on the gateway in the designer, and it pops open a widget with the URL. Let’s copy and paste that into some sort of REST tool.
But what tool? I know Postman is something a lot of people I work with use, though I tend to use other integration tools like Charles for much of my work. But in the spirit of trying new things, let’s use Postman!
Oh? You have to create an account? That’s annoying but whatever.
Oh? My username is already in use? Did I create an account before? Let me try to… oh son of a
Well dumb, But once you get past all that mess, we can finally test the gateway. Drum roll please…
Success! That looks like something this unconfigured code would return.
That was virtually painless! Now I can actually make something!
Design Is Law!
OpenAPI is a formal way to describe the behavior of a RESTful API. I’m a big fan of the potential a properly described OAS has. So let’s throw together a quick spec and go from there.
openapi: "3.0.2" info: version: 1.0.0 title: PSO2 API servers: - url: https://czaevsd4x1.execute-api.us-east-1.amazonaws.com/default/pso2API-Function paths: /uq: get: description: Gets the current or next Urgent Quest responses: '200': description: The current or next Urgent Quest content: application/json: schema: $ref: "#/components/schemas/UrgentQuest" default: description: unexpected error content: application/json: schema: $ref: "#/components/schemas/Error" components: schemas: UrgentQuest: description: Information about a specific UQ type: object properties: id: type: integer format: int64 name: type: string