This project provides an HTTP REST API for business lookup, built with an Express.js server using TypeScript. The API enables users to lookup for businesses, filter by type, limit, and sort them by proximity to specified coordinate (latitude and longitude).
Table of Contents (click to expand)
Please ensure that you have Node.js 20 and pnpm installed for local development. Alternatively, you can use Docker to run the application in a containerized environment using the included compose file, which eliminates the need for local Node.js and pnpm installations.
-
Clone the repository
git clone https://github.com/askmrsinh/business-lookup business-lookup cd business-lookup
-
Install dependencies:
pnpm install
Run migrations and seed the database:
npx mikro-orm migration:fresh && npx mikro-orm seeder:run
To run the application in development mode (watch mode):
pnpm start:dev
The server will be available at http://localhost:3000
.
Lists all businesses with optional sorting, limiting, and filtering.
Parameter | Type | Description | Default |
---|---|---|---|
lat | number | Latitude for distance calculation | 0 |
long | number | Longitude for distance calculation | 0 |
limit | integer | Maximum number of results to return (-1 for all) | -1 |
type | string | Filter businesses by type (eg. Cafe) |
The response is an array of business objects, each containing:
name
: Name of the businesslatitude
: Latitude coordinate of the businesslongitude
: Longitude coordinate of the businessdistance
: Distance from the provided coordinates (default from 0,0)
Note
The distance calculation (in kilometers) is performed using the spherical law of cosines formula at the database level. Sorting, limiting, and filtering are also handled at the database level for optimal performance.
-
Get all businesses (sorted by nearest to 0,0, default):
GET /discovery
[ { "name": "Business 4", "latitude": 48.8566, "longitude": 2.3522, "distance": 5437.294595456117 }, { "name": "Business 3", "latitude": 51.5074, "longitude": -0.1278, "distance": 5727.37416793213 }, { "name": "Business 6", "latitude": 51.5074, "longitude": -0.1278, "distance": 5727.37416793213 }, { "name": "Business 1", "latitude": 40.7128, "longitude": -74.006, "distance": 8667.068154202436 }, { "name": "Business 5", "latitude": 41.8781, "longitude": -87.6298, "distance": 9811.334640548625 }, { "name": "Business 2", "latitude": 34.0522, "longitude": -118.2437, "distance": 12574.353209790605 } ]
-
Get businesses near a specific location, sorted by distance:
GET /discovery?lat=40.7128&long=-74.0060
[ { "name": "Business 1", "latitude": 40.7128, "longitude": -74.006, "distance": 0 }, { "name": "Business 5", "latitude": 41.8781, "longitude": -87.6298, "distance": 1144.291273946347 }, { "name": "Business 2", "latitude": 34.0522, "longitude": -118.2437, "distance": 3935.746254609723 }, { "name": "Business 3", "latitude": 51.5074, "longitude": -0.1278, "distance": 5570.222179737958 }, { "name": "Business 6", "latitude": 51.5074, "longitude": -0.1278, "distance": 5570.222179737958 }, { "name": "Business 4", "latitude": 48.8566, "longitude": 2.3522, "distance": 5837.24090382584 } ]
-
Get three businesses near a specific location, sorted by distance:
GET /discovery?lat=40.7128&long=-74.0060&limit=3
[ { "name": "Business 1", "latitude": 40.7128, "longitude": -74.006, "distance": 0 }, { "name": "Business 5", "latitude": 41.8781, "longitude": -87.6298, "distance": 1144.291273946347 }, { "name": "Business 2", "latitude": 34.0522, "longitude": -118.2437, "distance": 3935.746254609723 } ]
-
Get the closest cafe to a specific location:
GET /discovery?lat=40.7128&long=-74.0060&limit=1&type=Cafe
[ { "name": "Business 1", "latitude": 40.7128, "longitude": -74.006, "distance": 0 } ]
- Invalid query parameters will result in a 400 Bad Request response with details about the error.
- Valid latitude ranges from -90 to 90.
- Valid longitude ranges from -180 to 180.
- Limit can be any non-negative integer or -1 (for all results).
Example:
GET /discovery?lat=invalid8&long=9000&limit=-42.42
{
"message": "Invalid request.",
"error": {
"lat": [
"lat must be a number",
"lat must be a valid earth latitude",
"lat must not be less than -90",
"lat must not be greater than 90"
],
"long": ["long must be a valid earth longitude", "long must not be greater than 180"],
"limit": ["limit must be an integer number", "limit must not be less than -1"]
}
}
pnpm start
: Initializes the Database and start the application in production modepnpm start:dev
: Start the application in development (watch) modepnpm start:prod
: Start the application in production modepnpm test
: Run testspnpm lint
: Check code style with Prettier and ESLintpnpm format
: Format code with Prettier
- Express.js
- TypeScript
- MikroORM
- SQLite
- class-validator (for request validation)
- class-transformer (for request deserialization)
- Pino (for logging)
- Jest (for testing)
The project uses a typical Express.js structure with TypeScript. Key files and directories include:
server.ts
: Main application fileapp/
: Contains application logiccontrollers/
: API route handlersentities/
: Database entity definitionsseeders/
: Database seedersdtos/
: Request deserialization and validation
The project includes comprehensive tests for the /discovery
API endpoint. Run the tests using:
pnpm test