Responsible for provide data to the web
and mobile
front-ends. Allow users to create their meetups' and/or subscribe to from other users. The app has, pagination, pagination's link header (to previous, next, first and last page), friendly errors, use JWT to logins, validation, also a simple versioning was made.
Easy peasy lemon squeezy:
$ yarn
Or:
$ npm install
Was installed and configured the
eslint
andprettier
to keep the code clean and patterned.
The application uses two databases: Postgres and Redis. For the fastest setup is recommended to use docker-compose, you just need to up all services:
$ docker-compose up -d
Responsible to store data utilized by the mail queue. If for any reason you would like to create a Redis container instead of use docker-compose
, you can do it by running the following command:
$ docker run --name meetapp-redis -d -p 6379:6379 redis:alpine
Responsible to store all application data. If for any reason you would like to create a Postgres container instead of use docker-compose
, you can do it by running the following command:
$ docker run --name meetapp-postgres -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres
Remember to run the Postgres database migrations:
$ npx sequelize db:migrate
Or:
$ yarn sequelize db:migrate
See more information on Sequelize Migrations.
Optionally you can fill the database with some random data:
$ npx sequelize db:seed:all
Or:
$ yarn sequelize db:seed:all
In this file you may configure your Redis database connection, JWT settings, the environment, app's port and a url to documentation (this will be returned with error responses, see error section). Rename the .env.example
in the root directory to .env
then just update with your settings.
key | description | default |
---|---|---|
APP_URL | App's url. | http://localhost |
APP_PORT | Port number where the app will run. | 3333 |
NODE_ENV | App environment. | development |
JWT_SECRET | A alphanumeric random string. Used to create signed tokens. | - |
JWT_EXPIRATION_TIME | How long time will be the token valid. See jsonwebtoken repo for more information. | 7d |
DB_HOST | Postgres host. | pg |
DB_PORT | Postgres port. | 5432 |
DB_USER | Postgres user. | - |
DB_PASS | Postgres password. | - |
DB_NAME | meetapp |
|
MAIL_HOST | SMTP service's host. | smtp.mailtrap.io |
MAIL_PORT | SMTP service's port. | 2525 |
MAIL_USER | SMTP service's user | - |
MAIL_PASS | SMTP service's password | - |
REDIS_HOST | Redis host. | redis |
REDIS_PORT | Redis port. | 6379 |
SEQUELIZE_LOG | Indicates whether sequelize query operation logs should be shown. | 0 |
DOCS_URL | An url to docs where users can find more information about the app's internal code errors. | https://github.com/DiegoVictor/meetapp-api#errors-reference |
To start up the app run:
$ yarn dev:server
Or:
npm run dev:server
Also the application has a mail queue, to setup it just remember to run:
$ npm run queue
Or:
$ yarn queue
The mail queue send emails to meetups' owner notifying when a user subscribes to it
Instead of only throw a simple message and HTTP Status Code this API return friendly errors:
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Token not provided",
"code": 441,
"docs": "https://github.com/DiegoVictor/meetapp-api#errors-reference"
}
Errors are implemented with @hapi/boom. As you can see a url to error docs are returned too. To configure this url update the
DOCS_URL
key from.env
file. In the next sub section (Errors Reference) you can see the errorscode
description.
code | message | description |
---|---|---|
140 | Past dates are not permited | You can't created meetup with past dates. |
141 | The provided banner does not exists | The banner_id sent does not references an existing file in the database. |
142 | You can't edit past meetups | Is not permitted update past meetups. |
143 | You can't remove past meetups | Past meetup can't be deleted. |
144 | Meetup does not exists | The provided meetup does not exists. |
240 | Meetup does not exists or is owned by the provided user | Is not possible to create a subscripton from a meetup that not exists or a meetup owned by yourself. |
241 | You can't subscribe to a past meetup | Is not possible to subscribe to past meetups. |
242 | You are already subscribed to this meetup or there is another meetup in the same time | Conflict or hours or you are already subscribed. |
244 | Meetup or user does not exists | You are trying delete a subscription from a meetup or user that not exists. |
340 | Password does not match | You are trying to update the password with wrong old password. |
341 | Email already in use | Email is already registered by another user. |
440 | Password does not match | Wrong password when trying to login. |
441 | Token not provided | The JWT token was not sent. |
442 | Token invalid | The JWT token provided is invalid or expired. |
444 | User not found | The JWT token not correspond to existing user. |
All the routes with pagination returns 20 records per page, to navigate to other pages just send the page
query parameter with the number of the page.
- To get the third page of meetups:
GET http://localhost:3333/v1/meetups?page=3
Also in the headers of every route with pagination the Link
header is returned with links to first
, last
, next
and prev
(previous) page.
<http://localhost:3333/v1/meetups?page=7>; rel="last",
<http://localhost:3333/v1/meetups?page=4>; rel="next",
<http://localhost:3333/v1/meetups?page=1>; rel="first",
<http://localhost:3333/v1/meetups?page=2>; rel="prev"
See more about this header in this MDN doc: Link - HTTP.
Another header returned in routes with pagination, this bring the total records amount.
A few routes expect a Bearer Token in an Authorization
header.
You can see these routes in the routes section.
GET http://localhost:3333/v1/subscriptions Authorization: Bearer <token>
To achieve this token you just need authenticate through the
/sessions
route and it will return thetoken
key with a valid Bearer Token.
A simple versioning was made. Just remember to set after the host
the /v1/
string to your requests.
GET http://localhost:3333/v1/subscriptions
route | HTTP Method | pagination | params | description | auth method |
---|---|---|---|---|---|
/sessions |
POST | ❌ | Body with user's email and password . |
Authenticates user, return a Bearer Token and user's id and email. | ❌ |
/users |
POST | ❌ | Body with user's name , email and password . |
Create new users. | ❌ |
/users |
PUT | ❌ | Body with user's name , email and old_password , password and confirm_password . |
Update an existing users. | Bearer |
/files |
POST | ❌ | Multipart payload with a file field with a image (See insomnia file for good example). |
Upload meetup banner. | Bearer |
/meetups |
GET | ✔️ | page query parameter. |
Lists meetups. | Bearer |
/meetups |
POST | ❌ | Body with meetup's banner_id date , description , localization and title . |
Create a new meetup. | Bearer |
/meetups |
PUT | ❌ | Body with meetup's banner_id date , description , localization and title . |
Update a meetup. | Bearer |
/meetups/:id |
DELETE | ❌ | id of the meetup. |
Delete a meetup. | Bearer |
/scheduled |
GET | ❌ | - | Lists logged in user's meetups. | Bearer |
/scheduled/:id |
GET | ❌ | id of the meetup. |
Show one logged in user's meetup. | Bearer |
/subscriptions |
GET | ✔️ | - | Lists logged in user's subscriptions. | Bearer |
/subscriptions |
POST | ❌ | Body with subscription's meetup_id . |
Subscribe yourself to a meetup. | Bearer |
/subscriptions |
DELETE | ❌ | Body with subscription's meetup_id . |
Unsubscribe yourself from a meetup. | Bearer |
Routes with
Bearer
as auth method expect anAuthorization
header. See Bearer Token section for more information.
POST /session
Request body:
{
"email": "johndoe@example.com",
"password": "123456"
}
POST /users
Request body:
{
"email": "johndoe@example.com",
"name": "John Doe",
"password": "123456"
}
PUT /users
Request body:
{
"name": "John Doe",
"email": "johndoe@example.com",
"old_password": "123456",
"password": "123456789",
"confirm_password": "123456789"
}
POST /files
Image file
POST /meetups
Request body:
{
"banner_id": 1,
"date": "2020-12-30",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"localization": "4795 Denesik Throughway Kaileefurt, NC 07927-4723",
"title": "Creative Planner"
}
PUT /meetups
Request body:
{
"banner_id": 1,
"date": "2020-12-31",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"localization": "64504 Stehr Motorway Tellyfort, IL 33915-6894",
"title": "Lead Quality Director"
}
PUT /subscriptions
Request body:
{
"meetup_id": 1,
}
Jest was the choice to test the app, to run:
$ yarn test
Or:
$ npm run test
You can see the coverage report inside tests/coverage
. They are automatically created after the tests run.