- Original Requirements
- Backend Auth
- Frontend Auth
- Stripe Integration
- Mailgun Integration
The purpose of this lab is to make a your own personal blog .. full stack! You'll use everything you've learned from the Database lectures to make a schema, connect it to your Express server, write REST API Endpoints to get your data, and display it all using React. Let's crush it!
- Create a new database named blogs.
- Create the following tables:
Blogs (
id
title
content
authorid
_created
)
Authors (
id
name
email
_created
)
Tags (
id
name
_created
)
BlogTags (
blogid
tagid
)
- Create a stored procedure named
spBlogTagsto pull back the tag of a blog.- Must have one parameter:
blogid - Hint: You only need to join
BlogTagsandTags
- Must have one parameter:
- Create a new user with privileges for your
Blogsdatabase
- Install mysql and its typings into your project
- Make sure your project runs via npm run dev and going to localhost:3000/
- Set up your database config, and don't forget to include it in your .gitignore!
- Use your config object to connect to your mysql database.
- Write your DB queries and REST API Endpoints to:
- GET all Blogs
- GET one Blog
- POST a new Blog, with at least one tag
- Hint: Your blog insert will result in an id response from mysql, use that to insert your blog id and tag id into your blogtags table!
- PUT to edit a Blog
- DELETE to delete a blog
- GET all Blogtags for a blogid
- Create a component to display all Blogs
- Create a component to show one Blog
- Add a button that links to another component to edit this Blog
- The Edit Blog component should allow you to save any edits to your Blog, or delete that Blog
- Create a component to add a new Blog post
- Hint: Use a select element with options to handle adding a tag to your new Blog post
The all Blogs component should display previews of the blog posts that a user can click on, which would navigate to the single Blog component that would display all the information of the Blog post. Don't forget to use your blog tags at least on the single Blog component!
https://www.youtube.com/watch?v=Be8UZxPGyAY
The purpose of this lab is to protect your Blog API routes by adding back end authentication! You should be able to "login" by sending a POST request to a route in Postman. This login should create and send tokens on a successful response. After, you need to be able to protect certain routes on your API by requiring a valid auth token.
- Make sure your users (or authors) table contains an email column, a password column of type
VARCHAR(60), and a role column that can be any text data type. It'd be good practice to make the default value of role to"guest" - If you don't have one, create a accesstokens table with at least the following:
accesstokens (
id,
userid (FK to users id),
token TEXT NOT NULL,
_created
);
- Create a new user with privileges to connect to this schema
- Create a config directory in your server
srccode - Have an
index.tsthat will swap between production/development based on the environment variableNODE_ENV - Export your MySQL config object from your
development.tsand a mirror object format fromproduction.tsusing environment variables - Update your
.gitignoreto include just thedevelopment.tsfile
- Connect to your MySQL DB if you aren't already
- Should already have CRUD (get all, get one, insert, update, and delete) operations for blogs table, write them if you don't
- For your users table, make sure you can
findOneByEmailandfindOneByIdat minimum - For your accesstokens table, make sure you can
findOneByIdAndToken, insert, and update a token at a minimum
Note: If you wish to write a more generic / reusable find, findOne, or any other query, go for it! You don't have to have these very specific queries that the walkthroughs demo. You can write similar functions that can take an entire object and use its keys/values to make a dynamic query every time!
Make sure you have the following modules and their types installed:
bcrypt @types/bcryptjsonwebtoken @types/jsonwebtokenpassport @types/passportpassport-http-bearer @types/passport-http-bearerpassport-local @types/passport-local
- Create a Password Utility using
bcryptto:- Generate a hashed and salted password
- Compare a plain text password to a hash
- Create a Token Utility using
cryptoandjwtto:- CreateToken
- Create a new row in your accesstokens table with that users' id
- Update your payload with that new row's id
- Generate a unique property using
crypto - Sign the token using
jwtand a secret auth key - Update the row with the token value
- Return the token
- ValidateToken
- Using
jwtto decode the token and get a payload - Find the payload in your accesstokens table to verify it
- Return the payload
- Using
- CreateToken
Write a middleware for passport to use a new LocalStrategy to:
- serialize/deserialize a
user - Use the
LocalStrategyusing an email/password - Find that user by their email
- Compare that user's hashed password with what they provided
- Return the
userif it's valid
Write a middleware for passport to use a new BearerStrategy to:
- Validate a provided token
- Using the token's payload, find that user's id in your users table
- Return the
userif it's valid
Make sure in your root server server.ts to:
- Initialize
passport - Import both your middlewares
- Create an auth router with
/loginand/registerroutes - Have the
/loginroute authenticate aPOSTrequest with an email/password. If valid, respond with an object containing thetoken,userid, androleof that user - Have the
/registerroute insert a new user with their hashed/salted password, generate a token, and respond with the same object as the above step (token,userid, androle)
- Have your
passport'bearer' intercept every incoming API route request - It should add a
userproperty to thereqobject if provided a valid Bearer token - In any case, it should forward the
reqobject to the next step in your route logic - Write a new function middleware using
RequestHandlerto check yourreqobject for auserproperty or a specificroleon that property
If all is coded, your completed back end authentication lab should be able to use Postman to:
- Register a new user, and have their hash stored in your users table
- Use the token from a new user's registration to make a request to a protected route
- Make sure you receive "unauthorized" on those protected routes when using no/an incorrect token
https://www.youtube.com/watch?v=xqLg-nUn9Fg
The purpose of this lab is to protect your frontend components using the auth workflow we coded on the backend. We write a utility file to handle localStorage and extending the use of fetch to more reusable in our applications.
At this point, you should have your basic Blog already running components for displaying all blogs, a single blog, and something to post/edit/delete blogs.
- Create an "admin" page that will allow you to create new blog posts and edit and delete existing ones
- You may be able to link to your existing pages for editing and deleting posts
- Make sure you protect your admin page, and the edit/delete pages (require login)
- Any "admin-type" functionality should not be visible from the "public" pages. Those functions should only appear on the admin page(s):
- Create a new post
- Edit a post
- Delete a post
Make sure you have the following modules and their types installed:
- isomorphic-fetch @types/isomorphic-fetch
- moment @types/moment
- for fun added utility :)
- Make sure all of your blog API endpoints use res.json() to send some kind of response, to make sure our frontend utility won't fail in certain circumstances
- Make sure to import isomorphic-fetch
- Export a new variable AccessToken who's value is gotten from localStorage, otherwise defaulting to null
- Export a new object User who's userid and role properties are gotten from localStorage, otherwise defaulting to null
- Export a utility function json (or any name of your choosing) which will make the fetch call, generate the appropriate headers, and convert the json response automatically for you
- arguments should be uri, method, body as the videos demo
- Export a utility function SetAccessToken that given a token, and user object, can set those key/value pairs on localStorage
- Change all your fetch methods across your React components to use your custom json function
- Make sure your "admin" component will not show unless you are logged in, i.e. have it reroute to the login form
- Make your Login component successfully POST request a login, and take the response and set it using SetAccessToken
- Confirm you can navigate back to the "admin" page without getting rerouted, and confirm you can successfully post blogs again
- Add some private class variables that prevent users from spamming a login/submit button and causing multiple requests to fulfill
- Add some error/success handling for good user experience on your webapp
- Add something sweet n' spicy the demos don't and share it in Discord
https://www.youtube.com/watch?v=2xJZQs_ugWQ
After reviewing the material, you should be able to use this knowledge and the boilerplate code to implement a donation form on your blog.
You can choose which Stripe Elements to implement and how you want to style them. It is recommended to look at the several Stripe demos available on their GitHub projects and website.
The goal of this lab is to integrate a 3rd Party API into your code! It's fairly straightforward, and most problems can be solved by following the API's documentation, the walkthroughs, or the reference! Let's start spamming!
- Sign up for a Mailgun Account.
- Get a sandbox domain and api key.
- Install the necessary module and typings.
- Establish your connection with Mailgun.
- Code a sendEmail function.
- Code a route to send an email using that function.
- Test the route in POSTMAN to confirm it works.
- Adjust your route to accept an email, subject, and message from the request body.
- Create a form in a React component with 3 inputs that match up with the above 3 parameters.
- Make sure they're controlled inputs that properly set state and are safely typed.
- Make your form perform an onSubmit event that makes a POST request to your endpoint.
- Make sure you received an email from your contact form.