mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-27 10:55:55 +08:00
Merge pull request #584 from kevynb/typescript-examples
Add typescript examples for error handling and project structure
This commit is contained in:
@ -8,13 +8,14 @@ Callbacks don’t scale well since most programmers are not familiar with them.
|
||||
|
||||
```javascript
|
||||
return functionA()
|
||||
.then((valueA) => functionB(valueA))
|
||||
.then((valueB) => functionC(valueB))
|
||||
.then((valueC) => functionD(valueC))
|
||||
.then(functionB)
|
||||
.then(functionC)
|
||||
.then(functionD)
|
||||
.catch((err) => logger.error(err))
|
||||
.then(alwaysExecuteThisFunction())
|
||||
.then(alwaysExecuteThisFunction)
|
||||
```
|
||||
|
||||
|
||||
### Code Example - using async/await to catch errors
|
||||
|
||||
```javascript
|
||||
@ -25,7 +26,7 @@ async function executeAsyncTask () {
|
||||
const valueC = await functionC(valueB);
|
||||
return await functionD(valueC);
|
||||
}
|
||||
catch(err) {
|
||||
catch (err) {
|
||||
logger.error(err);
|
||||
} finally {
|
||||
await alwaysExecuteThisFunction();
|
||||
@ -35,6 +36,9 @@ async function executeAsyncTask () {
|
||||
|
||||
### Anti pattern code example – callback style error handling
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
getData(someParameter, function(err, result) {
|
||||
if(err !== null) {
|
||||
@ -45,7 +49,7 @@ getData(someParameter, function(err, result) {
|
||||
getMoreData(b, function(c) {
|
||||
getMoreData(d, function(e) {
|
||||
if(err !== null ) {
|
||||
// you get the idea?
|
||||
// you get the idea?
|
||||
}
|
||||
})
|
||||
});
|
||||
@ -54,6 +58,31 @@ getData(someParameter, function(err, result) {
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
getData(someParameter, function(err: Error | null, resultA: ResultA) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
getMoreData(resultA, function(err: Error | null, resultB: ResultB) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
getMoreData(resultB, function(resultC: ResultC) {
|
||||
getMoreData(resultC, function(err: Error | null, d: ResultD) {
|
||||
if(err !== null) {
|
||||
// you get the idea?
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blog Quote: "We have a problem with promises"
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Typically, most of modern Node.js/Express application code runs within promises – whether within the .then handler, a function callback or in a catch block. Surprisingly, unless a developer remembered to add a .catch clause, errors thrown at these places are not handled by the uncaughtException event-handler and disappear. Recent versions of Node added a warning message when an unhandled rejection pops, though this might help to notice when things go wrong but it's obviously not a proper error handling method. The straightforward solution is to never forget adding .catch clauses within each promise chain call and redirect to a centralized error handler. However, building your error handling strategy only on developer’s discipline is somewhat fragile. Consequently, it’s highly recommended using a graceful fallback and subscribe to `process.on(‘unhandledRejection’, callback)` – this will ensure that any promise error, if not handled locally, will get its treatment.
|
||||
Typically, most of modern Node.js/Express application code runs within promises – whether within the .then handler, a function callback or in a catch block. Surprisingly, unless a developer remembered to add a .catch clause, errors thrown at these places are not handled by the uncaughtException event-handler and disappear. Recent versions of Node added a warning message when an unhandled rejection pops, though this might help to notice when things go wrong but it's obviously not a proper error handling method. The straightforward solution is to never forget adding .catch clauses within each promise chain call and redirect to a centralized error handler. However, building your error handling strategy only on developer’s discipline is somewhat fragile. Consequently, it’s highly recommended using a graceful fallback and subscribe to `process.on('unhandledRejection', callback)` – this will ensure that any promise error, if not handled locally, will get its treatment.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
@ -13,29 +13,54 @@ Typically, most of modern Node.js/Express application code runs within promises
|
||||
```javascript
|
||||
DAL.getUserById(1).then((johnSnow) => {
|
||||
// this error will just vanish
|
||||
if(johnSnow.isAlive == false)
|
||||
if(johnSnow.isAlive === false)
|
||||
throw new Error('ahhhh');
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Code example: Catching unresolved and rejected promises
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
// I just caught an unhandled promise rejection, since we already have fallback handler for unhandled errors (see below), let throw and let him handle that
|
||||
// I just caught an unhandled promise rejection,
|
||||
// since we already have fallback handler for unhandled errors (see below),
|
||||
// let throw and let him handle that
|
||||
throw reason;
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
// I just received an error that was never handled, time to handle it and then decide whether a restart is needed
|
||||
errorManagement.handler.handleError(error);
|
||||
if (!errorManagement.handler.isTrustedError(error))
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
process.on('unhandledRejection', (reason: string, p: Promise<any>) => {
|
||||
// I just caught an unhandled promise rejection,
|
||||
// since we already have fallback handler for unhandled errors (see below),
|
||||
// let throw and let him handle that
|
||||
throw reason;
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (error: Error) => {
|
||||
// I just received an error that was never handled, time to handle it and then decide whether a restart is needed
|
||||
errorManagement.handler.handleError(error);
|
||||
if (!errorManagement.handler.isTrustedError(error))
|
||||
process.exit(1);
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
@ -46,16 +71,16 @@ process.on('uncaughtException', (error) => {
|
||||
> Let’s test your understanding. Which of the following would you expect to print an error to the console?
|
||||
|
||||
```javascript
|
||||
Promise.resolve(‘promised value’).then(() => {
|
||||
throw new Error(‘error’);
|
||||
Promise.resolve('promised value').then(() => {
|
||||
throw new Error('error');
|
||||
});
|
||||
|
||||
Promise.reject(‘error value’).catch(() => {
|
||||
throw new Error(‘error’);
|
||||
Promise.reject('error value').catch(() => {
|
||||
throw new Error('error');
|
||||
});
|
||||
|
||||
new Promise((resolve, reject) => {
|
||||
throw new Error(‘error’);
|
||||
throw new Error('error');
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ Without one dedicated object for error handling, greater are the chances of impo
|
||||
|
||||
### Code Example – a typical error flow
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// DAL layer, we don't handle errors here
|
||||
DB.addDocument(newCustomer, (error, result) => {
|
||||
@ -33,9 +36,46 @@ app.use(async (err, req, res, next) => {
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// DAL layer, we don't handle errors here
|
||||
DB.addDocument(newCustomer, (error: Error, result: Result) => {
|
||||
if (error)
|
||||
throw new Error("Great error explanation comes here", other useful parameters)
|
||||
});
|
||||
|
||||
// API route code, we catch both sync and async errors and forward to the middleware
|
||||
try {
|
||||
customerService.addNew(req.body).then((result: Result) => {
|
||||
res.status(200).json(result);
|
||||
}).catch((error: Error) => {
|
||||
next(error)
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Code example – handling errors within a dedicated object
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
module.exports.handler = new errorHandler();
|
||||
|
||||
@ -48,9 +88,31 @@ function errorHandler() {
|
||||
};
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
class ErrorHandler {
|
||||
public async handleError(err: Error): Promise<void> {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical();
|
||||
await saveInOpsQueueIfCritical();
|
||||
await determineIfOperationalError();
|
||||
};
|
||||
}
|
||||
|
||||
export const handler = new ErrorHandler();
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Code Example – Anti Pattern: handling errors within the middleware
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
app.use((err, req, res, next) => {
|
||||
@ -63,6 +125,25 @@ app.use((err, req, res, next) => {
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
logger.logError(err);
|
||||
if (err.severity == errors.high) {
|
||||
mailer.sendMail(configuration.adminMail, 'Critical error occured', err);
|
||||
}
|
||||
if (!err.isOperational) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blog Quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller"
|
||||
|
||||
|
||||
@ -22,11 +22,15 @@ function addNewMember(newMember) {
|
||||
Joi.assert(newMember, memberSchema); //throws if validation fails
|
||||
// other logic here
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Anti-pattern: no validation yields nasty bugs
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// if the discount is positive let's then redirect the user to print his discount coupons
|
||||
function redirectToPrintDiscount(httpResponse, member, discount) {
|
||||
@ -37,8 +41,24 @@ function redirectToPrintDiscount(httpResponse, member, discount) {
|
||||
|
||||
redirectToPrintDiscount(httpResponse, someMember);
|
||||
// forgot to pass the parameter discount, why the heck was the user redirected to the discount screen?
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// if the discount is positive let's then redirect the user to print his discount coupons
|
||||
function redirectToPrintDiscount(httpResponse: Response, member: Member, discount: number) {
|
||||
if (discount != 0) {
|
||||
httpResponse.redirect(`/discountPrintView/${member.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
redirectToPrintDiscount(httpResponse, someMember, -12);
|
||||
// We passed a negative parameter discount, why the heck was the user redirected to the discount screen?
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blog Quote: "You should throw these errors immediately"
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ Distinguishing the following two error types will minimize your app downtime and
|
||||
|
||||
### Code Example – marking an error as operational (trusted)
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// marking an error object as operational
|
||||
const myError = new Error("How can I add new product when no value provided?");
|
||||
@ -25,6 +28,34 @@ class AppError {
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
|
||||
export class AppError extends Error {
|
||||
public readonly commonType: string;
|
||||
public readonly isOperational: boolean;
|
||||
|
||||
constructor(commonType: string, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
|
||||
this.commonType = commonType;
|
||||
this.isOperational = isOperational;
|
||||
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
// marking an error object as operational (true)
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blog Quote: "Programmer errors are bugs in the program"
|
||||
|
||||
|
||||
@ -6,12 +6,15 @@ Somewhere within your code, an error handler object is responsible for deciding
|
||||
|
||||
### Code example: deciding whether to crash
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
|
||||
process.on('uncaughtException', function(error) {
|
||||
errorManagement.handler.handleError(error);
|
||||
if(!errorManagement.handler.isTrustedError(error))
|
||||
process.exit(1)
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
// centralized error handler encapsulates error-handling related logic
|
||||
@ -28,6 +31,51 @@ function errorHandler() {
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
|
||||
process.on('uncaughtException', (error: Error) => {
|
||||
errorManagement.handler.handleError(error);
|
||||
if(!errorManagement.handler.isTrustedError(error))
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
// centralized error object that derives from Node’s Error
|
||||
export class AppError extends Error {
|
||||
public readonly isOperational: boolean;
|
||||
|
||||
constructor(description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
this.isOperational = isOperational;
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
// centralized error handler encapsulates error-handling related logic
|
||||
class ErrorHandler {
|
||||
public async handleError(err: Error): Promise<void> {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical();
|
||||
await saveInOpsQueueIfCritical();
|
||||
await determineIfOperationalError();
|
||||
};
|
||||
|
||||
public isTrustedError(error: Error) {
|
||||
if (error instanceof AppError) {
|
||||
return error.isOperational;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const handler = new ErrorHandler();
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blog Quote: "The best way is to crash"
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ Testing ‘happy’ paths is no better than testing failures. Good testing code
|
||||
|
||||
### Code example: ensuring the right exception is thrown using Mocha & Chai
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
describe("Facebook chat", () => {
|
||||
it("Notifies on new chat message", () => {
|
||||
@ -14,13 +17,30 @@ describe("Facebook chat", () => {
|
||||
expect(chatService.sendMessage.bind({ message: "Hi" })).to.throw(ConnectionError);
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
describe("Facebook chat", () => {
|
||||
it("Notifies on new chat message", () => {
|
||||
const chatService = new chatService();
|
||||
chatService.participants = getDisconnectedParticipants();
|
||||
expect(chatService.sendMessage.bind({ message: "Hi" })).to.throw(ConnectionError);
|
||||
});
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
### Code example: ensuring API returns the right HTTP error code
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
it("Creates new Facebook group", function (done) {
|
||||
it("Creates new Facebook group", (done) => {
|
||||
var invalidGroupInfo = {};
|
||||
httpRequest({
|
||||
method: 'POST',
|
||||
@ -30,9 +50,33 @@ it("Creates new Facebook group", function (done) {
|
||||
json: true
|
||||
}).then((response) => {
|
||||
// if we were to execute the code in this block, no error was thrown in the operation above
|
||||
}).catch(function (response) {
|
||||
}).catch((response) => {
|
||||
expect(400).to.equal(response.statusCode);
|
||||
done();
|
||||
});
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
it("Creates new Facebook group", async () => {
|
||||
let invalidGroupInfo = {};
|
||||
try {
|
||||
const response = await httpRequest({
|
||||
method: 'POST',
|
||||
uri: "facebook.com/api/groups",
|
||||
resolveWithFullResponse: true,
|
||||
body: invalidGroupInfo,
|
||||
json: true
|
||||
})
|
||||
// if we were to execute the code in this block, no error was thrown in the operation above
|
||||
expect.fail('The request should have failed')
|
||||
} catch(response) {
|
||||
expect(400).to.equal(response.statusCode);
|
||||
}
|
||||
});
|
||||
```
|
||||
</details>
|
||||
@ -11,7 +11,7 @@ We all love console.log but obviously, a reputable and persistent logger like [W
|
||||
|
||||
```javascript
|
||||
// your centralized logger object
|
||||
var logger = new winston.Logger({
|
||||
const logger = new winston.Logger({
|
||||
level: 'info',
|
||||
transports: [
|
||||
new (winston.transports.Console)()
|
||||
@ -20,22 +20,20 @@ var logger = new winston.Logger({
|
||||
|
||||
// custom code somewhere using the logger
|
||||
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });
|
||||
|
||||
```
|
||||
|
||||
### Code Example – Querying the log folder (searching for entries)
|
||||
|
||||
```javascript
|
||||
var options = {
|
||||
from: new Date - 24 * 60 * 60 * 1000,
|
||||
until: new Date,
|
||||
const options = {
|
||||
from: Date.now() - 24 * 60 * 60 * 1000,
|
||||
until: new Date(),
|
||||
limit: 10,
|
||||
start: 0,
|
||||
order: 'desc',
|
||||
fields: ['message']
|
||||
};
|
||||
|
||||
|
||||
// Find items logged between today and yesterday.
|
||||
winston.query(options, function (err, results) {
|
||||
// execute callback with results
|
||||
|
||||
@ -38,6 +38,9 @@ if(!productToAdd)
|
||||
|
||||
### Code example – doing it even better
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// centralized error object that derives from Node’s Error
|
||||
function AppError(name, httpCode, description, isOperational) {
|
||||
@ -55,6 +58,38 @@ module.exports.AppError = AppError;
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, "further explanation", true)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// centralized error object that derives from Node’s Error
|
||||
export class AppError extends Error {
|
||||
public readonly name: string;
|
||||
public readonly httpCode: HttpCode;
|
||||
public readonly isOperational: boolean;
|
||||
|
||||
constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
|
||||
this.name = name;
|
||||
this.httpCode = httpCode;
|
||||
this.isOperational = isOperational;
|
||||
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
// client throwing an exception
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, "further explanation", true)
|
||||
```
|
||||
</details>
|
||||
|
||||
*Explanation about the `Object.setPrototypeOf` in Typescript: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget*
|
||||
|
||||
### Blog Quote: "I don’t see the value in having lots of different types"
|
||||
|
||||
|
||||
@ -8,39 +8,54 @@ The latest Express generator comes with a great practice that is worth to keep -
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Code example: API declaration, should reside in app.js
|
||||
### Code example: API declaration, should reside in app.js/app.ts
|
||||
|
||||
```javascript
|
||||
var app = express();
|
||||
const app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.use("/api/events", events.API);
|
||||
app.use("/api/forms", forms);
|
||||
```
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Code example: Server network declaration, should reside in /bin/www
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
var app = require('../app');
|
||||
var http = require('http');
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
|
||||
// Get port from environment and store in Express.
|
||||
var port = normalizePort(process.env.PORT || '3000');
|
||||
app.set('port', port);
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
*/
|
||||
|
||||
// Create HTTP server.
|
||||
var server = http.createServer(app);
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
import app from '../app';
|
||||
import http from 'http';
|
||||
|
||||
// Get port from environment and store in Express.
|
||||
const port = normalizePort(process.env.PORT || '3000');
|
||||
app.set('port', port);
|
||||
|
||||
// Create HTTP server.
|
||||
const server = http.createServer(app);
|
||||
```
|
||||
</details>
|
||||
|
||||
### Example: test your API in-process using supertest (popular testing package)
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
const app = express();
|
||||
|
||||
@ -56,4 +71,28 @@ request(app)
|
||||
.end(function(err, res) {
|
||||
if (err) throw err;
|
||||
});
|
||||
````
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
const app = express();
|
||||
|
||||
app.get('/user', (req: Request, res: Response) => {
|
||||
res.status(200).json({ name: 'tobi' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Content-Length', '15')
|
||||
.expect(200)
|
||||
.end((err: Error) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
|
||||
```
|
||||
</details>
|
||||
Reference in New Issue
Block a user