This is a learning project to explore REST APIs by creating one from scratch, supporting CRUD operations and authentication via tokens. The database used in the project contains information on over 140,000 cities around the world.
http://domain/v1/cities
This is the endpoint to make the requests, retrieve cities information, update or delete data. The response will be in JSON
format.
GET http://domain/v1/cities?id={city_id}
Inserting the id as a query parameter
allows to retrieve the information of the city with that specific id.
GET http://domain/v1/cities?id=1
View JSON Data
{
"data": {
"id": 1,
"name": "Beijing",
"country": "CN",
"population": 18960744,
"lat": 39.9075,
"lon": 116.39723
}
}
GET http://domain/v1/cities?city={your_city_name}
Use this URL
to retrieve the information of all the cities that share the requested name.
The search is case-insensitive.
GET http://domain/v1/cities?city=rome
View JSON Data
{
"data": [
{
"id": 150,
"name": "Rome",
"country": "IT",
"population": 2318895,
"lat": 41.89193,
"lon": 12.51133
},
{
"id": 13582,
"name": "Rome",
"country": "US",
"population": 36323,
"lat": 34.25704,
"lon": -85.16467
},
{
"id": 14954,
"name": "Rome",
"country": "US",
"population": 32573,
"lat": 43.21285,
"lon": -75.45573
},
{
"id": 77931,
"name": "Rome",
"country": "US",
"population": 2697,
"lat": 44.2206,
"lon": -89.80843
},
{
"id": 97045,
"name": "Rome",
"country": "US",
"population": 1738,
"lat": 40.88309,
"lon": -89.50259
},
{
"id": 123454,
"name": "Rome",
"country": "US",
"population": 1019,
"lat": 44.58506,
"lon": -69.86922
}
]
}
NOTE cities are ordered by population in a decreasing order.
To retrieve a specific city through its latitude and longitude.
GET http://domain/v1/cities?lat={city_latitude}&lon={city_longitude}
It suffice to pass lat
and lon
as query parameters
.
GET http://domain/v1/cities?lat=41.89193&lon=12.51133
View JSON Data
{
"data":
{
"id": 150,
"name": "Rome",
"country": "IT",
"population": 2318895,
"lat": 41.89193,
"lon": 12.51133
}
}
NOTE there can't be two cities with the same latitude or longitude.
To narrow the results, use multiple parameters.
GET http://domain/v1/cities?name=rome&country=it
View JSON Data
{
"data":
{
"id": 150,
"name": "Rome",
"country": "IT",
"population": 2318895,
"lat": 41.89193,
"lon": 12.51133
}
}
NOTE the search is case-insensitive and the results have been narrowed to one.
To run the project is required PHP 8.3 or higher and composer in order to use its autoloader and install libraries, alongside the needed extensions for PDO
, usually enabled by default.
The only used library is vlucas/dotenv a .env loader.
It is used in the config to populate $_ENV
super global with environment variables.
if (file_exists(BASE_PATH . '.env')) {
$dotenv = Dotenv\Dotenv::createImmutable(BASE_PATH);
$dotenv->load();
}
Needed libraries and their versions can be consulted in composer.json to install needed libraries run in the root directory of the project:
composer install
Create a database of the supported type (Mysql, PostgreSQL, SQLite). In the sql directory, there are schemas for different type of SQL
supported databases. It will suffice to run the chosen schema.sql script to initialize the empty tables in the database.
The token table is meant for testing authentication for CRUD operation. Sample tokens can be generated using the token generator script. Make sure to give execute permission to the script before trying to run it.
Linux/MacOS
chmod +x bin/tokengenerator
Now simply run the script with this command to generate a sample Token.
./bin/tokenGenerator
Windows
Assuming that PHP 8.2 or higher is installed in the system.
php /bin/tokenGenerator
If the database was created successfully it will suffice to run the seed script to populate the database with a sample of 100 cities.
In the .env specify the type of database to use, make sure to use PDO
dsn names for the database type such as: sqlite, mysql, pgsql, sqlsrv.
DB_TYPE=sqlite
DB_NAME=your_database.sqlite3
DB_HOST=
DB_PORT=
DB_USERNAME=
DB_PASSWORD=
in the case of a SQLite
database DB_NAME
will refer to its path, it will be joined with the root path of the project directory, so it's also possible to indicate a subdirectory.
DB_NAME=subdir/your_database.sqlite3
that's how the Database class will handle the DSN.
$dsn = "sqlite:" . BASE_PATH . $config["name"];
DB_TYPE=your_database_type # mysql/pgsql
DB_NAME=your_database_name # name of the created database
DB_HOST=localhost # or the IP address of the server
DB_PORT=3306 # or the port that the MySQL/PostgreSQL server uses
DB_USERNAME=your_username
DB_PASSWORD=your_password
NOTE username and password are not mandatory