Become the Very Best, Like No One Ever Was: Create Your Own Pokemon API with TypeScript & Deno
Become the Very Best, Like No One Ever Was: Create Your Own Pokemon API with TypeScript & Deno was initially published on Saturday January 14 2023 on the Tech Dev Blog. For the latest up-to-date content, fresh out of the oven, visit https://techdevblog.io and subscribe to our newsletter!
Welcome to our guide on how to create a JSON REST Pokemon API using Deno, TypeScript, and the PokeAPI! In this guide, we'll be walking through the process of setting up a simple API that can retrieve information about Pokemon from the PokeAPI and return it in JSON format. We'll be using Deno as our runtime environment, TypeScript for type-checking, and the PokeAPI as our data source.
Prerequisites
Before we begin, you'll need to make sure you have the following installed on your machine:
- Deno - a secure JavaScript/TypeScript runtime built with V8 and Rust
- TypeScript - a strongly type superset of JavaScript
- Denon - a development tool that restarts your server when you make changes to your code
Installing Deno
Deno can be installed on your machine by running the following command in your terminal:
curl -fsSL https://deno.land/x/install/install.sh | sh
This will download and install the latest version of Deno on your machine. You can verify the installation by running the following command:
deno -v
Installing TypeScript
TypeScript can be installed on your machine using npm...
npm install -g typescript
... or yarn
yarn global add typescript
This will download and install the latest version of TypeScript on your machine. You can verify the installation by running the following command:
tsc -v
Installing Denon
A neat trick with Deno is that can run remote modules without needing them to be installed first. So it is up to you wether or not you should install Denon. If you nonetheless wish to install Denon as a global module, it can be done by running the following command in your terminal:
deno install --unstable --allow-read --allow-write --allow-run https://deno.land/x/denon/denon.ts
Set up
Setting up the project
First, let's create a new directory for our project and navigate into it:
mkdir pokemon-api
cd pokemon-api
Setting up Denon
Denon uses a denon.json
for it's settings and scripts. In order to avoid having to deal with Deno permissions at runtime when using Denon, we will create a denon.json
file containing the following settings:
{
"scripts": {
"start": "deno run --allow-env --allow-net server.ts"
}
}
Next, we'll create a new file called server.ts
and open it in your text editor of choice. This will be the entry point for our API.
Importing dependencies
In the first few lines of server.ts
, we import the dependencies we need for our project:
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
This line imports the Application
and Router
classes from the Oak library, which we will use them to set up our server and routing.
Creating the server
Next, let's create a new instance of the Application
class and set up our server:
const app = new Application();
const PORT = 3000;
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.headers.get("X-Response-Time");
console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
});
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.response.headers.set("X-Response-Time", `${ms}ms`); });
app.use(async (ctx) => { ctx.response.body = "Hello World!"; });
console.log(`Server running on port ${PORT}`);
await app.listen({ port: PORT });
This sets up an instance of the Application
class in a variable named app
, and sets the listening port to 3000. Additionally, we have added two middleware functions. One to log the response time, another that sets the response time in headers. This sets up a basic "Hello World" route for our server, which returns the string "Hello World!" when you visit the root URL of the server.
If you have chosen not to install Denon, you can run this file using this command:
deno run --allow-read --allow-write --allow-run https://deno.land/x/denon/denon.ts start
If you have installed Denon, you can simply use that command:
denon start
Now, if you visit http://localhost:3000/
in your web browser, you should see the "Hello World!" message.
Retrieving a list of Pokemons
Let's add a route for retrieving a list of Pokemons from the PokeAPI. In the server.ts
file, add the following code:
router.get("/pokemons", async (ctx) => {
const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=151`);
const data = await res.json();
ctx.response.body = data;
});
This creates a new route for the URL pattern /pokemons
. When this route is accessed, the code inside the callback function is executed.
The callback function makes a GET
request to the PokeAPI, retrieving the first generation's 151 original Pokemons. After that, the response JSON is parsed and returned to the user as the response body.
Retrieving Pokemon data
Now that we have our basic server set up, we can add a route for retrieving Pokemon data by name. In the server.ts
file, add the following code:
router.get("/pokemon/:name", async (ctx) => {
const pokemonName = ctx.params.name;
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`);
const data = await res.json();
ctx.response.body = data;
});
This creates a new route for the URL pattern /pokemon/:name
. When this route is accessed, the code inside the callback function is executed.
The callback function uses the name
parameter from the URL to make a GET
request to the PokeAPI, retrieving the pokemon data for the name
specified by the user in the url. After that, the response JSON is parsed and returned to the user as the response body.
Then we tell our app to use the routes and allowed methods defined by our router.
Now, if you visit http://localhost:3000/pokemon/pikachu
in your web browser, you should see information about Pikachu in JSON format.
Result
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
const PORT = 3000;
const router = new Router();
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.headers.get("X-Response-Time");
console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
});
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.response.headers.set("X-Response-Time", `${ms}ms`);
});
router.get("/", async (ctx) => {
ctx.response.body = "Hello World!";
})
router.get("/pokemons", async (ctx) => {
const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=151`);
const data = await res.json();
ctx.response.body = data;
});
router.get("/pokemon/:name", async (ctx) => {
const pokemonName = ctx.params.name;
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`);
const data = await res.json();
ctx.response.body = data;
});
app.use(router.routes());
app.use(router.allowedMethods());
console.log(`Server running on port ${PORT}`);
await app.listen({ port: PORT });
Conclusion
That's it! You now have a basic JSON REST Pokemon API up and running using Deno, TypeScript, and the PokeAPI. This API can be further enhanced with more routes and functionalities to fit your use-case. To go further, you could also add more error handling, caching, and rate limiting for better performance and security.
I hope this guide has been helpful in getting you started with creating your own API using Deno. Happy coding!
Become the Very Best, Like No One Ever Was: Create Your Own Pokemon API with TypeScript & Deno was initially published on Saturday January 14 2023 on the Tech Dev Blog. For the latest up-to-date content, fresh out of the oven, visit https://techdevblog.io and subscribe to our newsletter!