In this article, I’ll install the Deno runtime and create a command-line weather program that takes a city name as an argument and returns the weather forecast for the next 24 hours.

To Code for Deno, I strongly recommend using Visual Studio Code with the official Deno plug-in. To make things more interesting, we’ll write our application in TypeScript.

Install Deno

First, let’s install Deno locally so we can start scripting. This process is simple because all three operating systems have installation scripts.

Windows

On Windows, you can install Deno from PowerShell:

iwr https://deno.land/x/install/install.ps1 -useb | iex
Copy the code

Linux

On a Linux terminal, you can use the following command:

curl -fsSL https://deno.land/x/install/install.sh |  sh
Copy the code

macOS

On Mac, Brew can be installed with Deno:

brew install deno
Copy the code

After installation

After the installation process is complete, you can check that Deno is installed correctly by running the following command.

deno --version
Copy the code

You should now see something like the following:

Deno 1.2.0 V8 8.5.216 typescript 3.9.2Copy the code

Let’s create a folder for our new project (in your home folder, or wherever you like to save the code project) and add an index.ts file.

mkdir weather-app
cd weather-app
code index.ts
Copy the code

Note: As I mentioned above, I’m using VS Code in this tutorial. If you are using a different editor, replace the last line above.

Get user input

Our program retrieves the weather forecast for a given city, so we need to accept the city name as a parameter when running the program. The parameters supplied to the Deno script are in the form of deno.args. Let’s log this variable to the console to see how it works.

console.log(Deno.args);
Copy the code

Now run the script with the following command:

Deno run index.ts -- City HangzhouCopy the code

You should see the following output:

[ "--city"."Hangzhou" ]
Copy the code

Although we can parse this array of parameters ourselves, Deno’s standard library includes a module called Flags that will solve this problem for us. To use it, all we need to do is add an import statement at the top of the file:

import { parse } from  "https://deno.land/[email protected]/flags/mod.ts";
Copy the code

