Skip to content

Commit bb651a3

Browse files
migrate station cmd to zod
1 parent bddd7bf commit bb651a3

File tree

4 files changed

+73
-46
lines changed

4 files changed

+73
-46
lines changed

src/commands/utils/station.ts

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js';
2-
import fetch from 'node-fetch';
3-
import { slashCommand, slashCommandStructure, makeEmbed, Logger, makeLines } from '../../lib';
2+
import { Request } from 'node-fetch';
3+
import { z, ZodError } from 'zod';
4+
import { AVWXRunwaySchema, AVWXStation, AVWXStationSchema, fetchData, Logger, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';
5+
6+
type Runway = z.infer<typeof AVWXRunwaySchema>;
47

58
const data = slashCommandStructure({
69
name: 'station',
@@ -22,6 +25,12 @@ const noQueryEmbed = makeEmbed({
2225
color: Colors.Red,
2326
});
2427

28+
const errorEmbed = (error: string) => makeEmbed({
29+
title: 'Station Error',
30+
description: error,
31+
color: Colors.Red,
32+
});
33+
2534
export default slashCommand(data, async ({ interaction }) => {
2635
await interaction.deferReply();
2736

@@ -40,54 +49,44 @@ export default slashCommand(data, async ({ interaction }) => {
4049

4150
if (!icao) return interaction.editReply({ embeds: [noQueryEmbed] });
4251

52+
let station: AVWXStation;
4353
try {
44-
const stationReport: any = await fetch(`https://avwx.rest/api/station/${icao}`, {
54+
station = await fetchData<AVWXStation>(new Request(`https://avwx.rest/api/station/${icao}`, {
4555
method: 'GET',
4656
headers: { Authorization: stationToken },
47-
}).then((res) => res.json());
48-
49-
if (stationReport.error) {
50-
const invalidEmbed = makeEmbed({
51-
title: `Station Error | ${icao.toUpperCase()}`,
52-
description: stationReport.error,
53-
color: Colors.Red,
54-
});
55-
return interaction.editReply({ embeds: [invalidEmbed] });
57+
}), AVWXStationSchema);
58+
} catch (e) {
59+
if (e instanceof ZodError) {
60+
return interaction.editReply({ embeds: [errorEmbed('The API returned unknown data.')] });
5661
}
62+
Logger.error(`Error while fetching station info from AVWX: ${e}`);
63+
return interaction.editReply({ embeds: [errorEmbed(`An error occurred while fetching the station information for ${icao.toUpperCase()}.`)] });
64+
}
5765

58-
const runwayIdents = stationReport.runways.map((runways: any) => `**${runways.ident1}/${runways.ident2}:** `
59-
+ `${runways.length_ft} ft x ${runways.width_ft} ft / `
60-
+ `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`);
66+
const runwayIdents = station.runways ? station.runways.map((runways: Runway) => `**${runways.ident1}/${runways.ident2}:** `
67+
+ `${runways.length_ft} ft x ${runways.width_ft} ft / `
68+
+ `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`) : null;
6169

62-
const stationEmbed = makeEmbed({
63-
title: `Station Info | ${stationReport.icao}`,
64-
description: makeLines([
65-
'**Station Information:**',
66-
`**Name:** ${stationReport.name}`,
67-
`**Country:** ${stationReport.country}`,
68-
`**City:** ${stationReport.city}`,
69-
`**Latitude:** ${stationReport.latitude}°`,
70-
`**Longitude:** ${stationReport.longitude}°`,
71-
`**Elevation:** ${stationReport.elevation_m} m/${stationReport.elevation_ft} ft`,
72-
'',
73-
'**Runways (Ident1/Ident2: Length x Width):**',
74-
`${runwayIdents.toString().replace(/,/g, '\n')}`,
75-
'',
76-
`**Type:** ${stationReport.type.replace(/_/g, ' ')}`,
77-
`**Website:** ${stationReport.website}`,
78-
`**Wiki:** ${stationReport.wiki}`,
79-
]),
80-
footer: { text: 'Due to limitations of the API, not all links may be up to date at all times.' },
81-
});
70+
const stationEmbed = makeEmbed({
71+
title: `Station Info | ${station.icao}`,
72+
description: makeLines([
73+
'**Station Information:**',
74+
`**Name:** ${station.name}`,
75+
`**Country:** ${station.country}`,
76+
`**City:** ${station.city}`,
77+
`**Latitude:** ${station.latitude}°`,
78+
`**Longitude:** ${station.longitude}°`,
79+
`**Elevation:** ${station.elevation_m} m/${station.elevation_ft} ft`,
80+
'',
81+
'**Runways (Length x Width):**',
82+
`${runwayIdents ? runwayIdents.toString().replace(/,/g, '\n') : 'N/A'}`,
83+
'',
84+
`**Type:** ${station.type.replace(/_/g, ' ')}`,
85+
`**Website:** ${station.website ?? 'N/A'}`,
86+
`**Wiki:** ${station.wiki ?? 'N/A'}`,
87+
]),
88+
footer: { text: 'Due to limitations of the API, not all links may be up to date at all times.' },
89+
});
8290

83-
return interaction.editReply({ embeds: [stationEmbed] });
84-
} catch (error) {
85-
Logger.error('station:', error);
86-
const fetchErrorEmbed = makeEmbed({
87-
title: 'Station Error | Fetch Error',
88-
description: 'There was an error fetching the station report. Please try again later.',
89-
color: Colors.Red,
90-
});
91-
return interaction.editReply({ embeds: [fetchErrorEmbed] });
92-
}
91+
return interaction.editReply({ embeds: [stationEmbed] });
9392
});

src/commands/utils/taf.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js';
22
import { Request } from 'node-fetch';
33
import { ZodError } from 'zod';
4-
import { TAF, TafSchema, fetchData, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';
4+
import { Logger, TAF, TafSchema, fetchData, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';
55

66
const data = slashCommandStructure({
77
name: 'taf',
@@ -59,6 +59,7 @@ export default slashCommand(data, async ({ interaction }) => {
5959
if (e instanceof ZodError) {
6060
return interaction.editReply({ embeds: [errorEmbed('The API returned unknown data.')] });
6161
}
62+
Logger.error(`Error while fetching TAF from AVWX: ${e}`);
6263
return interaction.editReply({ embeds: [errorEmbed(`An error occurred while fetching the latest TAF for ${icao.toUpperCase()}.`)] });
6364
}
6465

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { z } from 'zod';
2+
3+
export const AVWXRunwaySchema = z.object({
4+
length_ft: z.number(),
5+
width_ft: z.number(),
6+
ident1: z.string(),
7+
ident2: z.string(),
8+
});
9+
10+
export const AVWXStationSchema = z.object({
11+
city: z.string(),
12+
country: z.string(),
13+
elevation_ft: z.number(),
14+
elevation_m: z.number(),
15+
icao: z.string(),
16+
latitude: z.number(),
17+
longitude: z.number(),
18+
name: z.string(),
19+
runways: z.nullable(z.array(AVWXRunwaySchema)),
20+
type: z.string(),
21+
website: z.nullable(z.string().url()),
22+
wiki: z.nullable(z.string().url()),
23+
});
24+
25+
export type AVWXStation = z.infer<typeof AVWXStationSchema>;

src/lib/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export * from './schedulerJobs/postBirthdays';
2626
export * from './apis/fetchData';
2727
export * from './apis/zodSchemas/vatsim/vatsimEventsSchemas';
2828
export * from './apis/zodSchemas/vatsim/vatsimDataSchemas';
29+
export * from './apis/zodSchemas/avwx/metarSchemas';
2930
export * from './apis/zodSchemas/avwx/tafSchemas';
31+
export * from './apis/zodSchemas/avwx/stationSchemas';
3032
export * from './apis/zodSchemas/simbrief/simbriefSchemas';
3133
export * from './apis/zodSchemas/wolframAlpha/wolframAlphaSchemas';

0 commit comments

Comments
 (0)