Initial overpass api connections
This commit is contained in:
parent
246debe642
commit
3dd43deec0
36
apps/blakus-api/src/app/routes/blakus.ts
Normal file
36
apps/blakus-api/src/app/routes/blakus.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { OverpassService } from '../services/overpass';
|
||||
import { OverpassQuerySchema, OverpassQueryType } from '../schemas/overpass';
|
||||
|
||||
const overpassService = new OverpassService();
|
||||
|
||||
export default async function (fastify: FastifyInstance) {
|
||||
|
||||
fastify.get<{ Querystring: OverpassQueryType }>('/blakus', {
|
||||
schema: {
|
||||
querystring: OverpassQuerySchema,
|
||||
response: {
|
||||
200: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
title: { type: 'string' },
|
||||
amenity: { type: 'string' },
|
||||
tags: { type: 'object', additionalProperties: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, async function ({query}) {
|
||||
const elements = await overpassService.getAmenitiesAroundLocation({
|
||||
latlon: {
|
||||
lat: query.lat,
|
||||
lon: query.lon,
|
||||
},
|
||||
amenities: ['restaurant', 'cafe', 'bar', 'pub', 'biergarten', 'fast_food', 'food_court', 'ice_cream']
|
||||
});
|
||||
return elements;
|
||||
});
|
||||
}
|
||||
10
apps/blakus-api/src/app/schemas/overpass.ts
Normal file
10
apps/blakus-api/src/app/schemas/overpass.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Static, Type } from '@sinclair/typebox'
|
||||
|
||||
export const OverpassQuerySchema = Type.Object({
|
||||
lat: Type.Number(),
|
||||
lon: Type.Number(),
|
||||
radius: Type.Optional(Type.Number()),
|
||||
amenities: Type.Optional(Type.Array(Type.String())),
|
||||
});
|
||||
|
||||
export type OverpassQueryType = Static<typeof OverpassQuerySchema>;
|
||||
89
apps/blakus-api/src/app/services/overpass.ts
Normal file
89
apps/blakus-api/src/app/services/overpass.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
type OverpassResult = {
|
||||
version: number;
|
||||
generator: string;
|
||||
osm3s: Record<string, string>;
|
||||
elements: (NodeElement | WayElement | RelationElement)[];
|
||||
}
|
||||
|
||||
type OverpassLocation = {
|
||||
lat: number,
|
||||
lon: number
|
||||
}
|
||||
|
||||
type OverpassElement = {
|
||||
type: string;
|
||||
id: number;
|
||||
tags?: { [key: string]: string }
|
||||
};
|
||||
|
||||
type NodeElement = OverpassElement & OverpassLocation & {
|
||||
type: 'node';
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
type WayElement = OverpassElement & {
|
||||
type: 'way';
|
||||
nodes: number[];
|
||||
}
|
||||
|
||||
type RelationElement = OverpassElement & {
|
||||
type: 'relation';
|
||||
members: {
|
||||
type: 'node' | 'way' | 'relation';
|
||||
ref: number;
|
||||
role: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
function opq(strings, ...expressions) {
|
||||
let query = '[out:json];\n';
|
||||
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
query += strings[i];
|
||||
if (i < expressions.length) query += expressions[i];
|
||||
}
|
||||
|
||||
query += '\nout body;\n>;\nout skel qt;';
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
export class OverpassService {
|
||||
private axios: AxiosInstance;
|
||||
|
||||
constructor(baseURL = 'https://overpass-api.de/api/') {
|
||||
this.axios = axios.create({ baseURL });
|
||||
}
|
||||
|
||||
async getAmenitiesAroundLocation({radius = 500, amenities = [], latlon}: {radius?: number, latlon: OverpassLocation, amenities: string[]}) {
|
||||
|
||||
if (!latlon || !latlon.lat || !latlon.lon) throw new Error('Invalid location');
|
||||
|
||||
const { lat, lon } = latlon;
|
||||
|
||||
const query = opq`node(around:${radius}, ${lat}, ${lon})["amenity"~"${amenities.join('|')}"];`;
|
||||
|
||||
const result = await this.overpassQuery(query);
|
||||
|
||||
return result.elements
|
||||
.map(({ tags }) => ({ title: tags.name, amenity: tags.amenity, tags}))
|
||||
.filter(i => amenities.includes(i.amenity)); // query returns some random results. need to look into this
|
||||
}
|
||||
|
||||
async overpassQuery(query: string): Promise<OverpassResult> {
|
||||
return this.getData('interpreter', { data: query });
|
||||
}
|
||||
|
||||
async getData<T>(endpoint: string, params: Record<string, string>): Promise<T> {
|
||||
try {
|
||||
const response = await this.axios.get(endpoint, { params });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching data from ${endpoint}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user