chore: added api mocking

This commit is contained in:
2025-01-27 02:31:08 +01:00
parent 48e8129902
commit f19a256153
9 changed files with 164 additions and 55 deletions
+6
View File
@@ -11,6 +11,8 @@ node_modules
dist dist
dist-ssr dist-ssr
*.local *.local
.env
.env.*
# Editor directories and files # Editor directories and files
.vscode/* .vscode/*
@@ -22,3 +24,7 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
# api-mock
/api-mock/endpoints/
/api-mock/*.lock
+33
View File
@@ -0,0 +1,33 @@
import { existsSync } from 'fs';
import { mkdir, writeFile } from 'fs/promises';
async function fetchJSONEndpointData(url, fileName) {
try {
const res = await fetch(url);
const data = await res.json();
await writeFile(`./endpoints/${fileName}`, JSON.stringify(data));
return true;
} catch (error) {
console.error(error);
}
return false;
}
async function main() {
if (!existsSync('endpoints')) await mkdir('endpoints');
Promise.all(
['getActiveData', 'getDonators', 'getSceneries', 'getVehicles'].map((endpointName) =>
fetchJSONEndpointData(
`https://stacjownik.spythere.eu/api/${endpointName}`,
`${endpointName}.json`
)
)
).then(() => {
console.log('Endpoints downloaded!');
});
}
main();
+28
View File
@@ -0,0 +1,28 @@
import express from 'express';
import path from 'path';
import { cwd } from 'process';
import cors from 'cors';
const app = express();
app.use(cors());
app.get('/api/getActiveData', (_, res) => {
res.sendFile(path.join(cwd(), 'endpoints', 'getActiveData.json'));
});
app.get('/api/getSceneries', (_, res) => {
res.sendFile(path.join(cwd(), 'endpoints', 'getSceneries.json'));
});
app.get('/api/getVehicles', (_, res) => {
res.sendFile(path.join(cwd(), 'endpoints', 'getVehicles.json'));
});
app.get('/api/getDonators', (_, res) => {
res.sendFile(path.join(cwd(), 'endpoints', 'getDonators.json'));
});
app.listen(3123, () => {
console.log('Mocking API server...');
});
+18
View File
@@ -0,0 +1,18 @@
{
"name": "api-mock",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js",
"fetch": "node fetchEndpoints.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.3"
}
}
+3 -1
View File
@@ -4,7 +4,9 @@
"version": "0.1.1", "version": "0.1.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite --mode staging",
"dev:mock": "vite --mode development & yarn --cwd ./api-mock start",
"mock:setup": "cd ./api-mock && yarn && yarn fetch",
"build": "vue-tsc -b && vite build", "build": "vue-tsc -b && vite build",
"preview": "vite preview" "preview": "vite preview"
}, },
+8 -9
View File
@@ -238,13 +238,13 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useGlobalStore } from './stores/global.store';
import sceneryCorrections from './data/corrections.json'; import sceneryCorrections from './data/corrections.json';
import type { ActiveTrain } from './types/common.types'; import type { ActiveTrain } from './types/common.types';
import { version } from '../package.json'; import { version } from '../package.json';
import { PrinterIcon, ArrowPathIcon } from '@heroicons/vue/16/solid'; import { PrinterIcon, ArrowPathIcon } from '@heroicons/vue/16/solid';
import { useApiStore } from './stores/api.store';
interface StopRow { interface StopRow {
pointName: string; pointName: string;
@@ -281,7 +281,7 @@ export default defineComponent({
components: { PrinterIcon, ArrowPathIcon }, components: { PrinterIcon, ArrowPathIcon },
data: () => ({ data: () => ({
selectedTrainId: '', selectedTrainId: '',
globalStore: useGlobalStore(), apiStore: useApiStore(),
selectedTrain: null as ActiveTrain | null, selectedTrain: null as ActiveTrain | null,
generatedMs: 0, generatedMs: 0,
@@ -290,12 +290,12 @@ export default defineComponent({
}), }),
mounted() { mounted() {
this.globalStore.setupData(); this.apiStore.setupAPIData();
}, },
methods: { methods: {
selectTrain() { selectTrain() {
if (!this.globalStore.activeData) return; if (!this.apiStore.activeData) return;
this.selectedTrain = this.activeTimetableTrains.find((train) => train.id == this.selectedTrainId) ?? null; this.selectedTrain = this.activeTimetableTrains.find((train) => train.id == this.selectedTrainId) ?? null;
@@ -307,17 +307,16 @@ export default defineComponent({
}, },
refreshData() { refreshData() {
this.apiStore.fetchActiveData();
this.selectTrain(); this.selectTrain();
}, },
}, },
computed: { computed: {
activeTimetableTrains() { activeTimetableTrains() {
if (!this.globalStore.activeData) return []; if (!this.apiStore.activeData) return [];
return this.globalStore.activeData.trains return this.apiStore.activeData.trains.filter((train) => train.timetable).sort((t1, t2) => t1.driverName.localeCompare(t2.driverName, 'pl-PL'));
.filter((train) => train.timetable)
.sort((t1, t2) => t1.driverName.localeCompare(t2.driverName, 'pl-PL'));
}, },
computedTimetable() { computedTimetable() {
@@ -343,7 +342,7 @@ export default defineComponent({
const [arrivalLine, scenery, departureLine] = pathEl.split(','); const [arrivalLine, scenery, departureLine] = pathEl.split(',');
const sceneryName = scenery.split(' ').slice(0, -1).join(' '); const sceneryName = scenery.split(' ').slice(0, -1).join(' ');
const sceneryData = this.globalStore.sceneryData?.find((sc) => sc.name == sceneryName) ?? null; const sceneryData = this.apiStore.sceneryData?.find((sc) => sc.name == sceneryName) ?? null;
const arrivalLineData = arrivalLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == arrivalLine) ?? null : null; const arrivalLineData = arrivalLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == arrivalLine) ?? null : null;
const departureLineData = departureLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == departureLine) ?? null : null; const departureLineData = departureLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == departureLine) ?? null : null;
+66
View File
@@ -0,0 +1,66 @@
import type { AxiosInstance } from 'axios';
import axios from 'axios';
import { defineStore } from 'pinia';
import type { ActiveDataResponse, SceneriesDataResponse } from '../types/api.types';
import type { ActiveData, SceneryData } from '../types/common.types';
export const useApiStore = defineStore('api', {
state() {
return {
client: null as AxiosInstance | null,
activeData: null as ActiveData | null,
sceneryData: null as SceneryData[] | null,
};
},
actions: {
async setupAPIData() {
if (this.client != null) return;
let baseURL = 'https://stacjownik.spythere.eu';
switch (import.meta.env.VITE_API_MODE) {
case 'development':
baseURL = 'http://localhost:3001';
break;
case 'mocking':
baseURL = 'http://localhost:3123';
break;
default:
break;
}
this.client = axios.create({
baseURL,
});
this.fetchSceneriesData();
this.fetchActiveData();
setInterval(() => {
this.fetchActiveData();
}, 20000);
},
async fetchActiveData() {
try {
const response = (await this.client!.get<ActiveDataResponse>('/api/getActiveData')).data;
this.activeData = response;
} catch (error) {
console.error(error);
}
},
async fetchSceneriesData() {
try {
const response = (await this.client!.get<SceneriesDataResponse>('/api/getSceneries')).data;
this.sceneryData = response;
} catch (error) {
console.error(error);
}
},
},
});
+2 -37
View File
@@ -1,42 +1,7 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import httpClient from '../utils/http';
import type { ActiveDataResponse, SceneriesDataResponse } from '../types/api.types';
import type { ActiveData, SceneryData } from '../types/common.types';
export const useGlobalStore = defineStore('global', { export const useGlobalStore = defineStore('global', {
state: () => ({ state: () => ({}),
activeData: null as ActiveData | null,
sceneryData: null as SceneryData[] | null,
}),
getters: {}, getters: {},
actions: { actions: {},
async _fetchActiveData() {
try {
const response = (await httpClient.get<ActiveDataResponse>('/api/getActiveData')).data;
this.activeData = response;
} catch (error) {
console.error(error);
}
},
async _fetchSceneriesData() {
try {
const response = (await httpClient.get<SceneriesDataResponse>('/api/getSceneries')).data;
this.sceneryData = response;
} catch (error) {
console.error(error);
}
},
setupData() {
this._fetchActiveData();
this._fetchSceneriesData();
setInterval(() => {
this._fetchActiveData();
}, 20000);
},
},
}); });
-8
View File
@@ -1,8 +0,0 @@
import axios from 'axios';
const httpClient = axios.create({
baseURL: 'https://stacjownik.spythere.eu',
timeout: 3000,
});
export default httpClient;