Name of app: Traveling Journal
Live app: https://traveling-journal.now.sh/
App repo: https://github.com/sPro1ly0/traveling-journal-app
I like to travel but I have trouble remembering the details of what I did during my trips. I would normally try to write what I did on random pieces of paper only to lose them over time. When I go hiking or have a carry on bag on a plane, I would like to bring a note-book or journal along but I need to pack light so that I have enough room for food or other necessary items. I can take many pictures with my phone but I never go back to look at them often. I just pick a few pictures to post on Instagram with a caption of the place and forget about it. I decided to make the Traveling Journal to help me remember on what I do on my trips, and to keep everything in one place on my phone or laptop.
The Traveling Journal allows users to write about any places they have been and current trips in one place. The user home page has all the user's journal posts listed and the number of journals they have. Users can add, edit, or delete journal posts. They can click on their journal posts to see an individual journal's page. The journal pages allow a user to read a journal's content. The journal page also has a comment section below the content for all users to make comments and ask questions about the journal. The discover page allows users to read and comment on all the journal posts from all users of the app. Users can tell if a journal post is theirs by the edit button displayed on the journal post. The discover page also has a search filter to search journals by a place's name or date.
Protected Endpoints must have a valid authorization token with the request.
All Protected Endpoints Used in Traveling Journal App:
- POST /api/auth/refresh
- GET /api/users
- GET /api/users/journals
- GET /api/journals
- GET /api/journals/:journal_id
- POST /api/journals
- DELETE /api/journals/:journal_id
- PATCH /api/journals/:journal_id
- GET /api/journals/:journal_id/comments
- POST /api/comments
POST /api/auth/login - Login to a user account and get authorization token
Required fields: email and password
Request body template:
{
"email": "valid email address",
"password": "valid password"
}
Request body example:
{
"email": "[email protected]",
"password": "123Abc4!"
}
Response example:
{
"authToken": "893y94hsdjfhaiuiungerlseimg988343y84y37y4r8347brn9834"
}
Response example for invalid email or password:
{
"error": "Incorrect email or password"
}
Response example for missing email or password:
{
"error": "Missing 'email' in request body"
}
{
"error": "Missing 'password' in request body"
}
POST /api/auth/refresh (Protected) - Refresh an authorization token and get a new token
Response example:
{
"authToken": "jfhaiuiu2352svngerlseimg988343y8423fefwe834"
}
GET /api/users (Protected) - Get a user's information
Response example:
{
"full_name": "John Doe"
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
POST /api/users - Create a user
Required fields: full_name, email, password
Request body template:
{
"full_name": "user full name",
"email": "valid email address",
"password": "valid password"
}
Request body example:
{
"full_name": "John Doe",
"email": "[email protected]",
"password": "123Abc4!"
}
Header: Location at /api/users/:user_id
Response example:
{
"id": "1",
"full_name": "John Doe",
"email": "[email protected]",
"date_created": "2019-04-14 20:00:00"
}
Response example for missing one required field:
{
"error": "Missing 'email' in request body"
}
Response example for existing user with same email address:
{
"error": "Email already taken"
}
Response examples for wrong password format:
{
"error": "Password must contain 1 upper case, lower case, number, and special character"
}
{
"error": "Password must be longer than 8 characters"
}
{
"error": "Password must not start or end with empty spaces"
}
Response example for wrong email format:
{
"error": "Please enter an email such as [email protected]"
}
GET /api/users/journals (Protected) - Get a user's journals
Response example:
[
{
"id": 1,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00",
"date_created": "2020-03-11 20:00:00",
"date_modified": "2020-03-12 20:00:00",
"number_of_comments": 2,
"author": "John Doe"
},
{
"id": 3,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-01-14 20:00:00",
"end_date": "2019-02-14 20:00:00",
"date_created": "2020-03-01 20:00:00",
"date_modified": "2020-03-11 20:00:00",
"number_of_comments": 0,
"author": "John Doe"
}
]
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
All journals endpoints are protected and require authorization token with requests.
GET /api/journals (Protected) - Get all journals
Response example:
[
{
"id": 1,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00",
"date_created": "2020-03-11 20:00:00",
"date_modified": "2020-03-12 20:00:00",
"number_of_comments": 2,
"author": "John Doe"
},
{
"id": 2,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-01-14 20:00:00",
"end_date": "2019-02-14 20:00:00",
"date_created": "2020-03-01 20:00:00",
"date_modified": "2020-03-11 20:00:00",
"number_of_comments": 0,
"author": "Jane Lane"
},
{
"id": 3,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00",
"date_created": "2020-03-11 20:00:00",
"date_modified": "2020-03-12 20:00:00",
"number_of_comments": 2,
"author": "John Doe"
},
{
"id": 4,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-01-14 20:00:00",
"end_date": "2019-02-14 20:00:00",
"date_created": "2020-03-01 20:00:00",
"date_modified": "2020-03-11 20:00:00",
"number_of_comments": 0,
"author": "Jack Scott"
}
]
POST /api/journals (Protected) - Add a journal
Required fields: title, location, content, start_date, end_date
Request example:
{
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00"
}
Header: Location at /api/journals/:journal_id
{
"id": 1,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00",
"date_created": "2020-03-11 20:00:00",
"date_modified": null,
"number_of_comments": 0,
"author": "John Doe"
}
Response example for missing one required field:
{
"error": {
"message": "Missing 'title' in request body"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
GET /api/journals/:journal_id (Protected) - Get a specific journal by id
URL- :journal_id is the ID of the journal.
Response example:
[
{
"id": 1,
"title": "Example Title",
"location": "Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-14 20:00:00",
"end_date": "2019-04-14 20:00:00",
"date_created": "2020-03-11 20:00:00",
"date_modified": "2020-03-12 20:00:00",
"number_of_comments": 2,
"author": "John Doe"
}
]
If there is no journal with given id.
Response:
{
"error": {
"message": "Journal doesn't exist"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
DELETE /api/journals/:journal_id (Protected) - Delete a specific journal by id
URL- :journal_id is the ID of the journal.
If there is no journal with given id.
Response:
{
"error": {
"message": "Journal doesn't exist"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
PATCH /api/journals/:journal_id (Protected) - Update specific journal by id
URL- :journal_id is the ID of the journal.
Required fields: title, location, content, start_date, end_date
Request example:
{
"title": "Change Example Title",
"location": "Change Example Location",
"content": "Ipsum ipsum ipsum ipsum ipsum Ipsum ipsum ipsum ipsum ipsum",
"start_date": "2019-04-15 20:00:00",
"end_date": "2019-04-19 20:00:00"
}
If there is no journal with given id.
Response:
{
"error": {
"message": "Journal doesn't exist"
}
}
Response example for missing one required field:
{
"error": {
"message": "Missing 'title' in request body"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
GET /api/journals/:journal_id/comments (Protected) - Get a specific journal by id and its comments
URL- :journal_id is the ID of the journal.
[
{
"id": 1,
"text": "Ipsum!",
"journal_id": 1,
"date_created": "2020-02-19 20:00:00",
"author": "John Doe"
},
{
"id": 3,
"text": "Ipsum dolor!",
"journal_id": 1,
"date_created": "2020-02-22 20:00:00",
"author": "Jane Lane"
}
]
If there is no journal with given id.
Response:
{
"error": {
"message": "Journal doesn't exist"
}
}
Response example for missing one required field:
{
"error": {
"message": "Missing 'title' in request body"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
Comments endpoint is protected and requires authorization token with requests.
POST /api/comments (Protected) - Add a comment *Only comments endpoint used in traveling journal app.
Required fields: text and journal_id
Request example:
{
"text": "Hello there!",
"journal_id": 1
}
Header: Location at /api/comments/:comment_id
{
"id": 1,
"text": "Hello there!",
"journal_id": 1,
"date_created": "2020-02-19 20:00:00",
"author": "Obi Ben"
}
Response example for missing one required field:
{
"error": {
"message": "Missing 'text' in request body"
}
}
If no authorization token provided.
Response:
{
"error": "Missing bearer token"
}
If authorization token is not valid.
Response:
{
"error": "Unauthorized request"
}
- Node.js
- Express.js
- PostgreSQL
- Postgrator for SQL migration
- Knex.js a SQL Query Builder
- JWT for authentication
- Supertest, Mocha, and Chai for testing