Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generic wrapper for JSON APIs #70

Draft
wants to merge 36 commits into
base: staging
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
759758a
add fetchData
ExampleWasTaken Jun 25, 2024
c15b315
add vatsim-event endpoint types
ExampleWasTaken Jun 25, 2024
211579d
add util type guards
ExampleWasTaken Jun 25, 2024
684ca62
migrate vatsim events to the new api wrapper
ExampleWasTaken Jun 25, 2024
7ab2383
add vatsim data endpoint types
ExampleWasTaken Jun 25, 2024
bd67559
add zod library
ExampleWasTaken Jul 1, 2024
bd0b412
partial vatsim port to zod
ExampleWasTaken Jul 1, 2024
0f7ec61
migrate vatsim observer to zod
ExampleWasTaken Jul 2, 2024
992c700
add missing flight plan type export
ExampleWasTaken Jul 2, 2024
81b9045
migrate vatsim pilot to zod
ExampleWasTaken Jul 2, 2024
7b37d6e
migrate vatsim stats to zod
ExampleWasTaken Jul 2, 2024
7062fc0
fix lint in vatsim
ExampleWasTaken Jul 2, 2024
5e2a3b7
migrate vatsimEvents
ExampleWasTaken Jul 2, 2024
33e3219
improve var naming
ExampleWasTaken Jul 2, 2024
7a0c89b
refactor fetchData
ExampleWasTaken Jul 2, 2024
31c2ea3
remove any ewww
ExampleWasTaken Jul 2, 2024
540557a
migrate taf cmd to zod
ExampleWasTaken Jul 3, 2024
0bffea0
migrate metar cmd to zod
ExampleWasTaken Jul 3, 2024
5c1299b
add disclaimer comments to taf and metar schemas
ExampleWasTaken Jul 3, 2024
f24dd5c
migrate simbrief cmd to zod
ExampleWasTaken Jul 3, 2024
50d08dc
migrate wolfram alpha cmd to zod
ExampleWasTaken Jul 3, 2024
0044d3c
fix zod error being thrown incorrectly while fetching data
ExampleWasTaken Jul 3, 2024
d1a8704
add folder structure to zod schema directory
ExampleWasTaken Jul 3, 2024
c841fea
migrate station cmd to zod
ExampleWasTaken Jul 4, 2024
698074e
migrate live-flight cmd to zod
ExampleWasTaken Jul 4, 2024
eae9c22
rename fetchData to fetchForeignAPI
ExampleWasTaken Jul 4, 2024
03adb0d
improve fetchForeignAPI zod error logging
ExampleWasTaken Jul 4, 2024
c01ad7a
allow string and url when fetching from foreign apis
ExampleWasTaken Jul 4, 2024
6647032
use string instead of request object for foreign apis
ExampleWasTaken Jul 4, 2024
0b2de9e
add changelog
ExampleWasTaken Jul 28, 2024
a5b363e
self review
ExampleWasTaken Jul 4, 2024
aa84fa9
update simbrief zod schema
ExampleWasTaken Aug 8, 2024
7e46e6b
remove console
ExampleWasTaken Aug 26, 2024
e4eca0d
Merge branch 'staging' into feat/generic-api-wrapper
ExampleWasTaken Oct 27, 2024
256b6db
update changelog
ExampleWasTaken Oct 27, 2024
777c5b6
Merge branch 'staging' into feat/generic-api-wrapper
ExampleWasTaken Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
migrate metar cmd to zod
ExampleWasTaken committed Aug 8, 2024

Verified

