1- import express , {
2- Express ,
3- Request ,
4- Response ,
5- NextFunction ,
6- RequestHandler ,
7- } from "express" ;
1+ import { Hono } from "hono" ;
2+ import { cors } from "hono/cors" ;
83import { ALL_PLACES } from "../data/geoData.js" ;
94import { getPlace , findPlace , getTimes } from "../api_src/calculator.js" ;
105import {
116 getCommonTimeRequestParameters ,
127 getParamsForPlaceSearch ,
138 isInRange ,
149} from "../api_src/util.js" ;
10+ import { getPlaceSuggestionsByText , getNearbyPlaces , getPlaceById } from "irem" ;
11+
1512import path from "path" ;
1613import { fileURLToPath } from "url" ;
1714import { dirname } from "path" ;
18- import { getPlaceSuggestionsByText , getNearbyPlaces , getPlaceById } from "irem" ;
19-
20- export const app : Express = express ( ) ;
15+ import { Context } from "hono" ;
2116
22- /** use this function like `app.use(allowOriginForAll);` for an express app
23- * Make API accessible for all clients. Not for only clients from a specific domain.
24- */
25- const allowOriginForAll : RequestHandler = (
26- _ : Request ,
27- res : Response ,
28- next : NextFunction ,
29- ) => {
30- res . setHeader ( "Access-Control-Allow-Credentials" , "true" ) ;
31- res . setHeader ( "Access-Control-Allow-Origin" , "*" ) ;
32- // another common pattern
33- // res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
34- res . setHeader (
35- "Access-Control-Allow-Methods" ,
36- "GET,OPTIONS,PATCH,DELETE,POST,PUT" ,
37- ) ;
38- res . setHeader (
39- "Access-Control-Allow-Headers" ,
40- "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" ,
41- ) ;
42- next ( ) ;
43- } ;
17+ const app = new Hono ( ) ;
4418
45- app . use ( allowOriginForAll ) ;
46- app . use ( express . static ( "public" ) ) ;
47- app . use ( logIPAdress ) ;
19+ // Middleware
20+ app . use ( "*" , cors ( ) ) ;
4821
4922app . get ( "/api/searchPlaces" , searchPlaces ) ;
50- app . get ( "/api/nearbyPlaces " , nearByPlaces ) ;
23+ app . get ( "/api/nearByPlaces " , nearByPlaces ) ;
5124app . get ( "/api/timesForGPS" , getTimesForGPS ) ;
5225app . get ( "/api/timesForPlace" , getTimesForPlace ) ;
5326app . get ( "/api/timesFromCoordinates" , getTimesFromCoordinates ) ;
@@ -71,120 +44,137 @@ app.post("/api/ip", getIPAdress);
7144
7245const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
7346// if not starting with "/api" return index.html page as response so that routes in the static page will work
74- app . get ( / ^ \/ (? ! a p i ) .* / , ( _ , res ) => {
75- res . sendFile ( path . resolve ( __dirname , ".." , "public" , "index.html" ) ) ;
47+ app . get ( "*" , async ( c ) => {
48+ const url = new URL ( c . req . url ) ;
49+ if ( ! url . pathname . startsWith ( "/api" ) ) {
50+ const fs = await import ( "fs/promises" ) ;
51+ try {
52+ const content = await fs . readFile (
53+ path . resolve ( __dirname , ".." , "public" , "index.html" ) ,
54+ "utf-8" ,
55+ ) ;
56+ return c . html ( content ) ;
57+ } catch {
58+ return c . text ( "index.html not found" , 404 ) ;
59+ }
60+ }
61+ return c . text ( "index.html not found" , 404 ) ;
7662} ) ;
7763
78- const PORT = process . env [ "PORT" ] || 3000 ;
79- export const httpServer = app . listen ( PORT ) ;
64+ // For compatibility with some localdev setups, but purely optional for Hono + Workers
65+ if (
66+ process . env [ "NODE_ENV" ] !== "production" &&
67+ ! process . env [ "Generic_Worker" ]
68+ ) {
69+ // try to serve with @hono /node-server if installed, or just log
70+ console . log (
71+ `To run locally, use 'npm run dev' which uses nodemon/tsx. For production use 'wrangler dev'` ,
72+ ) ;
73+ }
8074
8175/** get a list of countries
82- * @param { } _
83- * @param { } res
8476 */
85- function getCountries ( _ : Request , res : Response ) {
77+ function getCountries ( c : Context ) {
8678 try {
8779 const r = [ ] ;
88- for ( const c in ALL_PLACES ) {
89- r . push ( { code : ALL_PLACES [ c ] . code , name : c } ) ;
80+ for ( const place in ALL_PLACES ) {
81+ r . push ( { code : ALL_PLACES [ place ] . code , name : place } ) ;
9082 }
91- res . send ( r . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ) ;
83+ return c . json ( r . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ) ;
9284 } catch ( e ) {
9385 console . log ( "error! " , e ) ;
94- res . send ( "error: " + e ) ;
95- } finally {
96- res . send ( "error: " ) ;
86+ return c . json ( { error : String ( e ) } ) ;
9787 }
9888}
9989
100- function getRegionsOfCountry ( req : Request , res : Response ) {
101- const country = req . query [ "country" ] as string ;
90+ function getRegionsOfCountry ( c : Context ) {
91+ const country = c . req . query ( "country" ) as string ;
10292 if ( ALL_PLACES [ country ] ) {
103- res . send (
93+ return c . json (
10494 Object . keys ( ALL_PLACES [ country ] . regions ) . sort ( ( a , b ) =>
10595 a . localeCompare ( b ) ,
10696 ) ,
10797 ) ;
10898 } else {
109- res . send ( { error : "NOT FOUND!" } ) ;
99+ return c . json ( { error : "NOT FOUND!" } ) ;
110100 }
111101}
112102
113- function getCitiesOfRegion ( req : Request , res : Response ) {
114- const country = req . query [ "country" ] as string ;
115- const region = req . query [ "region" ] as string ;
103+ function getCitiesOfRegion ( c : Context ) {
104+ const country = c . req . query ( "country" ) as string ;
105+ const region = c . req . query ( "region" ) as string ;
116106 if ( ALL_PLACES [ country ] && ALL_PLACES [ country ] . regions [ region ] ) {
117- res . send (
107+ return c . json (
118108 Object . keys ( ALL_PLACES [ country ] . regions [ region ] ) . sort ( ( a , b ) =>
119109 a . localeCompare ( b ) ,
120110 ) ,
121111 ) ;
122112 } else {
123- res . send ( { error : "NOT FOUND!" } ) ;
113+ return c . json ( { error : "NOT FOUND!" } ) ;
124114 }
125115}
126116
127- function getCoordinateData ( req : Request , res : Response ) {
128- const country = req . query [ "country" ] as string ;
129- const region = req . query [ "region" ] as string ;
130- const city = req . query [ "city" ] as string ;
117+ function getCoordinateData ( c : Context ) {
118+ const country = c . req . query ( "country" ) as string ;
119+ const region = c . req . query ( "region" ) as string ;
120+ const city = c . req . query ( "city" ) as string ;
131121 const coords = getPlace ( country , region , city ) ;
132122 if ( coords ) {
133- res . send ( coords ) ;
123+ return c . json ( coords ) ;
134124 } else {
135- res . send ( { error : "NOT FOUND!" } ) ;
125+ return c . json ( { error : "NOT FOUND!" } ) ;
136126 }
137127}
138128
139129/**
140130 * DEPRECATED, use `getTimesForGPS`
141131 */
142- function getTimesFromCoordinates ( req : Request , res : Response ) {
143- const lat = Number ( req . query [ "lat" ] as string ) ;
144- const lng = Number ( req . query [ "lng" ] as string ) ;
132+ function getTimesFromCoordinates ( c : Context ) {
133+ const lat = Number ( c . req . query ( "lat" ) as string ) ;
134+ const lng = Number ( c . req . query ( "lng" ) as string ) ;
145135 const { date, days, tzOffset, calculateMethod } =
146- getCommonTimeRequestParameters ( req ) ;
136+ getCommonTimeRequestParameters ( c ) ;
147137 if (
148138 isNaN ( lat ) ||
149139 isNaN ( lng ) ||
150140 ! isInRange ( lat , - 90 , 90 ) ||
151141 ! isInRange ( lng , - 180 , 180 )
152142 ) {
153- res . send ( { error : "Invalid coordinates!" } ) ;
143+ return c . json ( { error : "Invalid coordinates!" } ) ;
154144 } else if ( days > 1000 ) {
155- res . send ( { error : "days can be maximum 1000!" } ) ;
145+ return c . json ( { error : "days can be maximum 1000!" } ) ;
156146 } else {
157147 const place = findPlace ( lat , lng ) ;
158148 const times = getTimes ( lat , lng , date , days , tzOffset , calculateMethod ) ;
159- res . send ( { place, times } ) ;
149+ return c . json ( { place, times } ) ;
160150 }
161151}
162152
163- async function getTimesForGPS ( req : Request , res : Response ) {
164- const { lat, lng, lang } = getParamsForPlaceSearch ( req ) ;
153+ async function getTimesForGPS ( c : Context ) {
154+ const { lat, lng, lang } = getParamsForPlaceSearch ( c ) ;
165155 const { date, days, tzOffset, calculateMethod } =
166- getCommonTimeRequestParameters ( req ) ;
156+ getCommonTimeRequestParameters ( c ) ;
167157 if (
168158 isNaN ( lat ) ||
169159 isNaN ( lng ) ||
170160 ! isInRange ( lat , - 90 , 90 ) ||
171161 ! isInRange ( lng , - 180 , 180 )
172162 ) {
173- res . send ( { error : "Invalid coordinates!" } ) ;
163+ return c . json ( { error : "Invalid coordinates!" } ) ;
174164 } else if ( days > 1000 ) {
175- res . send ( { error : "days can be maximum 1000!" } ) ;
165+ return c . json ( { error : "days can be maximum 1000!" } ) ;
176166 } else {
177167 const [ place ] = await getNearbyPlaces ( lat , lng , lang , 1 ) ;
178168 const times = getTimes ( lat , lng , date , days , tzOffset , calculateMethod ) ;
179- res . send ( { place, times } ) ;
169+ return c . json ( { place, times } ) ;
180170 }
181171}
182172
183- async function searchPlaces ( req : Request , res : Response ) {
184- const q = ( req . query [ "q" ] ?? "" ) as string ;
173+ async function searchPlaces ( c : Context ) {
174+ const q = ( c . req . query ( "q" ) ?? "" ) as string ;
185175 const { lat, lng, lang, resultCount, countryCode } =
186- getParamsForPlaceSearch ( req ) ;
187- res . send (
176+ getParamsForPlaceSearch ( c ) ;
177+ return c . json (
188178 await getPlaceSuggestionsByText (
189179 q ,
190180 lang ,
@@ -196,88 +186,88 @@ async function searchPlaces(req: Request, res: Response) {
196186 ) ;
197187}
198188
199- async function nearByPlaces ( req : Request , res : Response ) {
200- const { lat, lng, lang, resultCount } = getParamsForPlaceSearch ( req ) ;
201-
202- res . send ( await getNearbyPlaces ( lat , lng , lang , resultCount ) ) ;
189+ async function nearByPlaces ( c : Context ) {
190+ try {
191+ const { lat, lng, lang, resultCount } = getParamsForPlaceSearch ( c ) ;
192+ const places = await getNearbyPlaces ( lat , lng , lang , resultCount ) ;
193+ return c . json ( places ) ;
194+ } catch ( e ) {
195+ console . error ( "nearByPlaces error:" , e ) ;
196+ return c . json ( { error : String ( e ) } , 500 ) ;
197+ }
203198}
204199
205- function getPlaceData ( req : Request , res : Response ) {
206- const lat = Number ( req . query [ "lat" ] as string ) ;
207- const lng = Number ( req . query [ "lng" ] as string ) ;
200+ function getPlaceData ( c : Context ) {
201+ const lat = Number ( c . req . query ( "lat" ) as string ) ;
202+ const lng = Number ( c . req . query ( "lng" ) as string ) ;
208203 if ( lat === undefined || lng === undefined || isNaN ( lat ) || isNaN ( lng ) ) {
209- res . send ( { error : "INVALID coordinates!" } ) ;
204+ return c . json ( { error : "INVALID coordinates!" } ) ;
210205 } else {
211- res . send ( findPlace ( lat , lng ) ) ;
206+ return c . json ( findPlace ( lat , lng ) ) ;
212207 }
213208}
214209
215- async function getTimesForPlace ( req : Request , res : Response ) {
216- const placeId = Number ( req . query [ "id" ] ) ;
210+ async function getTimesForPlace ( c : Context ) {
211+ const placeId = Number ( c . req . query ( "id" ) ) ;
217212 if ( Number . isNaN ( placeId ) ) {
218- res . send ( { error : "Id should be a positive integer!" } ) ;
219- return ;
213+ return c . json ( { error : "Id should be a positive integer!" } ) ;
220214 }
221215 const { date, days, tzOffset, calculateMethod } =
222- getCommonTimeRequestParameters ( req ) ;
223- const { lang } = getParamsForPlaceSearch ( req ) ;
216+ getCommonTimeRequestParameters ( c ) ;
217+ const { lang } = getParamsForPlaceSearch ( c ) ;
224218 const place = await getPlaceById ( placeId , lang ) ;
225219
226220 if ( ! place ) {
227- res . send ( { error : "Place cannot be found!" } ) ;
221+ return c . json ( { error : "Place cannot be found!" } ) ;
228222 } else if ( days > 1000 ) {
229- res . send ( { error : "days can be maximum 1000!" } ) ;
223+ return c . json ( { error : "days can be maximum 1000!" } ) ;
230224 } else {
231225 const lat = place . latitude ;
232226 const lng = place . longitude ;
233227 const times = getTimes ( lat , lng , date , days , tzOffset , calculateMethod ) ;
234- res . send ( { place, times } ) ;
228+ return c . json ( { place, times } ) ;
235229 }
236230}
237231
238- async function placeById ( req : Request , res : Response ) {
239- const placeId = Number ( req . query [ "id" ] ) ;
232+ async function placeById ( c : Context ) {
233+ const placeId = Number ( c . req . query ( "id" ) ) ;
240234 if ( Number . isNaN ( placeId ) ) {
241- res . send ( { error : "Id should be a positive integer!" } ) ;
242- return ;
235+ return c . json ( { error : "Id should be a positive integer!" } ) ;
243236 }
244- const { lang } = getParamsForPlaceSearch ( req ) ;
237+ const { lang } = getParamsForPlaceSearch ( c ) ;
245238 const place = await getPlaceById ( placeId , lang ) ;
246239
247240 if ( ! place ) {
248- res . send ( { error : "Place cannot be found!" } ) ;
241+ return c . json ( { error : "Place cannot be found!" } ) ;
249242 } else {
250- res . send ( { ...place } ) ;
243+ return c . json ( { ...place } ) ;
251244 }
252245}
253246
254247/**
255248 * DEPRECATED, use `getTimesForPlace`
256249 */
257- function getTimesFromPlace ( req : Request , res : Response ) {
258- const country = req . query [ "country" ] as string ;
259- const region = req . query [ "region" ] as string ;
260- const city = req . query [ "city" ] as string ;
250+ function getTimesFromPlace ( c : Context ) {
251+ const country = c . req . query ( "country" ) as string ;
252+ const region = c . req . query ( "region" ) as string ;
253+ const city = c . req . query ( "city" ) as string ;
261254 const place = getPlace ( country , region , city ) ;
262255 const { date, days, tzOffset, calculateMethod } =
263- getCommonTimeRequestParameters ( req ) ;
256+ getCommonTimeRequestParameters ( c ) ;
264257 if ( ! place ) {
265- res . send ( { error : "Place cannot be found!" } ) ;
258+ return c . json ( { error : "Place cannot be found!" } ) ;
266259 } else if ( days > 1000 ) {
267- res . send ( { error : "days can be maximum 1000!" } ) ;
260+ return c . json ( { error : "days can be maximum 1000!" } ) ;
268261 } else {
269262 const lat = place . latitude ;
270263 const lng = place . longitude ;
271264 const times = getTimes ( lat , lng , date , days , tzOffset , calculateMethod ) ;
272- res . send ( { place, times } ) ;
265+ return c . json ( { place, times } ) ;
273266 }
274267}
275268
276- function getIPAdress ( req : Request , res : Response ) {
277- res . send ( { IP : req . headers [ "x-forwarded-for" ] } ) ;
269+ function getIPAdress ( c : Context ) {
270+ return c . json ( { IP : c . req . header ( "x-forwarded-for" ) } ) ;
278271}
279272
280- function logIPAdress ( _req : Request , _ : Response , next : NextFunction ) {
281- next ( ) ;
282- }
283273export default app ;
0 commit comments