- Backpaca is an web application that allows users to brag about their travel experiences and plan future adventures with their friends.
Jacob A Brennan | Kyran McCann | Lola Heffernan | Conner Hoessly |
---|---|---|---|
Github | Github | Github | Github |
- front-end: https://backpaca.app/
- back-end: https://backpaca-yoga.herokuapp.com/
- database: https://backpaca-ed6c7c4fde.herokuapp.com/backpaca/prod
- Introduction
- Team
- Deployment Links
- Table of Contents
- Tech-Stack
- Running
- Environment variables
- Auth0 Setup
- API Documentation
cd /frontend >
yarn
to install dependencies >yarn dev
: Runs the frontend onhttp://localhost:3000
cd /backend >
yarn
to install dependencies >yarn dev
: Runs the backend locally with nodemon onhttp://localhost:4000
See Auth0 Setup for a guide on how to assign environment variables with Auth0
In a .env
file at the highest level of the front end folder add these environment variables:
REACT_APP_AUTH0_DOMAIN
: domain name
REACT_APP_AUTH0_CLIENT_ID
: Your personal Auth0 Client ID
REACT_APP_AUTH0_CLIENT_SECRET
: Secret for Auth0
REACT_APP_AUTH0_AUDIENCE
: URL
In a config.env
file at the highest level of the project add these environment variables:
REACT_APP_AUTH0_ISSUER
: URL
REACT_APP_AUTH0_CLIENT_SECRET
: Secret for Auth0 (Same as frontend)
REACT_APP_AUTH0_AUDIENCE
: URL (Same as frontend)
A fully-featured caching GraphQL client that integrates with React. It allows for you to build UI components that will fetch data using GraphQL.
Used to store data from the client.
A standard interface for modifying control flow of GraphQL requests and fetching GraphQL results.
An Apollo link used to remotely fetch data.
An Apollo link for handling errors.
An Apollo link for local state management.
Allows for async look up of things like Authentication tokens. Provides a function that returns either an object or a promise that returns an object to set the new context of the request.
Provides persistence for Apollo Client, the Apollo cache will immediately be restored asynchronously and will be persisted upon every write to the cache.
Allows for authentication through social and enterprise identity providers. Supports both logging the user in and registering the user.
A data query and manipulation language built in Javascript for APIs. GraphQL allows the client to retrieve exactly what they are asking for and nothing more.
A Javascript library for for light-weight, mobile-friendly maps.
Binds Node.JS to LibSass which is used to complile Sass.
A fast and scalable Javascript library for building user interfaces. Allows for a lot of out of the box solutions to modern problems. React has a large community backing which allows for finding solutions to most problems easy accessible.
Allows for fetching of data from the GraphQL server and use of the data for building UIs with React right out of the box.
Pairs with react to serve as the entry point to the DOM.
React-leaflet provides for an abstraction of Leaflet as React components. This does not replace Leaflet but leverages React's lifecycle methods to call the relevant Leaflet handlers.
Binds React Router to the DOM.
Includes the scripts and configuration used by Create React App.
See documentation here on how to use Create React App.
A react implementation of Semantic-UI which is a component framework used to build elegant user interfaces.
Used within our map, which-polygon allows for matching against a set of GeoJSON polygons to determine the location of a country.
Used to build the user visit distribution pie chart. Recharts is a library built with React and D3. The purpose of Recharts is to help in the writing of charts.
A node.js package used as a middleware for Express that allows for enabling of CORS with various options.
Allows for loading of environment variables from a .env
file into process.env
separating the configuration environment from the actual code.
Middleware to validate the JsonWebToken which allows for authentication of JWT tokens in the application.
A fully featured GraphQL Server that allows us to implement our Query and Mutation Resolvers, check permissions, and authenticates our JsonWebTokens.
An implementation of JSON Web Tokens used for Auth0.
A library used to retrieve RSA signing kets from a JSON Web Key Set endpoint. Jwks-rsa is used with Auth0.
A lodash method used to get the value at path of an object. If the resolved value is undefined, the default value will be returned.
Includes all the dependancies besides GraphQL needed to run Prisma client in Javascript. Prisma is our GraphQL database interface that provides a set of CRUD APIs for the database. Prisma also allows us to define our schema and add data relationships.
Watches for changes in the server and automatically restarts the server once changes are detected.
-
Log in or sign up for an account at Auth0.com.
-
Create a new tenant domain. You will be prompted to do so if this is a new account.
-
Go to your dashboard and create a new single page web application.
-
Go to the Applications tab and open your newly created App.
-
Copy and paste the domain field into the REACT_APP_AUTH0_DOMAIN key.
-
Copy and paste your Client ID field into the REACT_APP_AUTH0_CLIENT_ID key.
-
Scroll down to the Allowed Callback URLs field. Enter http://localhost:3000/callback
-
In the Allowed Web Origins field, the Allowed Logout URLs field, and the Allowed Origins(CORS) field, enter http://localhost:3000
-
Under the APIs tab, create a new API. Use the identifier http://localhost:5000
-
To use our custom log in widget, go to the Hosted Pages tab, enable the Custom Login Page switch and paste the following code over the existing widget code.
GraphQL allows for the client to retrieve only the information they request. Here is an example of how you can use GraphQL. You can find our schema here. When clicking the link you will be navigated to the GraphQL interactive playground where you can perform queries and mutations that are provided by the schema when the tab on the right side is opened.
query {
user(id: "cjqpxk83t000o0829p7mr6qto") {
id
name
nickname
scratchingAutomated
isPrivate
identity
twitterHandle
}
}
Using the schema you can see on the user route we have a variety of responses we can retrieve off the user.
id
: The id of the user
name
: The users name
nickname
: The nickname set by the user on their profile page
scratchingAutomated
: Boolean - Is scratching automated for the modal scratch off
isPrivate
: Boolean - Is the users profile set to private on their profile page
idenitity
: How the user was authenticated
twitterHandle
: The current users Twitter handle
{
"data": {
"user": {
"id": "cjqpxk83t000o0829p7mr6qto",
"name": "Ally Paca",
"nickname": "Al",
"scratchingAutomated": null,
"isPrivate": true,
"identity": null,
"twitterHandle": null,
"auth0id": null
}
}
}
mutation {
updateUser(id:"cjqpxk83t000o0829p7mr6qto", bio: "cool new bio") {
name
id
nickname
bio
}
}
A mutation is how we change the data of an object, which in this case is updating the users information.
We will first call updateUser then pass in the users id. Our next argument to updateUser is our data field. In the data field we will pass what we want to update on the user, which is bio in this example.
name
: The name of the user from the where argument
id
: The id of the user
nickname
: The current users nickname
bio
: The updated bio of the user
{
"data": {
"updateUser": {
"name": "Ally Paca",
"id": "cjqpxk83t000o0829p7mr6qto",
"nickname": "Al",
"bio": "cool new bio"
}
}
}
Using the database we can expect a similar experience with a slightly different syntax. You can find our database schema here. When in the GraphQL interactive playground, navigate to the right side of the screen and click the DOCS tab this time.
query {
user(where: { id: "cjqpxk83t000o0829p7mr6qto" }) {
name
id
visits {
id
country {
name
code
}
}
}
}
Here we are querying for the user and asking for their visits and the country of those visits with the country name and country code.
name
: The current users name we are querying
id
: The Id of the queried user
visits
: An object containing the users visits
id
: The id of the visit nested inside the visits object
country
: An object containing the country within that users visit
name
: The name of the country inside the country object
code
: The country code inside of the country object
{
"data": {
"user": {
"name": "Ally Paca",
"id": "cjqpxk83t000o0829p7mr6qto",
"visits": [
{
"id": "cjr0da23s002r0847hq4jx8g5",
"country": {
"name": "Hungary",
"code": "HUN"
}
}
]
}
}
}
mutation {
updateUser(where: { id: "cjqpxk83t000o0829p7mr6qto" }, data: { bio: "My new bio" }) {
name
bio
}
}
A mutation is how we change the data of an object, which in this case is updating the users information.
We will first call updateUser
then pass in where
which is an object containing the users id. Our next argument to updateUser
is our data field. In the data field we will pass an object of what we want to update on the user.
where: {id: cjqpxk83t000o0829p7mr6qto}
: Contains the user we are updating
data: {bio: "My new bio"}
: The field we are updating with the updated content
name
: The name of the user from the where
argument
bio
: The updated bio of the user
{
"data": {
"updateUser": {
"name": "Ally Paca",
"bio": "My new bio"
}
}
}