API built with Koa.js serving an instant bike rental service for a mobile app
This API is built in Koa.js framework using MongoDB for this mobile app. Together they provide an instant bike rental service handling users, bikes and trips. There are 3 kind of route, each one adds one security filter making use of Koa middlewares.
For development, run this commands so you clone the repo, install dependencies and start a local server
git clone https://github.com/fnmendez/lof-api
cd lof-api
yarn
yarn dev
Don't forget to set the environment variables exposed next.
You can do this making use of direnv and the .envrc.example
file.
variable | default | use |
---|---|---|
PORT | 3000 | Port in which the API is exposed |
API_URI | http://localhost:3000 | URI where this API is accessed from |
API_SECRET | Secret used for security | |
BIKES_API_URI | URI where we know bikes' locations | |
BIKES_API_USER | User for bikes API | |
BIKES_API_TOKEN | Token for bikes API | |
BIKES_API_RUBI_ID | Id for bikes API | |
BIKES_API_RADIUS | 80 | Radius to look for bikes from location |
MAIL_NAME | LOF Test Mail | Name to show in emails |
MAIL_USER | [email protected] | The email address |
MAIL_PASSWORD | loftest123 | Email's password |
MAX_REQUEST_TIMEOUT | 15000 | Seconds for timeout for requests |
Route: POST
/signup
Headers:
<api-secret>
application/json
Example Body:
{
"firstName": "Franco",
"lastName": "Mndez",
"mail": "[email protected]",
"password": "pass1234"
}
Success Response:
Status: 201
Content:
{
"balance": 0,
"confirmed": false,
"firstName": "Franco",
"lastName": "Mndez",
"mail": "[email protected]",
"token": "<user-token>"
}
Error Response:
Code: 406
Content:
{ "mail": "El correo electrnico ya est en uso" }
Route: GET
/confirm/<user-token>/<confirmation-token>
Headers:
<api-secret>
Success Response:
html
Error Response:
Code: 400
Content:
{ "message": "Ya ests confirmado" }
Route: POST
/login
Headers:
<api-secret>
application/json
Example Body:
{
"mail": "[email protected]",
"password": "pass1234"
}
Success Response:
Status: 200
Content:
{
"balance": 1400,
"confirmed": true,
"firstName": "Franco",
"lastName": "Mndez",
"mail": "[email protected]",
"token": "<user-token>",
"bike": null,
"trip": null
}
Error Response:
Code: 401
Content:
{ "message": "Credenciales invlidas" }
Route: PATCH
/user/<user-token>
Headers:
<api-secret>
application/json
Example Body:
{
"oldPassword": "pass1234",
"newPassword": "new1234"
}
Success Response:
Status: 200
Content:
{
"message": "Tu contrasea ha sido actualizada"
}
Error Response:
Code: 401
Content:
{ "message": "Credenciales invlidas" }
Route: PATCH
/user/<user-email>/recover
Headers:
<api-secret>
Success Response:
Status: 200
Content:
{
"message": "Se te ha enviado un email con tu nueva contrasea"
}
Error Response:
Code: 400
Content:
{ "message": "No se ha encontrado un usuario" }
Route: DELETE
/user/<user-token>
Headers:
<api-secret>
Success Response:
{ "message": "Se ha eliminado el usuario exitosamente" }
Error Response:
Code: 400
Content:
{ "message": "No se ha encontrado el usuario a eliminar" }
Route: GET
/user/<user-token>
Headers:
<api-secret>
Success Response:
{
"balance": 1400,
"confirmed": true,
"firstName": "Franco",
"lastName": "Mndez",
"mail": "[email protected]",
"token": "<user-token>",
"bike": {<Bike>},
"trip": {<Trip>}
}
Error Response:
Code: 401
Content:
{ "message": "Sesin invlida" }
Route: GET
/bikes/<latitude>/<longitude>
Headers:
<api-secret>
application/json
<user-token>
Success Response:
{
"bikes": [
{
"rubi_id": 337,
"coordinates": [
"<longitude>",
"<latitude>"
],
"macIOS": "<macIOS>",
"macAndroid": "<macAndroid>",
"hs1": "<hs1>",
"hs2": "<hs2>"
},
{
"rubi_id": 229,
"coordinates": [
"<longitude>",
"<latitude>"
],
"macIOS": "<macIOS>",
"macAndroid": "<macAndroid>",
"hs1": "<hs1>",
"hs2": "<hs2>"
}
],
"interval": 2000
}
Error Response:
Code: 403
Content:
{ "message": "Cuenta no confirmada" }
Route: GET
/trips
Headers:
<api-secret>
application/json
<user-token>
Success Response:
{
"trips": [
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 21,
"cost": 300,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 122,
"cost": 200,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 300,
"cost": 600,
"finishedAt": "<Date>",
"startedAt": "<Date>"
}
]
}
Error Response:
Code: 401
Content:
{ "message": "Credenciales invlidas" }
Route: POST
/trips/<rubi_id>
Headers:
<api-secret>
application/json
<user-token>
Success Response:
{
"trips": [
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 21,
"cost": 300,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 122,
"cost": 200,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 300,
"cost": 600,
"finishedAt": "<Date>",
"startedAt": "<Date>"
}
]
}
Error Response:
Code: 403
Content:
{ "message": "No tienes saldo" }
Route: PATCH
/trips
Headers:
<api-secret>
application/json
<user-token>
Success Response:
{
"trips": [
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 21,
"cost": 300,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 122,
"cost": 200,
"finishedAt": "<Date>",
"startedAt": "<Date>"
},
{
"_id": "<trip-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"userId": "<user-id>",
"rubi_id": 300,
"cost": 600,
"finishedAt": "<Date>",
"startedAt": "<Date>"
}
]
}
Error Response:
Code: 400
Content:
{
"message": "No tienes viajes sin finalizar"
}
Route: GET
admin/users/<user-email>
Headers:
<api-secret>
Success Response:
{
"balance": 1400,
"confirmed": true,
"firstName": "Franco",
"lastName": "Mndez",
"mail": "[email protected]",
"confirmPath": "<confirm-path>"
"token": "<user-token>",
"bike": {<Bike>},
"trip": {<Trip>}
}
Error Response:
Code: 401
Content:
{ "message": "No autorizado" }
Route: PATCH
admin/users
Headers:
<api-secret>
application/json
Example Body:
{
"mail": "[email protected]",
"amount": "2400"
}
Success Response:
{
"message": "Se ha aadido $2.400 de saldo a [email protected]"
}
Error Response:
Code: 401
Content:
{ "message": "No autorizado" }
Route: PATCH
admin/bikes/<rubi_id>
Headers:
<api-secret>
application/json
Example Body:
{
"firstHandshake": "e8a9ad38271968ab76c2a229834937685817a9",
"secondHanshake": "2a229834937685817a9e8a9ad38271968ab76c"
"macIOS": "1A0C18AA-B29A-930A-4711-0655F2181F34",
"macAndroid": "22:1A:3B:1A:AD:D2"
}
Success Response:
{
"bike": {
"_id": "<bike-id>",
"updatedAt": "<Date>",
"createdAt": "<Date>",
"rubi_id": 1,
"lat": <latitude>,
"lon": <longitude>,
"lastLockedDate": "<Date>",
"lastUnlockDate": "<Date>",
"lastUserId": "<user-id>",
"secondHandshake": "<secondHanshake>",
"firstHandshake": "<firstHandshake>",
"macAndroid": "<macAndroid>",
"macIOS": "<macIOS>",
"available": true
}
}
Error Response:
Code: 401
Content:
{ "message": "No autorizado" }