This is a starter project using OpenAPI specifications to bind a NodeJs Express backend and a React frontend, using an `API-first approach - For a quick start, please consult the Cheat Sheet.
Roadmap & Features
Status | Item | info |
---|---|---|
✅ | Codebase | TypeScript & Best Practices |
✅ | Backend | NodeJS, Express |
✅ | React UI | MUI, Chakra, AntD |
✅ | Authentication | OAuth |
✅ | ORM | TypeORM |
❌ | Authorization | Roles: Admins , Common Users |
❌ | User Profiles | Profile information + Image |
❌ | - | Common Users : Edit their profiles |
❌ | - | Admins : Edit all profiles |
❌ | Background tasks | Start, Cancel, Check Status, GET LOGS |
❌ | Deployment | Docker |
❌ | CI/CD | Render Deployment Platform |
❌ | Unitary Tests | - |
- NodeJs is the platform that runs the Backend and builds the Frontend
- NPM is the most popular package manager for the NodeJs ecosystem; to make use of the workspace monorepo architecture this project is built on, make sure you have at least version 7 of NPM installed
- Java JRE is needed by the OpenAPI generator; if you don't want to install Java, you can still use the generator, via the Docker image:
docker run --rm \
-v ${PWD}:/local openapitools/openapi-generator-cli generate \
-i /local/api-bundle.yaml \
-g typescript-fetch \
-o /local/packages/generated
--additional-properties=typescriptThreePlus=true,withInterfaces=true
then compile using:
tsc --project tsconfig.openapi.json
- Express is the most popular NodeJs web framework; the following commonly used plugins have been included:
- helmet is a utility for setting HTTP headers
- morgan is a logging utility
- cors is a utility for configuring cross origin request security
- express-openapi-validator is a utility for validating API requests against the OpenAPI specification
- TypeORM is an ORM that supports the
DataMapper
pattern, which makes is more attractive in combination with the "API first" approach - Express JWT and JWKS-RSA are two utilities for verifying a JWT token authenticity, in an OAuth2 / OpenID connect context
- Create React App is the most popular way to start with React; the Seed provides three UI alternatives:
- React Redux is a state container using the immutable state / action / reducer pattern
- Recharts is a charts library built with React and D3
- React I18Next is a popular internationalization framework for React
- OpenID AppAuth-Js is an OAuth2 / OpenID connect flow library
Both Backend and Frontend use Typescript.
The project consists of 3 major components:
- the OpenAPI specification
- the Backend
- the Frontend
This is found in the spec folder.
The up-to-date OpenAPI specification can be found here.
To improve maintainability, the spec is not provided as a single file, but broken into smaller pieces (read more about this here).
To assemble the API bundle, run this in the project root folder:
npm run generate:spec
This will combine all the smaller files into a single api-bundle.yaml
. This file is in .gitignore
, because we want to always have a single "source of truth" published.
To generate Typescript code from the OpenAPI spec, run the following command in the project root folder:
npm run generate:api
This will create a folder called generated
in packages/frontend
, based on the typescript-fetch generator. Note that this folder is also present in .gitignore
, because the intention is to create it every time, during the CI/CD cycles.
The generated code will include:
- Models
- API Interfaces
- API Client implementation using the Fetch API
The Frontend will use these directly.
The Backend will use them as follows:
- The TypeORM Entity classes will implement the OpenAPI Models
- The Services can implement the API interfaces (not possible yet due to this bug)
This will allow both the Frontend and the Backend to fail fast as soon as the API specification is changed.
Upgrade OpenAPI generator version in openapitools.json when this bug gets resolved.
The application setup, with the various middleware, the routes, as well as error handling, can be found in index.ts.
The ORM section, including Entities, Repositories and Migrations, can be found in data.
The controllers are in controller.
There's also a middleware folder, which contains any custom middleware you need to add (currently it only contains the Authorization middleware that verifies the Access Token received cryptographically).
The Backend configuration is in the .env file.
This seed is configured with a SQLite persistence.
In addition to the standard CRA output, the Frontend is organized as follows:
Each feature has a folder inside the features folder; each feature folder should contain a React component (.tsx
), a Redux slice, with the actions, reducers and side effects, and a test file.
Note that Redux is only necessary for "smart" components, that hold and manipulate a state. "Dumb" components, like nav don't need it.
Don't forget to add your Redux slice in the store to make it functional.
The Frontend also provides a ui folder, that contains the components drawn using the three UI alternatives.
To select one of them, use the corresponding script, in the packages/frontend
folder:
npm run select-ui:mui
npm run select-ui:chakra
npm run select-ui:bootstrap
npm run select-ui:antd
This will effectively replace the necessary components, as well as the theme, with the ones from the selected UI.
Feel free to clean this folder once you have decided upon a UI provider (don't forget to also cleanup the package.json, removing unnecessary dependencies).
The Frontend configuration is in the .env file.
A special note for the authentication flow: this project uses the Authentication Code flow with PKCE verification. The implementation is in authService.ts and the routes can be protected using the GuardedRoute.tsx wrapper component.
The project is configured with a demo Auth0 client.
Modify the backend .env and frontend .env to contain your IDP configuration.
Here are a few major providers of OpenID Connect / OAuth2 platforms (IDPs):
- Microsoft - https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc
- Okta - https://developer.okta.com/docs/guides/implement-grant-type/authcodepkce/main/#next-steps
- Auth0 - https://auth0.com/docs/get-started
For the Authentication Code flow, you'll need the following items:
- the
issuer uri
, which is a URL provided by the IDP for your tenant - the
client id
, which is an id associated with a certain application where the user performs the authentication (i.e. on the same tenant, you can connect multiple applications and users can authenticate for any of these applications with the same credentials / SSO) - the
audience
, which is the id associated with a certain application that receives and verifies the Access Tokens (i.e. your backend in this case) - the
scopes
, i.e. the privileges you can assign to various users (e.g.write_access
,admin_access
, etc.) - the
jwks uri
, which is a public resource associated with your tenant, containing the JSON Web Keys (public keys) that can be used to verify the signatures on your JWTs;
Note that all OpenID providers have a .well-known
path containing many of the information you require, once you are onboarded (e.g. https://node-seed.eu.auth0.com/.well-known/openid-configuration)
If you want to test the solution locally, you can also use Keycloak, the most popular open source IDP - for example using their Docker guide.
Full-Stack Generator - Express
& React
, free starter provided by AppSeed