CircleCI
postgres
redis
nodemon
eslint
airbnb-style
jest
coverage
MIT License
PRs Welcome
Run in Insomnia}
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
eslintandprettierto 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
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 |
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
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_URLkey from.envfile. In the next sub section (Errors Reference) you can see the errorscodedescription.
| 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
/sessionsroute and it will return thetokenkey 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
Beareras auth method expect anAuthorizationheader. 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.