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.
- Public: Authentication happens here.
- Admin: Manages users and sensitive data.
- Private routes: bikes and trips are offered here.
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:
- Secret:
<api-secret>
- Content-Type:
application/json
- Secret:
-
Example Body:
{ "firstName": "Franco", "lastName": "Méndez", "mail": "[email protected]", "password": "pass1234" }
-
Success Response:
-
Status: 201
-
Content:
{ "balance": 0, "confirmed": false, "firstName": "Franco", "lastName": "Méndez", "mail": "[email protected]", "token": "<user-token>" }
-
-
Error Response:
-
Code: 406
-
Content:
{ "mail": "El correo electrónico ya está en uso" }
-
-
Route:
GET
/confirm/<user-token>/<confirmation-token>
-
Headers:
- Secret:
<api-secret>
- Secret:
-
Success Response:
- Status: 200
- Content-Type:
html
-
Error Response:
-
Code: 400
-
Content:
{ "message": "Ya estás confirmado" }
-
-
Route:
POST
/login
-
Headers:
- Secret:
<api-secret>
- Content-Type:
application/json
- Secret:
-
Example Body:
{ "mail": "[email protected]", "password": "pass1234" }
-
Success Response:
-
Status: 200
-
Content:
{ "balance": 1400, "confirmed": true, "firstName": "Franco", "lastName": "Méndez", "mail": "[email protected]", "token": "<user-token>", "bike": null, "trip": null }
-
-
Error Response:
-
Code: 401
-
Content:
{ "message": "Credenciales inválidas" }
-
-
Route:
PATCH
/user/<user-token>
-
Headers:
- Secret:
<api-secret>
- Content-Type:
application/json
- Secret:
-
Example Body:
{ "oldPassword": "pass1234", "newPassword": "new1234" }
-
Success Response:
-
Status: 200
-
Content:
{ "message": "Tu contraseña ha sido actualizada" }
-
-
Error Response:
-
Code: 401
-
Content:
{ "message": "Credenciales inválidas" }
-
-
Route:
PATCH
/user/<user-email>/recover
-
Headers:
- Secret:
<api-secret>
- Secret:
-
Success Response:
-
Status: 200
-
Content:
{ "message": "Se te ha enviado un email con tu nueva contraseña" }
-
-
Error Response:
-
Code: 400
-
Content:
{ "message": "No se ha encontrado un usuario" }
-
-
Route:
DELETE
/user/<user-token>
-
Headers:
- Secret:
<api-secret>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "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:
- Secret:
<api-secret>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "balance": 1400, "confirmed": true, "firstName": "Franco", "lastName": "Méndez", "mail": "[email protected]", "token": "<user-token>", "bike": {<Bike>}, "trip": {<Trip>} }
-
Error Response:
-
Code: 401
-
Content:
{ "message": "Sesión inválida" }
-
-
Route:
GET
/bikes/<latitude>/<longitude>
-
Headers:
- Secret:
<api-secret>
- Content-Type:
application/json
- Authorization:
<user-token>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "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:
- Secret:
<api-secret>
- Content-Type:
application/json
- Authorization:
<user-token>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "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 inválidas" }
-
-
Route:
POST
/trips/<rubi_id>
-
Headers:
- Secret:
<api-secret>
- Content-Type:
application/json
- Authorization:
<user-token>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "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:
- Secret:
<api-secret>
- Content-Type:
application/json
- Authorization:
<user-token>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "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:
- Secret:
<api-secret>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "balance": 1400, "confirmed": true, "firstName": "Franco", "lastName": "Méndez", "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:
- Secret:
<api-secret>
- Content-Type:
application/json
- Secret:
-
Example Body:
{ "mail": "[email protected]", "amount": "2400" }
-
Success Response:
- Status: 200
- Content:
{ "message": "Se ha añadido $2.400 de saldo a [email protected]" }
-
Error Response:
-
Code: 401
-
Content:
{ "message": "No autorizado" }
-
-
Route:
PATCH
admin/bikes/<rubi_id>
-
Headers:
- Secret:
<api-secret>
- Content-Type:
application/json
- Secret:
-
Example Body:
{ "firstHandshake": "e8a9ad38271968ab76c2a229834937685817a9", "secondHanshake": "2a229834937685817a9e8a9ad38271968ab76c" "macIOS": "1A0C18AA-B29A-930A-4711-0655F2181F34", "macAndroid": "22:1A:3B:1A:AD:D2" }
-
Success Response:
- Status: 200
- Content:
{ "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" }
-
- Franco Méndez Z. - Only engineer to develop this API and the mobile app