feat: adding openapi spect generation to the frontend client aas well as to fast api. Broke API out into different routes
This commit is contained in:
11
justfile
11
justfile
@@ -7,4 +7,13 @@
|
||||
|
||||
# Setup project
|
||||
@run:
|
||||
poetry run uvicorn server:app --reload --port 8000
|
||||
poetry run python main.py
|
||||
|
||||
|
||||
# Lint project with ruff linter
|
||||
@lint:
|
||||
poetry run ruff .
|
||||
|
||||
# Auto fix lint with ruff
|
||||
@lint-fix:
|
||||
poetry run ruff . --fix
|
||||
|
||||
29
main.py
Normal file
29
main.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import json
|
||||
import logging
|
||||
import uvicorn
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
from mta_sign_server.router import router as default_router
|
||||
from mta_sign_server.mta.router import router as mta_router
|
||||
from mta_sign_server.config.router import router as config_router
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI()
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=['*']
|
||||
)
|
||||
|
||||
app.include_router(default_router)
|
||||
app.include_router(mta_router)
|
||||
app.include_router(config_router)
|
||||
|
||||
logger = logging.getLogger("main")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info", reload=True)
|
||||
2
mta-sign-ui/.gitignore
vendored
2
mta-sign-ui/.gitignore
vendored
@@ -33,3 +33,5 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.yarn
|
||||
|
||||
878
mta-sign-ui/.pnp.cjs
generated
878
mta-sign-ui/.pnp.cjs
generated
File diff suppressed because it is too large
Load Diff
@@ -1,34 +1,11 @@
|
||||
import Image from 'next/image'
|
||||
import TitleBar from "@/components/header";
|
||||
import Header from "@/components/header";
|
||||
import Station from "@/components/trains/station";
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between">
|
||||
<TitleBar></TitleBar>
|
||||
|
||||
{/*<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">*/}
|
||||
{/* <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">*/}
|
||||
{/* Get started by editing */}
|
||||
{/* <code className="font-mono font-bold">app/page.tsx</code>*/}
|
||||
{/* </p>*/}
|
||||
{/* <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">*/}
|
||||
{/* <a*/}
|
||||
{/* className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"*/}
|
||||
{/* href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"*/}
|
||||
{/* target="_blank"*/}
|
||||
{/* rel="noopener noreferrer"*/}
|
||||
{/* >*/}
|
||||
{/* By{' '}*/}
|
||||
{/* <Image*/}
|
||||
{/* src="/vercel.svg"*/}
|
||||
{/* alt="Vercel Logo"*/}
|
||||
{/* className="dark:invert"*/}
|
||||
{/* width={100}*/}
|
||||
{/* height={24}*/}
|
||||
{/* priority*/}
|
||||
{/* />*/}
|
||||
{/* </a>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
<Header></Header>
|
||||
<Station></Station>
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px]">
|
||||
<Image
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {fetchStartDate} from "@/services/mta-api/mta-server";
|
||||
import {MtaStartTime} from "@/services/mta-api/types";
|
||||
import Image from 'next/image';
|
||||
|
||||
const TitleBar = () => {
|
||||
const Header = () => {
|
||||
const [data, setData] = useState<MtaStartTime | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -13,7 +14,6 @@ const TitleBar = () => {
|
||||
console.log("CALLING API")
|
||||
const mtaData = await fetchStartDate([""])
|
||||
setData(mtaData)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
@@ -53,4 +53,4 @@ const TitleBar = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default TitleBar;
|
||||
export default Header;
|
||||
0
mta-sign-ui/components/trains/depot.tsx
Normal file
0
mta-sign-ui/components/trains/depot.tsx
Normal file
32
mta-sign-ui/components/trains/line.tsx
Normal file
32
mta-sign-ui/components/trains/line.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
'use client'
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {fetchStartDate} from "@/services/mta-api/mta-server";
|
||||
import {MtaStartTime} from "@/services/mta-api/types";
|
||||
import Image from 'next/image';
|
||||
|
||||
const Line = () => {
|
||||
// const [data, setData] = useState<MtaStartTime | null>(null);
|
||||
|
||||
// useEffect(() => {
|
||||
// const fetchData = async () => {
|
||||
// try {
|
||||
// console.log("CALLING API")
|
||||
// const mtaData = await fetchStartDate([""])
|
||||
// setData(mtaData)
|
||||
//
|
||||
// } catch (error) {
|
||||
// console.error('Error fetching data:', error);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// fetchData();
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<div className="align-middle lg:flex w-full">
|
||||
TRAIN LINE HERE
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Line;
|
||||
43
mta-sign-ui/components/trains/station.tsx
Normal file
43
mta-sign-ui/components/trains/station.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
'use client'
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {fetchStationData} from "@/services/mta-api/mta-server";
|
||||
import {MtaData,} from "@/services/mta-api/types";
|
||||
|
||||
const Station = () => {
|
||||
const [data, setData] = useState<MtaData | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
console.log("CALLING API")
|
||||
const mtaData = await fetchStationData([""])
|
||||
setData(mtaData)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="align-middle lg:flex w-full">
|
||||
<div className="lg:flex-grow"></div>
|
||||
<div className="lg:text-right text-center lg:p-2">
|
||||
|
||||
{data ? (
|
||||
<h2 className="text-lg lg:text-xl font-bold dark:text-white">Train Line <span>{data.mtaData.toLocaleString()}</span></h2>
|
||||
|
||||
) : (
|
||||
<p>Loading data...</p>
|
||||
)}
|
||||
|
||||
<h2 className="text-lg lg:text-xl font-bold dark:text-white">Updated
|
||||
At: <span>{new Date().toLocaleString("en-US")}</span></h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Station;
|
||||
@@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
||||
@@ -0,0 +1,13 @@
|
||||
apis/ConfigApi.ts
|
||||
apis/MtaDataApi.ts
|
||||
apis/StartApi.ts
|
||||
apis/index.ts
|
||||
index.ts
|
||||
models/AllStationModel.ts
|
||||
models/HTTPValidationError.ts
|
||||
models/Route.ts
|
||||
models/RouteResponse.ts
|
||||
models/StationResponse.ts
|
||||
models/ValidationError.ts
|
||||
models/index.ts
|
||||
runtime.ts
|
||||
@@ -0,0 +1 @@
|
||||
6.6.0
|
||||
53
mta-sign-ui/gen-sources/mta-sign-api/apis/ConfigApi.ts
Normal file
53
mta-sign-ui/gen-sources/mta-sign-api/apis/ConfigApi.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import * as runtime from '../runtime';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export class ConfigApi extends runtime.BaseAPI {
|
||||
|
||||
/**
|
||||
* Get All
|
||||
*/
|
||||
async getAllApiConfigGetRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<any>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/config`,
|
||||
method: 'GET',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
if (this.isJsonMime(response.headers.get('content-type'))) {
|
||||
return new runtime.JSONApiResponse<any>(response);
|
||||
} else {
|
||||
return new runtime.TextApiResponse(response) as any;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get All
|
||||
*/
|
||||
async getAllApiConfigGet(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<any> {
|
||||
const response = await this.getAllApiConfigGetRaw(initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
}
|
||||
141
mta-sign-ui/gen-sources/mta-sign-api/apis/MtaDataApi.ts
Normal file
141
mta-sign-ui/gen-sources/mta-sign-api/apis/MtaDataApi.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import * as runtime from '../runtime';
|
||||
import type {
|
||||
AllStationModel,
|
||||
HTTPValidationError,
|
||||
Route,
|
||||
RouteResponse,
|
||||
StationResponse,
|
||||
} from '../models';
|
||||
import {
|
||||
AllStationModelFromJSON,
|
||||
AllStationModelToJSON,
|
||||
HTTPValidationErrorFromJSON,
|
||||
HTTPValidationErrorToJSON,
|
||||
RouteFromJSON,
|
||||
RouteToJSON,
|
||||
RouteResponseFromJSON,
|
||||
RouteResponseToJSON,
|
||||
StationResponseFromJSON,
|
||||
StationResponseToJSON,
|
||||
} from '../models';
|
||||
|
||||
export interface GetRouteApiMtaStopIdRoutePostRequest {
|
||||
stopId: any;
|
||||
route: Route;
|
||||
}
|
||||
|
||||
export interface GetStationApiMtaStopIdPostRequest {
|
||||
stopId: any;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export class MtaDataApi extends runtime.BaseAPI {
|
||||
|
||||
/**
|
||||
* Get All
|
||||
*/
|
||||
async getAllApiMtaPostRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<AllStationModel>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/mta`,
|
||||
method: 'POST',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => AllStationModelFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get All
|
||||
*/
|
||||
async getAllApiMtaPost(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<AllStationModel> {
|
||||
const response = await this.getAllApiMtaPostRaw(initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Route
|
||||
*/
|
||||
async getRouteApiMtaStopIdRoutePostRaw(requestParameters: GetRouteApiMtaStopIdRoutePostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RouteResponse>> {
|
||||
if (requestParameters.stopId === null || requestParameters.stopId === undefined) {
|
||||
throw new runtime.RequiredError('stopId','Required parameter requestParameters.stopId was null or undefined when calling getRouteApiMtaStopIdRoutePost.');
|
||||
}
|
||||
|
||||
if (requestParameters.route === null || requestParameters.route === undefined) {
|
||||
throw new runtime.RequiredError('route','Required parameter requestParameters.route was null or undefined when calling getRouteApiMtaStopIdRoutePost.');
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/mta/{stop_id}/{route}`.replace(`{${"stop_id"}}`, encodeURIComponent(String(requestParameters.stopId))).replace(`{${"route"}}`, encodeURIComponent(String(requestParameters.route))),
|
||||
method: 'POST',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => RouteResponseFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Route
|
||||
*/
|
||||
async getRouteApiMtaStopIdRoutePost(requestParameters: GetRouteApiMtaStopIdRoutePostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RouteResponse> {
|
||||
const response = await this.getRouteApiMtaStopIdRoutePostRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Station
|
||||
*/
|
||||
async getStationApiMtaStopIdPostRaw(requestParameters: GetStationApiMtaStopIdPostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<StationResponse>> {
|
||||
if (requestParameters.stopId === null || requestParameters.stopId === undefined) {
|
||||
throw new runtime.RequiredError('stopId','Required parameter requestParameters.stopId was null or undefined when calling getStationApiMtaStopIdPost.');
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/mta/{stop_id}`.replace(`{${"stop_id"}}`, encodeURIComponent(String(requestParameters.stopId))),
|
||||
method: 'POST',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => StationResponseFromJSON(jsonValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Station
|
||||
*/
|
||||
async getStationApiMtaStopIdPost(requestParameters: GetStationApiMtaStopIdPostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<StationResponse> {
|
||||
const response = await this.getStationApiMtaStopIdPostRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
}
|
||||
53
mta-sign-ui/gen-sources/mta-sign-api/apis/StartApi.ts
Normal file
53
mta-sign-ui/gen-sources/mta-sign-api/apis/StartApi.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import * as runtime from '../runtime';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export class StartApi extends runtime.BaseAPI {
|
||||
|
||||
/**
|
||||
* Get Start Time
|
||||
*/
|
||||
async getStartTimeApiStartTimePostRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<any>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api/start_time`,
|
||||
method: 'POST',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
if (this.isJsonMime(response.headers.get('content-type'))) {
|
||||
return new runtime.JSONApiResponse<any>(response);
|
||||
} else {
|
||||
return new runtime.TextApiResponse(response) as any;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Start Time
|
||||
*/
|
||||
async getStartTimeApiStartTimePost(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<any> {
|
||||
const response = await this.getStartTimeApiStartTimePostRaw(initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
}
|
||||
5
mta-sign-ui/gen-sources/mta-sign-api/apis/index.ts
Normal file
5
mta-sign-ui/gen-sources/mta-sign-api/apis/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * from './ConfigApi';
|
||||
export * from './MtaDataApi';
|
||||
export * from './StartApi';
|
||||
5
mta-sign-ui/gen-sources/mta-sign-api/index.ts
Normal file
5
mta-sign-ui/gen-sources/mta-sign-api/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * from './runtime';
|
||||
export * from './apis';
|
||||
export * from './models';
|
||||
@@ -0,0 +1,73 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
import type { StationResponse } from './StationResponse';
|
||||
import {
|
||||
StationResponseFromJSON,
|
||||
StationResponseFromJSONTyped,
|
||||
StationResponseToJSON,
|
||||
} from './StationResponse';
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface AllStationModel
|
||||
*/
|
||||
export interface AllStationModel {
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: StationResponse; }}
|
||||
* @memberof AllStationModel
|
||||
*/
|
||||
stations: { [key: string]: StationResponse; } | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the AllStationModel interface.
|
||||
*/
|
||||
export function instanceOfAllStationModel(value: object): boolean {
|
||||
let isInstance = true;
|
||||
isInstance = isInstance && "stations" in value;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function AllStationModelFromJSON(json: any): AllStationModel {
|
||||
return AllStationModelFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function AllStationModelFromJSONTyped(json: any, ignoreDiscriminator: boolean): AllStationModel {
|
||||
if ((json === undefined) || (json === null)) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'stations': { [key: string]: StationResponse; }FromJSON(json['stations']),
|
||||
};
|
||||
}
|
||||
|
||||
export function AllStationModelToJSON(value?: AllStationModel | null): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
|
||||
'stations': { [key: string]: StationResponse; }ToJSON(value.stations),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface HTTPValidationError
|
||||
*/
|
||||
export interface HTTPValidationError {
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof HTTPValidationError
|
||||
*/
|
||||
detail?: any | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the HTTPValidationError interface.
|
||||
*/
|
||||
export function instanceOfHTTPValidationError(value: object): boolean {
|
||||
let isInstance = true;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function HTTPValidationErrorFromJSON(json: any): HTTPValidationError {
|
||||
return HTTPValidationErrorFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function HTTPValidationErrorFromJSONTyped(json: any, ignoreDiscriminator: boolean): HTTPValidationError {
|
||||
if ((json === undefined) || (json === null)) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'detail': !exists(json, 'detail') ? undefined : json['detail'],
|
||||
};
|
||||
}
|
||||
|
||||
export function HTTPValidationErrorToJSON(value?: HTTPValidationError | null): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
|
||||
'detail': value.detail,
|
||||
};
|
||||
}
|
||||
|
||||
44
mta-sign-ui/gen-sources/mta-sign-api/models/Route.ts
Normal file
44
mta-sign-ui/gen-sources/mta-sign-api/models/Route.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
/**
|
||||
* An enumeration.
|
||||
* @export
|
||||
* @interface Route
|
||||
*/
|
||||
export interface Route {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the Route interface.
|
||||
*/
|
||||
export function instanceOfRoute(value: object): boolean {
|
||||
let isInstance = true;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function RouteFromJSON(json: any): Route {
|
||||
return RouteFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function RouteFromJSONTyped(json: any, ignoreDiscriminator: boolean): Route {
|
||||
return json;
|
||||
}
|
||||
|
||||
export function RouteToJSON(value?: Route | null): any {
|
||||
return value;
|
||||
}
|
||||
|
||||
66
mta-sign-ui/gen-sources/mta-sign-api/models/RouteResponse.ts
Normal file
66
mta-sign-ui/gen-sources/mta-sign-api/models/RouteResponse.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface RouteResponse
|
||||
*/
|
||||
export interface RouteResponse {
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof RouteResponse
|
||||
*/
|
||||
arrivalTimes: any | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the RouteResponse interface.
|
||||
*/
|
||||
export function instanceOfRouteResponse(value: object): boolean {
|
||||
let isInstance = true;
|
||||
isInstance = isInstance && "arrivalTimes" in value;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function RouteResponseFromJSON(json: any): RouteResponse {
|
||||
return RouteResponseFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function RouteResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): RouteResponse {
|
||||
if ((json === undefined) || (json === null)) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'arrivalTimes': json['arrival_times'],
|
||||
};
|
||||
}
|
||||
|
||||
export function RouteResponseToJSON(value?: RouteResponse | null): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
|
||||
'arrival_times': value.arrivalTimes,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
import type { RouteResponse } from './RouteResponse';
|
||||
import {
|
||||
RouteResponseFromJSON,
|
||||
RouteResponseFromJSONTyped,
|
||||
RouteResponseToJSON,
|
||||
} from './RouteResponse';
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface StationResponse
|
||||
*/
|
||||
export interface StationResponse {
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: RouteResponse; }}
|
||||
* @memberof StationResponse
|
||||
*/
|
||||
routes: { [key: string]: RouteResponse; } | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the StationResponse interface.
|
||||
*/
|
||||
export function instanceOfStationResponse(value: object): boolean {
|
||||
let isInstance = true;
|
||||
isInstance = isInstance && "routes" in value;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function StationResponseFromJSON(json: any): StationResponse {
|
||||
return StationResponseFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function StationResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): StationResponse {
|
||||
if ((json === undefined) || (json === null)) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'routes': { [key: string]: RouteResponse; }FromJSON(json['routes']),
|
||||
};
|
||||
}
|
||||
|
||||
export function StationResponseToJSON(value?: StationResponse | null): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
|
||||
'routes': { [key: string]: RouteResponse; }ToJSON(value.routes),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { exists, mapValues } from '../runtime';
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ValidationError
|
||||
*/
|
||||
export interface ValidationError {
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof ValidationError
|
||||
*/
|
||||
loc: any | null;
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof ValidationError
|
||||
*/
|
||||
msg: any | null;
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof ValidationError
|
||||
*/
|
||||
type: any | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the ValidationError interface.
|
||||
*/
|
||||
export function instanceOfValidationError(value: object): boolean {
|
||||
let isInstance = true;
|
||||
isInstance = isInstance && "loc" in value;
|
||||
isInstance = isInstance && "msg" in value;
|
||||
isInstance = isInstance && "type" in value;
|
||||
|
||||
return isInstance;
|
||||
}
|
||||
|
||||
export function ValidationErrorFromJSON(json: any): ValidationError {
|
||||
return ValidationErrorFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ValidationErrorFromJSONTyped(json: any, ignoreDiscriminator: boolean): ValidationError {
|
||||
if ((json === undefined) || (json === null)) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'loc': json['loc'],
|
||||
'msg': json['msg'],
|
||||
'type': json['type'],
|
||||
};
|
||||
}
|
||||
|
||||
export function ValidationErrorToJSON(value?: ValidationError | null): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
|
||||
'loc': value.loc,
|
||||
'msg': value.msg,
|
||||
'type': value.type,
|
||||
};
|
||||
}
|
||||
|
||||
8
mta-sign-ui/gen-sources/mta-sign-api/models/index.ts
Normal file
8
mta-sign-ui/gen-sources/mta-sign-api/models/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * from './AllStationModel';
|
||||
export * from './HTTPValidationError';
|
||||
export * from './Route';
|
||||
export * from './RouteResponse';
|
||||
export * from './StationResponse';
|
||||
export * from './ValidationError';
|
||||
287
mta-sign-ui/gen-sources/mta-sign-api/openapi.json
Normal file
287
mta-sign-ui/gen-sources/mta-sign-api/openapi.json
Normal file
@@ -0,0 +1,287 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/start_time": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"start"
|
||||
],
|
||||
"summary": "Get Start Time",
|
||||
"operationId": "get_start_time_api_start_time_post",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/mta/{stop_id}/{route}": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"mta-data"
|
||||
],
|
||||
"summary": "Get Route",
|
||||
"operationId": "get_route_api_mta__stop_id___route__post",
|
||||
"parameters": [
|
||||
{
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Stop Id"
|
||||
},
|
||||
"name": "stop_id",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Route"
|
||||
},
|
||||
"name": "route",
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RouteResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/mta/{stop_id}": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"mta-data"
|
||||
],
|
||||
"summary": "Get Station",
|
||||
"operationId": "get_station_api_mta__stop_id__post",
|
||||
"parameters": [
|
||||
{
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Stop Id"
|
||||
},
|
||||
"name": "stop_id",
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/StationResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/mta": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"mta-data"
|
||||
],
|
||||
"summary": "Get All",
|
||||
"operationId": "get_all_api_mta_post",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AllStationModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/config": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"config"
|
||||
],
|
||||
"summary": "Get All",
|
||||
"operationId": "get_all_api_config_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"AllStationModel": {
|
||||
"properties": {
|
||||
"stations": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/StationResponse"
|
||||
},
|
||||
"type": "object",
|
||||
"title": "Stations"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"stations"
|
||||
],
|
||||
"title": "AllStationModel"
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"properties": {
|
||||
"detail": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Detail"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "HTTPValidationError"
|
||||
},
|
||||
"Route": {
|
||||
"enum": [
|
||||
"A",
|
||||
"C",
|
||||
"E",
|
||||
"B",
|
||||
"D",
|
||||
"F",
|
||||
"M",
|
||||
"G",
|
||||
"J",
|
||||
"Z",
|
||||
"N",
|
||||
"Q",
|
||||
"R",
|
||||
"W",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"L",
|
||||
"SIR"
|
||||
],
|
||||
"title": "Route",
|
||||
"description": "An enumeration."
|
||||
},
|
||||
"RouteResponse": {
|
||||
"properties": {
|
||||
"arrival_times": {
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Arrival Times"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"arrival_times"
|
||||
],
|
||||
"title": "RouteResponse"
|
||||
},
|
||||
"StationResponse": {
|
||||
"properties": {
|
||||
"routes": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/RouteResponse"
|
||||
},
|
||||
"type": "object",
|
||||
"title": "Routes"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"routes"
|
||||
],
|
||||
"title": "StationResponse"
|
||||
},
|
||||
"ValidationError": {
|
||||
"properties": {
|
||||
"loc": {
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Location"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"title": "Message"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"title": "Error Type"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"title": "ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
425
mta-sign-ui/gen-sources/mta-sign-api/runtime.ts
Normal file
425
mta-sign-ui/gen-sources/mta-sign-api/runtime.ts
Normal file
@@ -0,0 +1,425 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* FastAPI
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
|
||||
|
||||
export interface ConfigurationParameters {
|
||||
basePath?: string; // override base path
|
||||
fetchApi?: FetchAPI; // override for fetch implementation
|
||||
middleware?: Middleware[]; // middleware to apply before/after fetch requests
|
||||
queryParamsStringify?: (params: HTTPQuery) => string; // stringify function for query strings
|
||||
username?: string; // parameter for basic security
|
||||
password?: string; // parameter for basic security
|
||||
apiKey?: string | ((name: string) => string); // parameter for apiKey security
|
||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string | Promise<string>); // parameter for oauth2 security
|
||||
headers?: HTTPHeaders; //header params we want to use on every request
|
||||
credentials?: RequestCredentials; //value for the credentials param we want to use on each request
|
||||
}
|
||||
|
||||
export class Configuration {
|
||||
constructor(private configuration: ConfigurationParameters = {}) {}
|
||||
|
||||
set config(configuration: Configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
get basePath(): string {
|
||||
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
||||
}
|
||||
|
||||
get fetchApi(): FetchAPI | undefined {
|
||||
return this.configuration.fetchApi;
|
||||
}
|
||||
|
||||
get middleware(): Middleware[] {
|
||||
return this.configuration.middleware || [];
|
||||
}
|
||||
|
||||
get queryParamsStringify(): (params: HTTPQuery) => string {
|
||||
return this.configuration.queryParamsStringify || querystring;
|
||||
}
|
||||
|
||||
get username(): string | undefined {
|
||||
return this.configuration.username;
|
||||
}
|
||||
|
||||
get password(): string | undefined {
|
||||
return this.configuration.password;
|
||||
}
|
||||
|
||||
get apiKey(): ((name: string) => string) | undefined {
|
||||
const apiKey = this.configuration.apiKey;
|
||||
if (apiKey) {
|
||||
return typeof apiKey === 'function' ? apiKey : () => apiKey;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get accessToken(): ((name?: string, scopes?: string[]) => string | Promise<string>) | undefined {
|
||||
const accessToken = this.configuration.accessToken;
|
||||
if (accessToken) {
|
||||
return typeof accessToken === 'function' ? accessToken : async () => accessToken;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get headers(): HTTPHeaders | undefined {
|
||||
return this.configuration.headers;
|
||||
}
|
||||
|
||||
get credentials(): RequestCredentials | undefined {
|
||||
return this.configuration.credentials;
|
||||
}
|
||||
}
|
||||
|
||||
export const DefaultConfig = new Configuration();
|
||||
|
||||
/**
|
||||
* This is the base class for all generated API classes.
|
||||
*/
|
||||
export class BaseAPI {
|
||||
|
||||
private static readonly jsonRegex = new RegExp('^(:?application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i');
|
||||
private middleware: Middleware[];
|
||||
|
||||
constructor(protected configuration = DefaultConfig) {
|
||||
this.middleware = configuration.middleware;
|
||||
}
|
||||
|
||||
withMiddleware<T extends BaseAPI>(this: T, ...middlewares: Middleware[]) {
|
||||
const next = this.clone<T>();
|
||||
next.middleware = next.middleware.concat(...middlewares);
|
||||
return next;
|
||||
}
|
||||
|
||||
withPreMiddleware<T extends BaseAPI>(this: T, ...preMiddlewares: Array<Middleware['pre']>) {
|
||||
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
||||
return this.withMiddleware<T>(...middlewares);
|
||||
}
|
||||
|
||||
withPostMiddleware<T extends BaseAPI>(this: T, ...postMiddlewares: Array<Middleware['post']>) {
|
||||
const middlewares = postMiddlewares.map((post) => ({ post }));
|
||||
return this.withMiddleware<T>(...middlewares);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given MIME is a JSON MIME.
|
||||
* JSON MIME examples:
|
||||
* application/json
|
||||
* application/json; charset=UTF8
|
||||
* APPLICATION/JSON
|
||||
* application/vnd.company+json
|
||||
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
||||
* @return True if the given MIME is JSON, false otherwise.
|
||||
*/
|
||||
protected isJsonMime(mime: string | null | undefined): boolean {
|
||||
if (!mime) {
|
||||
return false;
|
||||
}
|
||||
return BaseAPI.jsonRegex.test(mime);
|
||||
}
|
||||
|
||||
protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise<Response> {
|
||||
const { url, init } = await this.createFetchParams(context, initOverrides);
|
||||
const response = await this.fetchApi(url, init);
|
||||
if (response && (response.status >= 200 && response.status < 300)) {
|
||||
return response;
|
||||
}
|
||||
throw new ResponseError(response, 'Response returned an error code');
|
||||
}
|
||||
|
||||
private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) {
|
||||
let url = this.configuration.basePath + context.path;
|
||||
if (context.query !== undefined && Object.keys(context.query).length !== 0) {
|
||||
// only add the querystring to the URL if there are query parameters.
|
||||
// this is done to avoid urls ending with a "?" character which buggy webservers
|
||||
// do not handle correctly sometimes.
|
||||
url += '?' + this.configuration.queryParamsStringify(context.query);
|
||||
}
|
||||
|
||||
const headers = Object.assign({}, this.configuration.headers, context.headers);
|
||||
Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {});
|
||||
|
||||
const initOverrideFn =
|
||||
typeof initOverrides === "function"
|
||||
? initOverrides
|
||||
: async () => initOverrides;
|
||||
|
||||
const initParams = {
|
||||
method: context.method,
|
||||
headers,
|
||||
body: context.body,
|
||||
credentials: this.configuration.credentials,
|
||||
};
|
||||
|
||||
const overriddenInit: RequestInit = {
|
||||
...initParams,
|
||||
...(await initOverrideFn({
|
||||
init: initParams,
|
||||
context,
|
||||
}))
|
||||
};
|
||||
|
||||
const init: RequestInit = {
|
||||
...overriddenInit,
|
||||
body:
|
||||
isFormData(overriddenInit.body) ||
|
||||
overriddenInit.body instanceof URLSearchParams ||
|
||||
isBlob(overriddenInit.body)
|
||||
? overriddenInit.body
|
||||
: JSON.stringify(overriddenInit.body),
|
||||
};
|
||||
|
||||
return { url, init };
|
||||
}
|
||||
|
||||
private fetchApi = async (url: string, init: RequestInit) => {
|
||||
let fetchParams = { url, init };
|
||||
for (const middleware of this.middleware) {
|
||||
if (middleware.pre) {
|
||||
fetchParams = await middleware.pre({
|
||||
fetch: this.fetchApi,
|
||||
...fetchParams,
|
||||
}) || fetchParams;
|
||||
}
|
||||
}
|
||||
let response: Response | undefined = undefined;
|
||||
try {
|
||||
response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);
|
||||
} catch (e) {
|
||||
for (const middleware of this.middleware) {
|
||||
if (middleware.onError) {
|
||||
response = await middleware.onError({
|
||||
fetch: this.fetchApi,
|
||||
url: fetchParams.url,
|
||||
init: fetchParams.init,
|
||||
error: e,
|
||||
response: response ? response.clone() : undefined,
|
||||
}) || response;
|
||||
}
|
||||
}
|
||||
if (response === undefined) {
|
||||
if (e instanceof Error) {
|
||||
throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const middleware of this.middleware) {
|
||||
if (middleware.post) {
|
||||
response = await middleware.post({
|
||||
fetch: this.fetchApi,
|
||||
url: fetchParams.url,
|
||||
init: fetchParams.init,
|
||||
response: response.clone(),
|
||||
}) || response;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow clone of `this` by constructing a new instance
|
||||
* and then shallow cloning data members.
|
||||
*/
|
||||
private clone<T extends BaseAPI>(this: T): T {
|
||||
const constructor = this.constructor as any;
|
||||
const next = new constructor(this.configuration);
|
||||
next.middleware = this.middleware.slice();
|
||||
return next;
|
||||
}
|
||||
};
|
||||
|
||||
function isBlob(value: any): value is Blob {
|
||||
return typeof Blob !== 'undefined' && value instanceof Blob;
|
||||
}
|
||||
|
||||
function isFormData(value: any): value is FormData {
|
||||
return typeof FormData !== "undefined" && value instanceof FormData;
|
||||
}
|
||||
|
||||
export class ResponseError extends Error {
|
||||
override name: "ResponseError" = "ResponseError";
|
||||
constructor(public response: Response, msg?: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export class FetchError extends Error {
|
||||
override name: "FetchError" = "FetchError";
|
||||
constructor(public cause: Error, msg?: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export class RequiredError extends Error {
|
||||
override name: "RequiredError" = "RequiredError";
|
||||
constructor(public field: string, msg?: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export const COLLECTION_FORMATS = {
|
||||
csv: ",",
|
||||
ssv: " ",
|
||||
tsv: "\t",
|
||||
pipes: "|",
|
||||
};
|
||||
|
||||
export type FetchAPI = WindowOrWorkerGlobalScope['fetch'];
|
||||
|
||||
export type Json = any;
|
||||
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
||||
export type HTTPHeaders = { [key: string]: string };
|
||||
export type HTTPQuery = { [key: string]: string | number | null | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery };
|
||||
export type HTTPBody = Json | FormData | URLSearchParams;
|
||||
export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody };
|
||||
export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original';
|
||||
|
||||
export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise<RequestInit>
|
||||
|
||||
export interface FetchParams {
|
||||
url: string;
|
||||
init: RequestInit;
|
||||
}
|
||||
|
||||
export interface RequestOpts {
|
||||
path: string;
|
||||
method: HTTPMethod;
|
||||
headers: HTTPHeaders;
|
||||
query?: HTTPQuery;
|
||||
body?: HTTPBody;
|
||||
}
|
||||
|
||||
export function exists(json: any, key: string) {
|
||||
const value = json[key];
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
export function querystring(params: HTTPQuery, prefix: string = ''): string {
|
||||
return Object.keys(params)
|
||||
.map(key => querystringSingleKey(key, params[key], prefix))
|
||||
.filter(part => part.length > 0)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery, keyPrefix: string = ''): string {
|
||||
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
||||
if (value instanceof Array) {
|
||||
const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue)))
|
||||
.join(`&${encodeURIComponent(fullKey)}=`);
|
||||
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
const valueAsArray = Array.from(value);
|
||||
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
||||
}
|
||||
if (value instanceof Object) {
|
||||
return querystring(value as HTTPQuery, fullKey);
|
||||
}
|
||||
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
||||
}
|
||||
|
||||
export function mapValues(data: any, fn: (item: any) => any) {
|
||||
return Object.keys(data).reduce(
|
||||
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
export function canConsumeForm(consumes: Consume[]): boolean {
|
||||
for (const consume of consumes) {
|
||||
if ('multipart/form-data' === consume.contentType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export interface Consume {
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
export interface RequestContext {
|
||||
fetch: FetchAPI;
|
||||
url: string;
|
||||
init: RequestInit;
|
||||
}
|
||||
|
||||
export interface ResponseContext {
|
||||
fetch: FetchAPI;
|
||||
url: string;
|
||||
init: RequestInit;
|
||||
response: Response;
|
||||
}
|
||||
|
||||
export interface ErrorContext {
|
||||
fetch: FetchAPI;
|
||||
url: string;
|
||||
init: RequestInit;
|
||||
error: unknown;
|
||||
response?: Response;
|
||||
}
|
||||
|
||||
export interface Middleware {
|
||||
pre?(context: RequestContext): Promise<FetchParams | void>;
|
||||
post?(context: ResponseContext): Promise<Response | void>;
|
||||
onError?(context: ErrorContext): Promise<Response | void>;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
raw: Response;
|
||||
value(): Promise<T>;
|
||||
}
|
||||
|
||||
export interface ResponseTransformer<T> {
|
||||
(json: any): T;
|
||||
}
|
||||
|
||||
export class JSONApiResponse<T> {
|
||||
constructor(public raw: Response, private transformer: ResponseTransformer<T> = (jsonValue: any) => jsonValue) {}
|
||||
|
||||
async value(): Promise<T> {
|
||||
return this.transformer(await this.raw.json());
|
||||
}
|
||||
}
|
||||
|
||||
export class VoidApiResponse {
|
||||
constructor(public raw: Response) {}
|
||||
|
||||
async value(): Promise<void> {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class BlobApiResponse {
|
||||
constructor(public raw: Response) {}
|
||||
|
||||
async value(): Promise<Blob> {
|
||||
return await this.raw.blob();
|
||||
};
|
||||
}
|
||||
|
||||
export class TextApiResponse {
|
||||
constructor(public raw: Response) {}
|
||||
|
||||
async value(): Promise<string> {
|
||||
return await this.raw.text();
|
||||
};
|
||||
}
|
||||
15
mta-sign-ui/openapitools.json
Normal file
15
mta-sign-ui/openapitools.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "6.6.0",
|
||||
"generators": {
|
||||
"mta-sign-api": {
|
||||
"generatorName": "typescript-fetch",
|
||||
"output": "#{cwd}/gen-sources/mta-sign-api/",
|
||||
"glob": "gen-sources/mta-sign-api/openapi.{json,yaml}",
|
||||
"additionalProperties": "supportsES6=true,typescriptThreePlus=true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,8 @@
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"gen-apis": "curl localhost:8000/openapi.json -O --output-dir ./gen-sources/mta-sign-api && openapi-generator-cli generate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "20.4.1",
|
||||
@@ -23,5 +24,8 @@
|
||||
"tailwindcss": "3.3.2",
|
||||
"typescript": "5.1.6"
|
||||
},
|
||||
"packageManager": "yarn@3.6.1"
|
||||
"packageManager": "yarn@3.6.1",
|
||||
"devDependencies": {
|
||||
"@openapitools/openapi-generator-cli": "^2.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {MtaData, MtaStartTime} from "@/services/mta-api/types";
|
||||
|
||||
export const fetchStationData = async (stations: [string]): Promise<MtaData> => {
|
||||
const res = await fetch("/api/mta_data", {method: "POST"})
|
||||
const res = await fetch("/api/mta", {method: "POST"})
|
||||
const data = await res.json()
|
||||
return {
|
||||
mtaData: data
|
||||
|
||||
@@ -3,7 +3,7 @@ module.exports = {
|
||||
content: [
|
||||
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./mta_sign_server/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,50 @@
|
||||
import requests
|
||||
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from .train import Train
|
||||
from .feed import Feed, ALL_FEEDS
|
||||
from .route import Route
|
||||
|
||||
|
||||
class MTA(object):
|
||||
def __init__(self, api_key: str, feeds: [Feed] = ALL_FEEDS, stations: [str] = [],
|
||||
max_arrival_time: int = 30):
|
||||
self.header = {
|
||||
"x-api-key": api_key
|
||||
}
|
||||
self.feeds = feeds
|
||||
self.stations = stations
|
||||
self.max_arrival_time = max_arrival_time
|
||||
self.trains: [Train] = []
|
||||
|
||||
def stop_updates(self):
|
||||
self.is_running = False
|
||||
|
||||
def update_trains(self) -> [Train]:
|
||||
trains = []
|
||||
for feed in self.feeds:
|
||||
r = requests.get(feed.value, headers=self.header)
|
||||
feed = gtfs_realtime_pb2.FeedMessage()
|
||||
feed.ParseFromString(r.content)
|
||||
trains.extend([train for train in [Train(train) for train in feed.entity] if
|
||||
train.has_trips()])
|
||||
self.trains = trains
|
||||
return trains
|
||||
|
||||
def get_trains(self) -> [Train]:
|
||||
return self.trains
|
||||
|
||||
def get_arrival_times(self, route: Route, station: str) -> [int]:
|
||||
arrival_times = []
|
||||
for train in self.trains:
|
||||
if train.get_route() is route:
|
||||
arrival = train.get_arrival_at(station)
|
||||
if arrival is not None and arrival < self.max_arrival_time and arrival > 0:
|
||||
arrival_times.append(arrival)
|
||||
return sorted(arrival_times)
|
||||
|
||||
def add_station_id(self, station_id: str):
|
||||
self.stations.append(station_id)
|
||||
|
||||
def remove_station_id(self, station_id: str):
|
||||
self.stations.remove(station_id)
|
||||
import requests
|
||||
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from .train import Train
|
||||
from .feed import Feed, ALL_FEEDS
|
||||
from .route import Route
|
||||
|
||||
|
||||
class MTA(object):
|
||||
def __init__(self, api_key: str, feeds: [Feed] = ALL_FEEDS, stations: [str] = [],
|
||||
max_arrival_time: int = 30):
|
||||
self.header = {
|
||||
"x-api-key": api_key
|
||||
}
|
||||
self.feeds = feeds
|
||||
self.stations = stations
|
||||
self.max_arrival_time = max_arrival_time
|
||||
self.trains: [Train] = []
|
||||
|
||||
def stop_updates(self):
|
||||
self.is_running = False
|
||||
|
||||
def update_trains(self) -> [Train]:
|
||||
trains = []
|
||||
for feed in self.feeds:
|
||||
r = requests.get(feed.value, headers=self.header)
|
||||
feed = gtfs_realtime_pb2.FeedMessage()
|
||||
feed.ParseFromString(r.content)
|
||||
trains.extend([train for train in [Train(train) for train in feed.entity] if
|
||||
train.has_trips()])
|
||||
self.trains = trains
|
||||
return trains
|
||||
|
||||
def get_trains(self) -> [Train]:
|
||||
return self.trains
|
||||
|
||||
def get_arrival_times(self, route: Route, station: str) -> [int]:
|
||||
arrival_times = []
|
||||
for train in self.trains:
|
||||
if train.get_route() is route:
|
||||
arrival = train.get_arrival_at(station)
|
||||
if arrival is not None and arrival < self.max_arrival_time and arrival > 0:
|
||||
arrival_times.append(arrival)
|
||||
return sorted(arrival_times)
|
||||
|
||||
def add_station_id(self, station_id: str):
|
||||
self.stations.append(station_id)
|
||||
|
||||
def remove_station_id(self, station_id: str):
|
||||
self.stations.remove(station_id)
|
||||
@@ -1,7 +1,7 @@
|
||||
from datetime import datetime
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from math import trunc
|
||||
|
||||
|
||||
def trip_arrival_in_minutes(stop_time_update: gtfs_realtime_pb2.TripUpdate):
|
||||
return trunc(((datetime.fromtimestamp(stop_time_update.arrival.time) - datetime.now()).total_seconds()) / 60)
|
||||
from datetime import datetime
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from math import trunc
|
||||
|
||||
|
||||
def trip_arrival_in_minutes(stop_time_update: gtfs_realtime_pb2.TripUpdate):
|
||||
return trunc(((datetime.fromtimestamp(stop_time_update.arrival.time) - datetime.now()).total_seconds()) / 60)
|
||||
@@ -1,33 +1,33 @@
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from .stop import trip_arrival_in_minutes
|
||||
from .route import Route, is_valid_route
|
||||
|
||||
|
||||
class Train(object):
|
||||
def __init__(self, train_proto: gtfs_realtime_pb2.FeedEntity):
|
||||
self.train_proto: gtfs_realtime_pb2.FeedEntity = train_proto
|
||||
|
||||
def get_arrival_at(self, stop_id) -> int | None:
|
||||
"""
|
||||
returns the routes stop time at a given stop ID in minutes
|
||||
if not found, returns None
|
||||
:param stop_id: stop ID of arrival station
|
||||
:return: arrival time in minutes
|
||||
"""
|
||||
for stop_time_update in self.train_proto.trip_update.stop_time_update:
|
||||
if stop_time_update.stop_id == stop_id:
|
||||
return trip_arrival_in_minutes(stop_time_update)
|
||||
return None
|
||||
|
||||
def _get_route(self) -> str:
|
||||
return self.train_proto.trip_update.trip.route_id
|
||||
|
||||
def get_route(self) -> Route:
|
||||
return Route(self.train_proto.trip_update.trip.route_id)
|
||||
|
||||
def has_trips(self) -> bool:
|
||||
return self.train_proto.trip_update is not None \
|
||||
and len(self.train_proto.trip_update.stop_time_update) > 0 and is_valid_route(self._get_route())
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.train_proto}"
|
||||
from google.transit import gtfs_realtime_pb2
|
||||
from .stop import trip_arrival_in_minutes
|
||||
from .route import Route, is_valid_route
|
||||
|
||||
|
||||
class Train(object):
|
||||
def __init__(self, train_proto: gtfs_realtime_pb2.FeedEntity):
|
||||
self.train_proto: gtfs_realtime_pb2.FeedEntity = train_proto
|
||||
|
||||
def get_arrival_at(self, stop_id) -> int | None:
|
||||
"""
|
||||
returns the routes stop time at a given stop ID in minutes
|
||||
if not found, returns None
|
||||
:param stop_id: stop ID of arrival station
|
||||
:return: arrival time in minutes
|
||||
"""
|
||||
for stop_time_update in self.train_proto.trip_update.stop_time_update:
|
||||
if stop_time_update.stop_id == stop_id:
|
||||
return trip_arrival_in_minutes(stop_time_update)
|
||||
return None
|
||||
|
||||
def _get_route(self) -> str:
|
||||
return self.train_proto.trip_update.trip.route_id
|
||||
|
||||
def get_route(self) -> Route:
|
||||
return Route(self.train_proto.trip_update.trip.route_id)
|
||||
|
||||
def has_trips(self) -> bool:
|
||||
return self.train_proto.trip_update is not None \
|
||||
and len(self.train_proto.trip_update.stop_time_update) > 0 and is_valid_route(self._get_route())
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.train_proto}"
|
||||
0
mta_sign_server/__init__.py
Normal file
0
mta_sign_server/__init__.py
Normal file
0
mta_sign_server/config/__init__.py
Normal file
0
mta_sign_server/config/__init__.py
Normal file
15
mta_sign_server/config/router.py
Normal file
15
mta_sign_server/config/router.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
router = APIRouter(
|
||||
tags=["config"],
|
||||
)
|
||||
|
||||
logger = logging.getLogger("config_router")
|
||||
|
||||
|
||||
@router.get("/api/config")
|
||||
def get_all():
|
||||
return JSONResponse({"config": "goes here"})
|
||||
0
mta_sign_server/mta/__init__.py
Normal file
0
mta_sign_server/mta/__init__.py
Normal file
68
mta_sign_server/mta/router.py
Normal file
68
mta_sign_server/mta/router.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi_utils.tasks import repeat_every
|
||||
from starlette import status
|
||||
|
||||
from mta_api_client import Route, MTA, Feed
|
||||
from mta_sign_server.mta.schemas import StationResponse, RouteResponse, AllStationModel
|
||||
|
||||
router = APIRouter(
|
||||
tags=["mta-data"],
|
||||
)
|
||||
|
||||
logger = logging.getLogger("mta")
|
||||
|
||||
api_key = os.getenv('MTA_API_KEY', '')
|
||||
|
||||
mtaController = MTA(
|
||||
api_key,
|
||||
feeds=[Feed.ACE, Feed.N1234567]
|
||||
)
|
||||
|
||||
ROUTES = [Route.A, Route.C, Route.E, Route.N1, Route.N2, Route.N3]
|
||||
STATION_STOP_IDs = ["127S", "127N", "A27N", "A27S"]
|
||||
|
||||
|
||||
@router.post("/api/mta/{stop_id}/{route}", response_model=RouteResponse, status_code=status.HTTP_200_OK)
|
||||
def get_route(stop_id: str, route: Route):
|
||||
arrival_times = mtaController.get_arrival_times(route, stop_id)
|
||||
if len(arrival_times) > 0:
|
||||
return RouteResponse(arrival_times=arrival_times)
|
||||
raise HTTPException(status_code=404, detail="no stops found for route and stop id")
|
||||
|
||||
|
||||
@router.post("/api/mta/{stop_id}", response_model=StationResponse, status_code=status.HTTP_200_OK)
|
||||
def get_station(stop_id: str):
|
||||
routes = {}
|
||||
for route in ROUTES:
|
||||
arrival_times = mtaController.get_arrival_times(route, stop_id)
|
||||
if len(arrival_times) > 0:
|
||||
routes[route] = RouteResponse(arrival_times=arrival_times)
|
||||
if routes:
|
||||
return StationResponse(routes=routes)
|
||||
raise HTTPException(status_code=404, detail="no trains or routes found for stop id")
|
||||
|
||||
|
||||
@router.post("/api/mta", response_model=AllStationModel, status_code=status.HTTP_200_OK)
|
||||
def get_all():
|
||||
print("HELLO WORLD")
|
||||
all_stations = {}
|
||||
for stop_id in STATION_STOP_IDs:
|
||||
routes = {}
|
||||
for route in ROUTES:
|
||||
arrival_times = mtaController.get_arrival_times(route, stop_id)
|
||||
if len(arrival_times) > 0:
|
||||
routes[route] = RouteResponse(arrival_times=arrival_times)
|
||||
all_stations[stop_id] = StationResponse(routes=routes)
|
||||
if all_stations:
|
||||
return AllStationModel(stations=all_stations)
|
||||
raise HTTPException(status_code=404, detail="no arriving trains found for all configured routes")
|
||||
|
||||
|
||||
@router.on_event("startup")
|
||||
@repeat_every(seconds=10)
|
||||
def update_trains():
|
||||
logger.info("UPDATING TRAINS")
|
||||
mtaController.update_trains()
|
||||
16
mta_sign_server/mta/schemas.py
Normal file
16
mta_sign_server/mta/schemas.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
|
||||
from mta_api_client import Route
|
||||
|
||||
|
||||
class RouteResponse(BaseModel):
|
||||
arrival_times: List[int]
|
||||
|
||||
|
||||
class StationResponse(BaseModel):
|
||||
routes: Dict[Route, RouteResponse]
|
||||
|
||||
|
||||
class AllStationModel(BaseModel):
|
||||
stations: Dict[str, StationResponse]
|
||||
12
mta_sign_server/router.py
Normal file
12
mta_sign_server/router.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, status
|
||||
|
||||
router = APIRouter(
|
||||
tags=["start"],
|
||||
)
|
||||
|
||||
start_time = datetime.now()
|
||||
@router.post("/api/start_time", status_code=status.HTTP_200_OK)
|
||||
def get_start_time():
|
||||
return start_time.isoformat()
|
||||
63
server.py
63
server.py
@@ -1,63 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from datetime import datetime
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi_utils.tasks import repeat_every
|
||||
|
||||
|
||||
# import pandas as pd
|
||||
from dotenv import load_dotenv
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from mta_manager import MTA, Feed, Route
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
api_key = os.getenv('MTA_API_KEY', '')
|
||||
|
||||
app = FastAPI()
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=['*']
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__) # the __name__ resolve to "main" since we are at the root of the project.
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
last_updated = datetime.now()
|
||||
|
||||
mtaController = MTA(
|
||||
api_key,
|
||||
feeds=[Feed.ACE, Feed.N1234567]
|
||||
)
|
||||
|
||||
ROUTES = [Route.A, Route.C, Route.E, Route.N1, Route.N2, Route.N3]
|
||||
STATION_STOP_IDs = ["127S", "127N", "A27N", "A27S"]
|
||||
|
||||
|
||||
@app.post("/api/start_time")
|
||||
def get_start_time():
|
||||
return start_time.isoformat()
|
||||
|
||||
@app.post("/api/mta_data")
|
||||
async def get_mta_data():
|
||||
# if len(mtaController.trains) == 0:
|
||||
# _ = update_trains()
|
||||
arrival_by_station_and_route = {}
|
||||
for stop_id in STATION_STOP_IDs:
|
||||
arrival_by_station_and_route[stop_id] = {}
|
||||
for route in ROUTES:
|
||||
arrival_times = mtaController.get_arrival_times(route, stop_id)
|
||||
if len(arrival_times) > 0:
|
||||
arrival_by_station_and_route[stop_id][route.value] = arrival_times
|
||||
return JSONResponse(arrival_by_station_and_route)
|
||||
|
||||
@app.on_event("startup")
|
||||
@repeat_every(seconds=5)
|
||||
async def update_trains():
|
||||
logger.info("UPDATING TRAINS")
|
||||
mtaController.update_trains()
|
||||
Reference in New Issue
Block a user