Note: The examples in the documentation of the standard library module will give you an unversioned URL(e.g. Deno.land/STD /flags/m…

Let’s use the imported function to parse the argument array into something more useful:

const args = parse(Deno.args);
Copy the code

We’ll also modify the script to print the new args variable to see what it looks like. So now your code should look like this:

import { parse } from  "https://deno.land/[email protected]/flags/mod.ts";

const args = parse(Deno.args);

console.log(args);
Copy the code

Now, if you run the script with the same parameters as before, you should see the following output:

Ts Download https://deno.land/[email protected]/_util/assert.ts Check file:///home/njacques/code/weather-app/index.ts { _: [], city:"Hangzhou" }
Copy the code

Every time Deno runs a script, it checks for a new import statement. Any remotely hosted imports will be downloaded, compiled, and cached for future use. The parse function gives us an object with a City property that contains our input.

Note: If you need to re-download and import a script for any reason, you can run deno cache –reload index.ts.

We should also add a check for the city parameter and exit the program with an error message if no city parameter is provided.

if (args.city === undefined) {
  console.error("No city supplied");
  Deno.exit();
}
Copy the code

Using the Weather API

We will obtain forecast data from tianqiapi.com. You need to sign up for a free account to get an API key. We will use their professional seven day weather interface, passing a city name as a parameter.

Let’s add some code to get the weather forecast and print it to the console to see the result:

import { parse } from  "https://deno.land/[email protected]/flags/mod.ts";

const args = parse(Deno.args);

if (args.city === undefined) {
    console.error("No city supplied");
    Deno.exit();
}

const appid = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const appsecret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

const res = await fetch(`https://yiketianqi.com/api?version=v9&appid=${appid}&appsecret=${appsecret}`);
const data = await res.json();

console.log(data);
Copy the code

Deno tries to support many browser apis where possible, so here we can use FETCH without having to import any external dependencies. We also take advantage of await support: normally, we would have to wrap all code that uses await in async functions, but TypeScript doesn’t make us do that, which makes the code better.

If you try to run this script now, you will get an error message:

Compile file:///Users/zhangbing/github/CodeTest/Deno/weather-app/index.ts
error: Uncaught PermissionDenied: network access to "https://yiketianqi.com/api?version=v9&appid=xxxxxxxx&appsecret=xxxxxxx", run again with the --allow-net flag
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at Object.sendAsync ($deno$/ops/dispatch_json.ts:98:10)
    at async fetch ($deno$/web/fetch.ts:296:27)
    at async file:///Users/zhangbing/github/CodeTest/Deno/weather-app/index.ts:13:13
Copy the code

By default, all Deno scripts run in a secure sandbox: they don’t have access to the network, the file system, or things like environment variables. Scripts need to be explicitly granted access to the system resources they need. In this case, the error message will help us understand the required permissions and how to enable it.

Let’s call the script again with the correct flag:

Deno run --allow-net index.ts --city HangzhouCopy the code

This time, we should get the JSON response back from the API:

{
  cityid: "101210101",
  city: "Hangzhou",
  cityEn: "hangzhou",
  country: "China",
  countryEn: "China",
  update_time: "The 2020-08-13 16:51:27",
  data: [
    {
      day: "Thursday the 13th",
      date: "2020-08-13",
      week: "Thursday",
      wea: "Cloudy",
      wea_img: "yun",
      wea_day: "Cloudy",
      wea_day_img: "yun",
      wea_night: "Cloudy",
      wea_night_img: "yun",
      tem: "37",
      tem1: "38",
      tem2: "28",
      humidity: "40%",
      visibility: "Vacant",
      pressure: "1002",
      win: [ "Southwest wind"."No sustained wind direction" ],
      win_speed: "Level 4-5 to < level 3",
      win_meter: "Less than 12 km/h",
      sunrise: "05:24",
      sunset: "18:43",
      air: "35",
      air_level: "Optimal",
      air_tips: "The air is so good to go outside and breathe the fresh air and embrace nature!",
      alarm: {
        alarm_type: "Hot",
        alarm_level: "Orange",
        alarm_content: Hangzhou Meteorological Observatory issued a high temperature orange warning signal at 9:05 on August 13, 2020: controlled by the subtropical high, the highest temperature is expected to reach about 38℃ in the main urban area and Qiantang New Area today. Please pay attention to the work of heat prevention and cooling. (Source: National Early Warning Information Release Center)}, hours: [ [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object], [Object] ], index: [ [Object], [Object], [Object], [Object], [Object], [Object] ] }, ... . ] }Copy the code

The meaning of the returned fields can be viewed in the API documentation. The data array is a list of daily data, 1-7 days, 7 groups. Each object contains weather warning (Alarm), hour forecast (Hours), life index (Index), and air quality Index (AQI) data.

For the sake of simplicity, we only get a few simple data: date, weather, real-time temperature, air quality level four data, to go through the number of sets:

const forecast = data.data.map((item) = > [
  item.day, / / date
  item.wea, / / the weather
  item.tem, // Real-time temperature
  item.air_level, // Air quality level
]);
Copy the code

If we try to run the script now, we get a compilation error (and if you use an IDE like VS code, you get this error when you type the code) : the argument ‘item’ implicitly has a type of ‘any’.

TypeScript requires us to tell it what type of variable item is so we know if we’re doing anything to it that could cause an error at run time. Let’s add an interface that describes the structure of item:

interface forecastItem {
  day: string;
  wea: string;
  tem: string;
  air_level: string;
}
Copy the code

Let’s add the new type to the map callback:

const forecast = data.data.map((item: forecastItem) = > [
  item.day, / / date
  item.wea, / / the weather
  item.tem, // Real-time temperature
  item.air_level, // Air quality level
]);
Copy the code

If you’re using an IDE that supports TypeScript, it should be able to type items automatically when you type, thanks to the interface type we provide.

Now run the result as follows:

forecast [
  [ "Thursday the 13th"."Cloudy to clear"."36"."Optimal" ],
  [ "Friday the 14th"."Fine"."37"."" ],
  [ "Saturday the 15th"."Fine"."37"."" ],
  [ "Sunday the 16th"."Cloudy to clear"."37"."" ],
  [ "Monday the 17th"."Fine"."37"."" ],
  [ "Tuesday the 18th"."Fine"."37"."" ],
  [ "Wednesday the 19th."."Fine"."38".""]]Copy the code

Formatted output

Now that we have the data set we need, let’s look at how to format it for display to the user. Let’s use the ascii_TABLE module to display it in a neat little table:

import AsciiTable from 'https://deno.land/x/ascii_table/mod.ts'; .const table = AsciiTable.fromJSON({
  title: `${args.city}Seven days weather forecast.heading: [ 'date'.'the weather'.'Real-time temperature'.'the wind'.'Air Quality'.'Weather Warning'].rows: forecast
})

console.log(table.toString())
Copy the code

Save and run the script, and we should now have the selected cities formatted and forecast for the next 7 days:

Complete code list

This is a compact script, but here’s the full code listing, also available on Github.

import { parse } from "https://deno.land/[email protected]/flags/mod.ts";
import AsciiTable from "https://deno.land/x/ascii_table/mod.ts";

const args = parse(Deno.args);

if (args.city === undefined) {
  console.error("No city supplied");
  Deno.exit();
}

// Your own API key
const appid = "xxxxxxxx";
const apiKey = "xxxxxxxxx";

const res = await fetch(
  `https://yiketianqi.com/api?version=v9&appid=${appid}&appsecret=${apiKey}`,);const data = await res.json();

interface forecastItem {
  day: string;
  wea: string;
  tem: string;
  air_level: string;
}

const forecast = data.data.map((item: forecastItem) = > [
  item.day, / / date
  item.wea, / / the weather
  item.tem, // Real-time temperature
  item.air_level, // Air quality level
]);

const table = AsciiTable.fromJSON({
  title: `${args.city}Seven days weather forecast.heading: ["Date"."The weather"."Temperature"."Air Quality"].rows: forecast,
});

console.log(table.toString());
Copy the code

conclusion

You now have your own running Deno command line program that will give you the weather forecast for the next 7 days. By following this tutorial, you should now be familiar with how to launch new programs, import dependencies from standard libraries and third parties, and grant script permissions.

So, after getting a taste of Deno programming, where should you go next? What do you think of Deno?