Skip to content

Api round trip endpoint#121

Draft
ApilaashY wants to merge 1 commit intomainfrom
feature/round-trip-endpoint
Draft

Api round trip endpoint#121
ApilaashY wants to merge 1 commit intomainfrom
feature/round-trip-endpoint

Conversation

@ApilaashY
Copy link
Contributor

Added an API endpoint to get trip times from ids and date.

description: 'Returns stop times for origin and destination stops',
})
async getRoundTrip(@Query() query: RoundTripQueryDto) {
const targetDate = new Date(query.date);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but it seems like the logic here would be just getting any time of any bus/train that is stopped at the specified stop, regardless of direction and where it's headed.

@jliu1016
Copy link
Contributor

jliu1016 commented Dec 5, 2025

You'll want to work off of baseEntitiesV2

Comment on lines +4 to +10
const RoundTripQuerySchema = z.object({
orgStopId: z.string().min(1, 'Origin stop ID is required'),
destStopId: z.string().min(1, 'Destination stop ID is required'),
date: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format'),
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should block origin and destination from being the same stop. Zod can do this with a refine/superRefine. We could also add a safer date parse/validation so we don’t accept a bad date that later becomes Invalid Date.

Comment on lines +53 to +68
return {
orgStopTimes: orgStopTimes.map((st) => ({
id: st.id,
trip_id: st.trip.trip_id,
arrival_time: st.arrivalTime as unknown as string,
departure_time: st.departureTime as unknown as string,
stop_id: st.stop.stopid,
})),
destStopTimes: destStopTimes.map((st) => ({
id: st.id,
trip_id: st.trip.trip_id,
arrival_time: st.arrivalTime as unknown as string,
departure_time: st.departureTime as unknown as string,
stop_id: st.stop.stopid,
})),
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We return two arrays and the client has to match them up. Could we instead return a list of matched trips, each with its origin/destination times, sorted by origin departure? That would make the endpoint easier to use.

Comment on lines +23 to +51
const orgStopTimes = await this.stopTimeRepository.find(
{
stop: { stopid: query.orgStopId },
trip: {
calendarDate: {
date: targetDate,
},
},
},
{
populate: ['trip', 'stop'],
orderBy: { departureTime: 'ASC' },
},
);

const destStopTimes = await this.stopTimeRepository.find(
{
stop: { stopid: query.destStopId },
trip: {
calendarDate: {
date: targetDate,
},
},
},
{
populate: ['trip', 'stop'],
orderBy: { departureTime: 'ASC' },
},
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now we fetch origin and destination stop times separately, so the client could accidentally pair different trips or the wrong direction. Could we query trips that contain both stops, ensure the origin stop_sequence is before the destination’s, and (if available) match direction/headsign? Also, we should skip trips canceled for that date (exceptionType=2).

description: 'Returns stop times for origin and destination stops',
})
async getRoundTrip(@Query() query: RoundTripQueryDto) {
const targetDate = new Date(query.date);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing the YYYY-MM-DD string with new Date() can shift the day because of timezones. Can we parse it as a plain date (e.g., split year/month/day or use a UTC parse) so it always matches the intended service date?

@jliu1016
Copy link
Contributor

jliu1016 commented Dec 7, 2025

So we don't want to be working off the GTFS service here, since that services purpose is for importing gtfs data. Since we will be interfacing with the combination of data (calling it trip schedule for now), it will be easier as an api developer to work off of a view. In mikroorm we can create entities that are virtual (which means we interact with it like we would a real object, but we don't actually create a new table). We want to return the stop time ids, and route ids to the frontend because they will need this to create an itinerary. The round trip controller should query this entity and pull the appropriate trip schedules.

import { Entity, Property, PrimaryKey, ManyToOne } from '@mikro-orm/core';

@Entity({
    expression: `
    SELECT
      t.id as "tripId",
      r.id as "routeId",
      r.route_short_name as "routeShortName",
      r.route_long_name as "routeLongName",
      st1.departure_time as "departureTime",
      st2.arrival_time as "arrivalTime",
      t.service_id as "serviceId",
      s1.stop_name as "startStopName",
      s2.stop_name as "endStopName",
      cd.date as "date",
      st1.id as "startStopTime_id",
      st2.id as "endStopTime_id"
    FROM gtfs_trips t
    JOIN gtfs_routes r ON t.route_id = r.id
    JOIN gtfs_stop_times st1 ON t.id = st1.trip_id
    JOIN gtfs_stop_times st2 ON t.id = st2.trip_id
    JOIN gtfs_stops s1 ON st1.stop_id = s1.id
    JOIN gtfs_stops s2 ON st2.stop_id = s2.id
    JOIN gtfs_calendar_dates cd ON t.service_id = cd.service_id
    WHERE st1.stop_sequence < st2.stop_sequence
      AND cd.exception_type = 1
  `,
})
export class TripSchedule {
    @Property()
    tripId!: string;

    @Property()
    routeId!: string;

    @Property()
    routeShortName!: string;

    @Property()
    routeLongName!: string;

    @Property()
    departureTime!: string;

    @Property()
    arrivalTime!: string;

    @Property()
    serviceId!: string;

    @Property()
    startStopName!: string;

    @Property()
    endStopName!: string;
 
    @Property()
    date!: string;

    @Property()
    startStopTimeId: string;

    @Property()
    endStopTimeId: string;
}

@jliu1016
Copy link
Contributor

jliu1016 commented Dec 7, 2025

Ended up opening a pr so you can use this, after my comment i realized I also needed to filter on active feeds. #123

@jliu1016
Copy link
Contributor

jliu1016 commented Dec 7, 2025

Relevant documentation: https://mikro-orm.io/docs/virtual-entities

@jliu1016 jliu1016 marked this pull request as draft December 9, 2025 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants