Giter Site home page Giter Site logo

node-react-udemy's Introduction

node-react-udemy

Coding along with the Udemy course:

  • Microservices with Node JS and React
    Instructor: Stephen Grider
    • Docker Google Cloud Kubernetes, Jest, MongoDB, NATS Streaming Server, Next JS, Node JS, NPM, Skaffold, React, TypeScript

Launching the application:

  1. create the Kubernetes Cluster in Google Cloud
  2. run the Connect command provided
  3. generate secrets:
  • kubectl create secret generic jwt-secret --from-literal=JWT_KEY=xyz123
  • kubectl create secret generic stripe-secret --from-literal=STRIPE_KEY=abc123
  1. Run two commands to install the Ingress-Nginx Controller:
    kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin \ --user $(gcloud config get-value account)
  2. kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml
  3. skaffold dev
  4. wait, the process takes a few minutes to complete
  5. get the ingress IP address
  6. apply that IP locally to the /etc/hosts file for the domain you want to subtitute, in this case, ticketing.com

Project Two, NATS Streaming: ticketing - users, sales, payments

26. Client, completing the routes needed

Route Goal
/auth/signin Signin form
/auth/signup Signup form
/auth/signout Log out
/ List all tickets ^new^
/tickets/new New ticket ^new^
/tickets/:ticketId Ticket details ^new^
/orders/:orderId Order details, Payment button ^new^
  • for Next route files which intake a parameter which the component utilizes, ie: /tickets/[ticketId].js

25. Handling Payments, Stripe

Payment Service
charges
orders
Listen Publish
order:created charge:created
order:cancelled
  • payments service will receive order created event, and listens for order cancelled
    • emits a charge created event
  • Stripe integrated for transactions

24. Order Expiration

  • cancelled event emit/publish added

23. Tickets and Orders Events Publishing/Listening

  • tests and NATS mocks added

22. Orders service

  • expiration date, isReserved() promise added to ticket model,

  • Order

    route method body purpose
    /api/orders GET - all active orders for current user
    /api/orders/id GET - get order details
    /api/orders POST {ticketID: string} create order for ticket#
    /api/orderes/:id DELETE - delete order#
    prop type
    userId the user who created
    status expired, paid, pending
    expiresAt order ttl timestamp
    ticketId id of ticket

    Ticket

    prop type
    title title of event
    price price in USD
    version don't process events twice

22. Tickets, NATS singleton

  • env vars created in Tickets YAML deployment for NATS values
  • NATS wrapper/singleton, graceful shutdown

21. NATS, poc/tests

  • initial stages of trying out publishing and listening to events using NATS Streaming Server (deprecated), Common updated with Events code

  • Class Listener

    Property Type Goal
    subject string name of the channel for listener
    onMessage (event: EventData)=>void run when message received
    client Stan pre-initialized NATS client
    queueGroupName string name of queue group listener will join
    ackWait number seconds has to ack message
    subscriptionOptions SubscriptionOptions default subscription options
    listen ()=>void sets up subscription
    parseMessage (msg:Message)=>any helper for parsing messages
  • Queue Group assigned to listeners - when we have multiple instances of a listener (for load balancing), new messages will be sent to only one listener instances so concurrent responses are not triggered

  • port fowarding for the node port service, ie. kubectl port-forward nats-deployment-xxx 4222:4222

20. Tickets CRUD, and test cases setup

Route Method Body Goal
/api/tickets GET - Retrieve all tickets
/api/tickets/:id GET - Retrieve one ticket
/api/tickets POST {title: string, price: string} Create ticket
/api/tickets PUT {title: string, price: string} Update ticket
  • utilized MONGO_URI environment variable defined in the depl.yaml for Auth and Tickets for the connection string

19. Common NPM module

  • shared NPM library created from Auth souces /middleware and /errors
  • Organization created in NPM, and module published as @agrtickets/common

19. Header navigation added, SignOut

  • useEffect used in SignOut for the /api/users/signout reqeust

19. Passing props through

  • once a getInitialProps is also added to our custom AppComponent (_app.js), the getInitialProps in index.js no longer gets called. This is resolved by calling appContext.Component.getInitialProps

  • nested context props when a Custom App Component is used

    getInitialProps context
    Page Component context==={req, res}
    Custom App Component context==={Component, ctx: {req, res}}
  • AppComponent full context: [ 'AppTree', 'Component', 'router', 'ctx' ]

18. onSuccess callback for Signup added, signed in check

  • reminder https when testing the cookie ๐Ÿ˜…
  • resolved Error: connect ECONNREFUSED 127.0.0.1:80 for when we call /api/users/currentuser. We're calling a service not in our Client or Next container, so the call is not getting routed to the Ingress Nginx Controller. This can be mitigated using getInitialProps
  • getInitialProps is invoked at specific times as per Next
request source getInitialProps execution
page hard refresh server
clicking link from different domain server
typing URL in address bar server
navigating in app between pages client
  • apiBuildClient created to handle these requests from inside or outside of the container, a call to the Ingress controller (not our React client) we route the baseURL to the ingress controller's name (use kubectl get services -n ingress-nginx) and the ingress' namespace (use kubectl get namespace). In this case, the configured path is http://ingress-nginx-controller.ingress-nginx.svc.cluster.local

17. Hook added for network request and error, SignUp

  • instead of setting up the post call manually for each network request, a hook has been added so once we define the url, method, body, simply call useRequest()

16. Bootstrap CSS, Axios, Signup form

  • npm install bootstrap
  • npm install axios - for making the http requests (POST, GET, etc.)
  • Signup form started which utilizes the custom error responses developed earlier for a valid email address and password

15. Next added, deployment for React Client configured

  • Next added for server side React rendering, Client Deployment and Service are working in cluster

14. Global helper signin function

  • additional authentication tests added
  • tests setup set with a global namespace entry for reuse whenever a signin() step is needed during unit tests

13. index.ts refactoring, unit test setup

  • npm install --save-dev @types/jest @types/supertest jest ts-jest supertest mongodb-memory-server
    -- so these aren't deployed to the cluster, in the Dockerfile --omit=dev
  • refactored so we can test app solo, and utilize the ephemeral ports the testing library gives us (ie, we cannot use port 3000 to test app)
  • Jest setup added, one passing test

12. requireAuthentication

  • UnauthorizedError added, requireAuthentication check added and testing successfully in the currentUserRouter route (cannot access the path unless user is logged in)

11. Augmented type definition, toggled vs-kubernetes resource-limits linter

  • added a shared currentUserCheck (verify JWT enviroment variable) which includes using declare global to modify an existing type definition, in this case, Express' Request to add a currentUser property
  • VS Code preference to dismiss the yaml linting warning about One or more containers do not have resource limits, use the following in setting.json:
    "vs-kubernetes": { "disable-linters": ["resource-limits"], ... },

10. SignOut added

  • setting the session to null destroys the cookie

9. CurrentUser

  • establish if user has a cookie with a valid JWT

8. SignIn started

  • using same pattern of session JWT coded in SignUp
  • comparision helper method in PasswordManager for stored and supplied password

7. Cookie, Kubernetes Secret, JWT

  • session cookie is authored when a User is created (npm install cookie-session, npm install jsonwebtoken and the @types), JSON web token value is written in the cookie
  • Kubernetes Secret is utilized for the JWT key
  • secret creation example kubectl create secret generic jwt-secret-name --from-literal=JWT_KEY=xxxxx
  • generate 32 bit string: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

6. Password hashing

  • before writing to MongoDB, password is not longer saved in plain text (login comparison is a later step)

5. Bad Request error type added

  • existing email check, added BadRequestError that can be used with throw

4. Mongo DB added to deployments, User model added

  • created interfaces for mongoose/TypeScript, used those types in the generic definitions, so now we can call User.build({}) and get proper type checking along the way

3. Async route error handling implemented

  • installed npm package express-async-errors to alter the default route handling of Express, there will be an await added to an async route (so we don't have to be confined to using next())

2. Common error handling middleware defined

  • Error class extended: RequestValidationError, DatabaseConnectionError
  • custom errors created, using them in route handler, common formatted response {errors: {message: string, field?: string}[]}

1. Initial setup, utilizing Skaffold, Google Cloud Build


Project One, blog - manually created event bus

5. Ingress Controller, local domain redirects, Skaffold config

  • added config file for trying out Skaffold, seems to kick off faster than possible and inconsistent services fail during deployment, todo/research
  • need to understand/resolve ingress to the client, data is displaying (incorrect)
  • resolving exising issue of two routes, a GET and a POST, both to /posts, ngnix cannot do routing based on the request method type, so we have to revise to unique paths
  • for an ingress controller, use the apply command noted in the nginx ingress controller documentation (see "If you don't have Helm..."). When done successfully kubectl get ingress will display an IP under 'ADDRESS' and requets to http://posts.com/posts result in JSON entries posted via postman, use gcloud compute instances list to get an external IP for the postman request address, and kubectl describe services to find the random port 3xxxx port assigned
  • added an entry in local /etc/hosts file to redirect posts.com requests to the IP of the Ingress controller
  • moved all infrastructure files into one folder, thus kubectl apply -f . to kick them all off

4. Cluster IP Services

  • integrated Cluster IP services for the event-bus and posts applications, tested using K8s Service names instead of localhost addresses

  • having memory and cpu limits in deployment file caused 'minimum cpu' errors when deploying and caused Pending instances, commented out generated defaults

3. Docker

Testing / utilizing configuration files

  • even though the kubectl k get services ouput reads as if a 3xxxx port is available, a firewall rule must be added in Google Cloud to open that port to traffic, ie.: gcloud compute firewall-rules create test-node-port \ --allow tcp:30317
    • Google Cloud docs, eposing apps

2. Approval flow, Moderation service, and Event Syncing

Service communication destination
Posts <=> Event Bus
Comments <=> ""
Query <=> ""
Moderation <=> ""
  • CommentModerated event

    • id : string
    • content : string
    • postId : string
    • status : 'approved' | 'rejected'
  • emitted from the Moderation service

  • received inside of Comments service

  • Added:

Service local folder port
Moderation /moderation 4003

Bringing up new services surfaces the strategy of storing events, to run new service/event jobs on previous events. Enter, the Event Sync changes:

  1. Store event bus events inside of an array
  2. Add endpoint to Event Bus to retrieve all events that have occurred
  3. Make sure when Query service is launched it reaches out to the Event Bus to request all events, and the Quer service tries to process that data

There's no persistence here, the exercise is the communication between resources and running our moderation sercie

Definitely messy business adding or changing events ๐Ÿ˜ฃ


1. Initial Event Bus setup

Service communication destination
Posts <=> Event Bus
Comments <=> ""
Query <=> ""
  • The application example is that of a blog (React front-end, Node microservices) where there can be posts with many comments, the comments will then have an approval flow.

  • Event bus example using Express coded by hand and working. The design will not have the vast majority of features a normal bus has. Production grade version will be in a later stage. The Posts, Comments, and Query services all communicate through the event bus.

  • Services:

    Service local folder port
    React /client 3000
    Posts /posts 4000
    Comments /comments 4001
    Query /query 4002
    Event Bus /event-bus 4005
  • React project structure

    • App
      • PostList
        • CommentsList
        • CommentsCreate
      • PostCreate

node-react-udemy's People

Contributors

adrian-rosario avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.