- Notifications
You must be signed in to change notification settings - Fork915
A delightful way to building a RESTful API with NodeJs & TypeScript by@w3tecch
License
w3tecch/express-typescript-boilerplate
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A delightful way to building a Node.js RESTful API Services with beautiful code written in TypeScript.
Inspired by the awesome frameworklaravel in PHP and of the repositories frompleerock
Made with ❤️ byw3tech,Gery Hirschfeld andcontributors
Our main goal with this project is a feature complete server application.We like you to be focused on your business and not spending hours in project configuration.
Try it!! We are happy to hear your feedback or any kind of new features.
- Beautiful Code thanks to the awesome annotations of the libraries frompleerock.
- Easy API Testing with included e2e testing.
- Dependency Injection done with the nice framework fromTypeDI.
- Simplified Database Query with the ORMTypeORM.
- Clear Structure with different layers such as controllers, services, repositories, models, middlewares...
- Easy Exception Handling thanks torouting-controllers.
- Smart Validation thanks toclass-validator with some nice annotations.
- Custom Validators to validate your request even better and stricter.custom-validation-classes.
- API Documentation thanks toswagger androuting-controllers-openapi.
- API Monitoring thanks toexpress-status-monitor.
- Integrated Testing Tool thanks toJest.
- E2E API Testing thanks tosupertest.
- Basic Security Features thanks toHelmet.
- Easy event dispatching thanks toevent-dispatch.
- Fast Database Building with simple migration fromTypeORM.
- Easy Data Seeding with our own factories.
- GraphQL provides as a awesome query language for our apiGraphQL.
- TypeGraphQL thanks toTypeGraphQL we have a some cool decorators to simplify the usage of GraphQL.
- DataLoaders helps with performance thanks to caching and batchingDataLoaders.
- Getting Started
- Scripts and Tasks
- Debugger in VSCode
- API Routes
- Project Structure
- Logging
- Event Dispatching
- Seeding
- GraphQL
- Docker
- Further Documentations
- Related Projects
- License
You need to set up your development environment before you can do anything.
InstallNode.js and NPM
- on OSX usehomebrew
brew install node
- on Windows usechocolatey
choco install nodejs
Install yarn globally
yarn global add yarn
Install a MySQL database.
If you work with a mac, we recommend to use homebrew for the installation.
Fork or download this project. Configure your package.json for your new project.
Then copy the.env.example
file and rename it to.env
. In this file you have to add your database connection information.
Create a new database with the name you have in your.env
-file.
Then setup your application environment.
yarn run setup
This installs all dependencies with yarn. After that it migrates the database and seeds some test data into it. So after that your development environment is ready to use.
Go to the project dir and start your app with this yarn script.
yarn start serve
This starts a local server using
nodemon
, which will watch for any file changes and will restart the server according to these changes.The server address will be displayed to you ashttp://0.0.0.0:3000
.
All script are defined in thepackage-scripts.js
file, but the most important ones are listed here.
- Install all dependencies with
yarn install
- Run code quality analysis using
yarn start lint
. This runs tslint. - There is also a vscode task for this called
lint
.
- Run the unit tests using
yarn start test
(There is also a vscode task for this calledtest
). - Run the integration tests using
yarn start test.integration
. - Run the e2e tests using
yarn start test.e2e
.
- Run
yarn start serve
to start nodemon with ts-node, to serve the app. - The server address will be displayed to you as
http://0.0.0.0:3000
- Run
yarn start build
to generated all JavaScript files from the TypeScript sources (There is also a vscode task for this calledbuild
). - To start the builded app located in
dist
useyarn start
.
- Run
typeorm migration:create -n <migration-file-name>
to create a new migration file. - Try
typeorm -h
to see more useful cli commands like generating migration out of your models. - To migrate your database run
yarn start db.migrate
. - To revert your latest migration run
yarn start db.revert
. - Drops the complete database schema
yarn start db.drop
.
- Run
yarn start db.seed
to seed your seeds into the database.
To debug your code runyarn start build
or hitcmd +b to build your app.Then, just set a breakpoint and hitF5 in your Visual Studio Code.
The route prefix is/api
by default, but you can change this in the .env file.The swagger and the monitor route can be altered in the.env
file.
Route | Description |
---|---|
/api | Shows us the name, description and the version of the package.json |
/graphql | Route to the graphql editor or your query/mutations requests |
/swagger | This is the Swagger UI with our API documentation |
/monitor | Shows a small monitor page for the server |
/api/users | Example entity endpoint |
/api/pets | Example entity endpoint |
Name | Description |
---|---|
.vscode/ | VSCode tasks, launch configuration and some other settings |
dist/ | Compiled source files will be placed here |
src/ | Source files |
src/api/controllers/ | REST API Controllers |
src/api/controllers/requests | Request classes with validation rules if the body is not equal with a model |
src/api/controllers/responses | Response classes or interfaces to type json response bodies |
src/api/errors/ | Custom HttpErrors like 404 NotFound |
src/api/interceptors/ | Interceptors are used to change or replace the data returned to the client. |
src/api/middlewares/ | Express Middlewares like helmet security features |
src/api/models/ | TypeORM Models |
src/api/repositories/ | Repository / DB layer |
src/api/services/ | Service layer |
src/api/subscribers/ | Event subscribers |
src/api/validators/ | Custom validators, which can be used in the request classes |
src/api/resolvers/ | GraphQL resolvers (query, mutation & field-resolver) |
src/api/types/ | GraphQL types ,input-types and scalar types |
src/api/ schema.gql | Generated GraphQL schema |
src/auth/ | Authentication checkers and services |
src/core/ | The core features like logger and env variables |
src/database/factories | Factory the generate fake entities |
src/database/migrations | Database migration scripts |
src/database/seeds | Seeds to create some data in the database |
src/decorators/ | Custom decorators like @Logger & @EventDispatch |
src/loaders/ | Loader is a place where you can configure your app |
src/public/ | Static assets (fonts, css, js, img). |
src/types/ *.d.ts | Custom type definitions and files that aren't on DefinitelyTyped |
test | Tests |
test/e2e/ *.test.ts | End-2-End tests (like e2e) |
test/integration/ *.test.ts | Integration test with SQLite3 |
test/unit/ *.test.ts | Unit tests |
.env.example | Environment configurations |
.env.test | Test environment configurations |
mydb.sql | SQLite database for integration tests. Ignored by git and only available after integration tests |
Our logger iswinston. To log http request we use the express middlewaremorgan.We created a simple annotation to inject the logger in your service (see example below).
import{Logger,LoggerInterface}from'../../decorators/Logger';@Service()exportclassUserService{constructor( @Logger(__filename)privatelog:LoggerInterface){} ...
We use this awesome repositoryevent-dispatch for event dispatching.We created a simple annotation to inject the EventDispatcher in your service (see example below). All events are listed in theevents.ts
file.
import{events}from'../subscribers/events';import{EventDispatcher,EventDispatcherInterface}from'../../decorators/EventDispatcher';@Service()exportclassUserService{constructor( @EventDispatcher()privateeventDispatcher:EventDispatcherInterface){}publicasynccreate(user:User):Promise<User>{ ...this.eventDispatcher.dispatch(events.user.created,newUser); ...}
Isn't it exhausting to create some sample data for your database, well this time is over!
How does it work? Just create a factory for your entities (models) and a seed script.
For all entities we want to seed, we need to define a factory. To do so we give you the awesomefaker library as a parameter into your factory. Then create your "fake" entity and return it. Those factory files should be in thesrc/database/factories
folder and suffixed withFactory
likesrc/database/factories/UserFactory.ts
.
Settings can be used to pass some static value into the factory.
define(User,(faker:typeofFaker,settings:{roles:string[]})=>{constgender=faker.random.number(1);constfirstName=faker.name.firstName(gender);constlastName=faker.name.lastName(gender);constemail=faker.internet.email(firstName,lastName);constuser=newUser();user.firstName=firstName;user.lastName=lastName;user.email=email;user.roles=settings.roles;returnuser;});
Handle relation in the entity factory like this.
define(Pet,(faker:typeofFaker,settings:undefined)=>{constgender=faker.random.number(1);constname=faker.name.firstName(gender);constpet=newPet();pet.name=name;pet.age=faker.random.number();pet.user=factory(User)({roles:['admin']})returnpet;});
The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.With the second function, accepting your settings defined in the factories, you are able to create different variations of entities.
exportclassCreateUsersimplementsSeed{publicasyncseed(factory:Factory,connection:Connection):Promise<any>{awaitfactory(User)({roles:[]}).createMany(10);}}
Here an example with nested factories. You can use the.map()
function to alterthe generated value before they get persisted.
...awaitfactory(User)().map(async(user:User)=>{constpets:Pet[]=awaitfactory(Pet)().createMany(2);constpetIds=pets.map((pet:Pet)=>pet.Id);awaituser.pets().attach(petIds);}).createMany(5);...
To deal with relations you can use the entity manager like this.
exportclassCreatePetsimplementsSeedsInterface{publicasyncseed(factory:FactoryInterface,connection:Connection):Promise<any>{constconnection=awaitfactory.getConnection();constem=connection.createEntityManager();awaittimes(10,async(n)=>{// This creates a pet in the databaseconstpet=awaitfactory(Pet)().create();// This only returns a entity with fake dataconstuser=awaitfactory(User)({roles:['admin']}).make();user.pets=[pet];awaitem.save(user);});}}
The last step is the easiest, just hit the following command in your terminal, but be sure you are in the projects root folder.
yarn start db.seed
Command | Description |
---|---|
yarn start "db.seed" | Run all seeds |
yarn start "db.seed --run CreateBruce,CreatePets" | Run specific seeds (file names without extension) |
yarn start "db.seed -L" | Log database queries to the terminal |
yarn start "db.seed --factories <path>" | Add a different path to your factories (Default:src/database/ ) |
yarn start "db.seed --seeds <path>" | Add a different path to your seeds (Default:src/database/seeds/ ) |
For the GraphQL part we used the libraryTypeGraphQL to build awesome GraphQL API's.
The context(shown below) of the GraphQL is builded in thegraphqlLoader.ts file. Inside of this loader we create a scoped container for each incoming request.
exportinterfaceContext{requestId:number;request:express.Request;response:express.Response;container:ContainerInstance;}
For the usage of the DataLoaders we created a annotation, which automatically creates and registers a new DataLoader to the scoped container.
Here is an example of thePetResolver.
importDataLoaderfrom'dataloader';import{DLoader}from'../../decorators/DLoader'; ...constructor(privatepetService:PetService, @Logger(__filename)privatelog:LoggerInterface, @DLoader(UserModel)privateuserLoader:DataLoader<string,UserModel>){}...
Or you could use the repository too.
@DLoader(UserRepository)private userLoader:DataLoader<string,UserModel>
Or even use a custom method of your given repository.
@DLoader(PetRepository,{method:'findByUserIds',key:'userId',multiple:true,})private petLoader:DataLoader<string,PetModel>
Before you start, make sure you have a recent version ofDocker installed
docker build -t<your-image-name>.
The port which runs your application inside Docker container is either configured asPORT
property in your.env
configuration file or passed to Docker container via environment variablePORT
. Default port is3000
.
docker run -d -p<port-on-host>:<port-inside-docker-container><your-image-name>
docker run -i -t -p<port-on-host>:<port-inside-docker-container><your-image-name>
docker stop<container-id>
You can get a list of all running Docker container and its ids by following command
docker images
Go to console and press + C at any time.
There are several options to configure your app inside a Docker container
You can use.env
file in project root folder which will be copied inside Docker image. If you want to change a property inside.env
you have to rebuild your Docker image.
You can also change app configuration by passing environment variables viadocker run
option-e
or--env
.
docker run --env DB_HOST=localhost -e DB_PORT=3306
Last but not least you can pass a config file todocker run
.
docker run --env-file ./env.list
env.list
example:
# this is a commentDB_TYPE=mysqlDB_HOST=localhostDB_PORT=3306
Name & Link | Description |
---|---|
Express | Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. |
Microframework | Microframework is a simple tool that allows you to execute your modules in a proper order, helping you to organize bootstrap code in your application. |
TypeDI | Dependency Injection for TypeScript. |
routing-controllers | Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage in Express / Koa using TypeScript and Routing Controllers Framework. |
TypeORM | TypeORM is highly influenced by other ORMs, such as Hibernate, Doctrine and Entity Framework. |
class-validator | Validation made easy using TypeScript decorators. |
class-transformer | Proper decorator-based transformation / serialization / deserialization of plain javascript objects to class constructors |
event-dispatcher | Dispatching and listening for application events in Typescript |
Helmet | Helmet helps you secure your Express apps by setting various HTTP headers. It’s not a silver bullet, but it can help! |
Auth0 API Documentation | Authentification service |
Jest | Delightful JavaScript Testing Library for unit and e2e tests |
supertest | Super-agent driven library for testing node.js HTTP servers using a fluent API |
nock | HTTP mocking and expectations library |
swagger Documentation | API Tool to describe and document your api. |
SQLite Documentation | Getting Started with SQLite3 – Basic Commands. |
GraphQL Documentation | A query language for your API. |
DataLoader Documentation | DataLoader is a generic utility to be used as part of your application's data fetching layer to provide a consistent API over various backends and reduce requests to those backends via batching and caching. |
- Microsoft/TypeScript-Node-Starter - A starter template for TypeScript and Node with a detailed README describing how to use the two together.
- express-graphql-typescript-boilerplate - A starter kit for building amazing GraphQL API's with TypeScript and express by @w3tecch
- aurelia-typescript-boilerplate - An Aurelia starter kit with TypeScript
- Auth0 Mock Server - Useful for e2e testing or faking an oAuth server
About
A delightful way to building a RESTful API with NodeJs & TypeScript by@w3tecch
Topics
Resources
License
Code of conduct
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.