This commit was signed with the committer’s verified signature.
ExampleWasTaken ExampleWasTaken
commit 0bffea0a5cffd67303ee29b463be75a91611b8d4
93 changes: 45 additions & 48 deletions src/commands/utils/metar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js';
import fetch from 'node-fetch';
import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, makeLines, Logger } from '../../lib';
import { Request } from 'node-fetch';
import { ZodError } from 'zod';
import { constantsConfig, fetchData, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';
import { Metar, MetarSchema } from '../../lib/apis/zodSchemas/metarSchemas';

const data = slashCommandStructure({
name: 'metar',
@@ -16,6 +18,12 @@ const data = slashCommandStructure({
}],
});

const errorEmbed = (error: string) => makeEmbed({
title: 'METAR Error',
description: error,
color: Colors.Red,
});

export default slashCommand(data, async ({ interaction }) => {
await interaction.deferReply();

@@ -32,55 +40,44 @@ export default slashCommand(data, async ({ interaction }) => {
return interaction.editReply({ embeds: [noTokenEmbed] });
}

let metar: Metar;
try {
const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, {
metar = await fetchData<Metar>(new Request(`https://avwx.rest/api/metar/${icao}`, {
method: 'GET',
headers: { Authorization: metarToken },
})
.then((res) => res.json());

if (metarReport.error) {
const invalidEmbed = makeEmbed({
title: `Metar Error | ${icao.toUpperCase()}`,
description: metarReport.error,
color: Colors.Red,
});
return interaction.editReply({ embeds: [invalidEmbed] });
}
const metarEmbed = makeEmbed({
title: `METAR Report | ${metarReport.station}`,
description: makeLines([
'**Raw Report**',
metarReport.raw,
'',
'**Basic Report:**',
`**Time Observed:** ${metarReport.time.dt}`,
`**Station:** ${metarReport.station}`,
`**Wind:** ${metarReport.wind_direction.repr}${metarReport.wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${metarReport.wind_speed.repr} ${metarReport.units.wind_speed}`,
`**Visibility:** ${metarReport.visibility.repr} ${Number.isNaN(+metarReport.visibility.repr) ? '' : metarReport.units.visibility}`,
`**Temperature:** ${metarReport.temperature.repr} ${constantsConfig.units.CELSIUS}`,
`**Dew Point:** ${metarReport.dewpoint.repr} ${constantsConfig.units.CELSIUS}`,
`**Altimeter:** ${metarReport.altimeter.value.toString()} ${metarReport.units.altimeter}`,
`**Flight Rules:** ${metarReport.flight_rules}`,
]),
fields: [
{
name: 'Unsure of how to read the raw report?',
value: 'Please refer to our guide [here.](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/)',
inline: false,
},
],
footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' },
});

return interaction.editReply({ embeds: [metarEmbed] });
}), MetarSchema);
} catch (e) {
Logger.error('metar:', e);
const fetchErrorEmbed = makeEmbed({
title: 'Metar Error | Fetch Error',
description: 'There was an error fetching the METAR report. Please try again later.',
color: Colors.Red,
});
return interaction.editReply({ embeds: [fetchErrorEmbed] });
if (e instanceof ZodError) {
return interaction.editReply({ embeds: [errorEmbed('The API returned unknown data.')] });
}
return interaction.editReply({ embeds: [errorEmbed(`An error occurred while fetching the latest METAR for ${icao.toUpperCase()}.`)] });
}

const metarEmbed = makeEmbed({
title: `METAR Report | ${metar.station}`,
description: makeLines([
'**Raw Report**',
metar.raw,
'',
'**Basic Report:**',
`**Time Observed:** ${metar.time.dt}`,
`**Station:** ${metar.station}`,
`**Wind:** ${metar.wind_direction.repr}${metar.wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${metar.wind_speed.repr} ${metar.units.wind_speed}`,
`**Visibility:** ${metar.visibility.repr} ${Number.isNaN(+metar.visibility.repr) ? '' : metar.units.visibility}`,
`**Temperature:** ${metar.temperature.repr} ${constantsConfig.units.CELSIUS}`,
`**Dew Point:** ${metar.dewpoint.repr} ${constantsConfig.units.CELSIUS}`,
`**Altimeter:** ${metar.altimeter.value.toString()} ${metar.units.altimeter}`,
`**Flight Rules:** ${metar.flight_rules}`,
]),
fields: [
{
name: 'Unsure of how to read the raw report?',
value: 'Please refer to our guide [here](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/).',
inline: false,
},
],
footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' },
});

return interaction.editReply({ embeds: [metarEmbed] });
});
48 changes: 19 additions & 29 deletions src/commands/utils/taf.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js';
import { Request } from 'node-fetch';
import { ZodError } from 'zod';
import { Logger, TAF, TafSchema, fetchData, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';
import { TAF, TafSchema, fetchData, makeEmbed, makeLines, slashCommand, slashCommandStructure } from '../../lib';

const data = slashCommandStructure({
name: 'taf',
@@ -62,33 +62,23 @@ export default slashCommand(data, async ({ interaction }) => {
return interaction.editReply({ embeds: [errorEmbed(`An error occurred while fetching the latest TAF for ${icao.toUpperCase()}.`)] });
}

try {
const tafEmbed = makeEmbed({
title: `TAF Report | ${taf.station}`,
description: makeLines(['**Raw Report**', ...taf.forecast.map((forecast, i) => {
if (i === 0) {
return `${taf.station} ${forecast.raw}`;
}
return forecast.raw;
})]),
fields: [
{
name: 'Unsure of how to read the report?',
value: `Please refer to our guide [here](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/#taf-example-decoded) or see above report decoded [here](https://e6bx.com/weather/${taf.station}/?showDecoded=1&focuspoint=tafdecoder).`,
inline: false,
},
],
footer: { text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.' },
});
const tafEmbed = makeEmbed({
title: `TAF Report | ${taf.station}`,
description: makeLines(['**Raw Report**', ...taf.forecast.map((forecast, i) => {
if (i === 0) {
return `${taf.station} ${forecast.raw}`;
}
return forecast.raw;
})]),
fields: [
{
name: 'Unsure of how to read the report?',
value: `Please refer to our guide [here](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/#taf-example-decoded) or see above report decoded [here](https://e6bx.com/weather/${taf.station}/?showDecoded=1&focuspoint=tafdecoder).`,
inline: false,
},
],
footer: { text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.' },
});

return interaction.editReply({ embeds: [tafEmbed] });
} catch (error) {
Logger.error('taf:', error);
const fetchErrorEmbed = makeEmbed({
title: 'TAF Error | Fetch Error',
description: 'There was an error fetching the TAF report. Please try again later.',
color: Colors.Red,
});
return interaction.editReply({ embeds: [fetchErrorEmbed] });
}
return interaction.editReply({ embeds: [tafEmbed] });
});
46 changes: 46 additions & 0 deletions src/lib/apis/zodSchemas/metarSchemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { z } from 'zod';

export const TimeSchema = z.object({ dt: z.string().datetime() });

export const WindDirectionSchema = z.object({ repr: z.string() });

export const WindSpeedSchema = z.object({ repr: z.string() });

export const VisibilitySchema = z.object({ repr: z.string() });

export const TemperatureSchema = z.object({ repr: z.string() });

export const DewpointSchema = z.object({ repr: z.string() });

export const AltimeterSchema = z.object({ value: z.number() });

export const UnitsSchema = z.object({
accumulation: z.string(),
altimeter: z.string(),
altitude: z.string(),
temperature: z.string(),
visibility: z.string(),
wind_speed: z.string(),
});

/**
* This schema only contains currently used fields. If you wish to use other fields returned by the API add them below.
*/
export const MetarSchema = z.object({
station: z.string(),
raw: z.string(),
time: TimeSchema,
wind_direction: WindDirectionSchema,
wind_speed: WindSpeedSchema,
visibility: VisibilitySchema,
temperature: TemperatureSchema,
dewpoint: DewpointSchema,
altimeter: AltimeterSchema,
flight_rules: z.string(),
units: UnitsSchema,
});

/**
* This type only contains currently used fields. If you wish to use other fields returned by the API add them below.
*/
export type Metar = z.infer<typeof MetarSchema>;
1 change: 0 additions & 1 deletion src/lib/apis/zodSchemas/tafSchemas.ts
Original file line number Diff line number Diff line change
@@ -8,5 +8,4 @@ export const TafSchema = z.object({
forecast: z.array(ForecastSchema),
});

export type Forecast = z.infer<typeof ForecastSchema>;
export type TAF = z.infer<typeof TafSchema>;