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 devDon'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 | lofdevtest@gmail.com | 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": "fnmendez@uc.cl", "password": "pass1234" }
-
Success Response:
-
Status: 201
-
Content:
{ "balance": 0, "confirmed": false, "firstName": "Franco", "lastName": "Méndez", "mail": "fnmendez@uc.cl", "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": "fnmendez@uc.cl", "password": "pass1234" }
-
Success Response:
-
Status: 200
-
Content:
{ "balance": 1400, "confirmed": true, "firstName": "Franco", "lastName": "Méndez", "mail": "fnmendez@uc.cl", "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": "fnmendez@uc.cl", "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:
GETadmin/users/<user-email> -
Headers:
- Secret:
<api-secret>
- Secret:
-
Success Response:
- Status: 200
- Content:
{ "balance": 1400, "confirmed": true, "firstName": "Franco", "lastName": "Méndez", "mail": "fnmendez@uc.cl", "confirmPath": "<confirm-path>" "token": "<user-token>", "bike": {<Bike>}, "trip": {<Trip>} }
-
Error Response:
-
Code: 401
-
Content:
{ "message": "No autorizado" }
-
-
Route:
PATCHadmin/users -
Headers:
- Secret:
<api-secret> - Content-Type:
application/json
- Secret:
-
Example Body:
{ "mail": "fnmendez@uc.cl", "amount": "2400" }
-
Success Response:
- Status: 200
- Content:
{ "message": "Se ha añadido $2.400 de saldo a fnmendez@uc.cl" }
-
Error Response:
-
Code: 401
-
Content:
{ "message": "No autorizado" }
-
-
Route:
PATCHadmin/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