3.3.1 • Published 4 years ago

flyback v3.3.1

Weekly downloads
61
License
MIT
Repository
github
Last release
4 years ago

Flyback

Record, replay and mock HTTP requests. Flyback is a javascript HTTP recorder written in typescript. Can be used as standalone server or http middleware. It is created for use in your integration or e2e tests or running your application against mocked HTTP servers.

npm version CircleCI codecov

Installation

npm i flyback
yarn add flyback

Usage

const { createFlybackMiddleware, FlybackServer, RecordModes } = require("flyback");

const options = {
    proxyUrl: "https://api.service.com/v3/",
    recordMode: RecordModes.NEW,
    silent: true,
    summary: false,
    path: "./tapes",
    tapeFileExtension: 'json5'
};

const server = new FlybackServer(opts);

server.start();

// or

const middleware = createFlybackMiddleware(options);

Options:

NameTypeDescriptionDefault
proxyUrlStringWhere to proxy unknown requests
flybackUrlStringWhere to serve flyback server (ignored for middleware)http://localhost:8080
tapesPathStringPath where to load and save tapesundefined
recordModeRecordMode \| FunctionSet record mode. More infoRecordMode.NEW
fallbackModeFallbackMode \| FunctionFallback mode for unknown requests when recording is disabled. More infoFallbackMode.NOT_FOUND
tapeNameGeneratorFunctionCustomize how a tape file name is generated for new tapes.null
tapePathGeneratorFunctionCustomize how a tape file path (to directory) is generated for new tapes.null
tapeFileExtensionStringTape file extension.json
httpsObjectHTTPS cert options options used to create https server in FlybackServernull
agenthttps.Agenthttps.Agent for node-fetch to make requests to proxyUrl
ignoreQueryParams[String]Query params to ignore when matching tapes. Useful when having dynamic query params like timestamps[]
ignoreAllQueryParamsBooleanIgnore all query params when matching tapes.['content-length', 'host]
checkHeaders[String]List of headers to check when matching tapes. Other headers are ignored. Useful when you want to check specific headers['x-user-role', 'host']
ignoreHeaders[String]List of headers to ignore when matching tapes. Useful when having dynamic headers like cookies or correlation ids['content-length', 'host']
ignoreAllHeaders[String]List of headers to ignore when matching tapes. Useful when having dynamic headers like cookies or correlation ids['content-length', 'host']
ignoreBodyBooleanShould the request body be ignored when matching tapesfalse
tapeMatcherFunctionCustomize how a request's body is matched against saved tapes. More infonull
tapeDecoratorFunctionDecorate tapes when they are created. More infonull
summaryBooleanEnable exit summary of new and unused tapes at exit. Printed when flyback server stoppped More infotrue
verboseBooleanEnable requests information printingfalse
debugBooleanEnable debug informationfalse

HTTPS options

NameTypeDescriptionDefault
keyPathStringPath to the key filenull
certPathStringPath to the cert filenull

Api

FlybackServer(options)

deprecated, will be removed in 4.0 returns server instance that can be started and closed

start(callback)

Starts the HTTP server.

close(callback)

Stops the HTTP server.

createFlybackMiddleware(options)

returns node middleware

createFlybackServer(options)

returns FlybackServer instance

create(options)

returns flyback instance with created server, middleware and tape usage statistics

Tapes

Tapes can be freely edited to match new requests or return a different response than the original. They are loaded recursively from the tapesPath directory at startup if specified.

tapesPath can be generated dynamically, you can take it from request header or cookie, it can be used in testing with puppeteer, you can add header with test path, and tapes will be loaded from directory near test files

Format

All tapes have the following 2 properties:

Request: Used to match incoming requests against the tape.

export type RequestJson = {
    pathname: string;
    query?: QueryParamsObject;
    method: string;
    headers: HeadersJson;
    body?: string | Object;
};

Response: The HTTP response that will be returned in case the tape matches a request.

export type ResponseJson = {
   status: number;
   headers: HeadersJson;
   body?: string | Object;
};

You can edit any part of the tape through tapeDecorator option.

Flyback doesn't watch tape files so if you will change them in runtime, changes wont be applied

Tape naming

Tape name by default generated from path, for /api/v3/data you will have api.v3.data.json tape name

Tapes can be renamed at will, for example to give some meaning to the scenario the tape represents.

If a custom tapeNameGenerator is provided, it will be called to produce an alternate file path under path that can be based on the tape contents. Note that the file extension .json will be appended automatically if need.

Grouping

Tapes with the same paths in directory will be grouped in tape file in case tapes don't match and record mode is NEW or OVERWRITE, tape file consist of tapes, you can edit it as regular tape.

Request and Response body

If the content type of the request or response is considered human readable, the body will be saved in plain text or plain object. It works even in case your content is gzipped or brottlied, it will uncompress your tapes before serialization and compress it before returning matching tape

Otherwise, the body will be saved as a Base64 string, allowing to save binary content.

Pretty Printing

If the request or response have a JSON content-type, their body will be pretty printed as an object in the tape for better readability. Two tapes with json bodies will be compared using deep equal tool, so order of keys in object doesn't matter

Recording Modes

Flyback proxying and recording behavior can be controlled through the recordMode option. This option accepts either one of the possible recording modes to be used for all requests or a function that takes the request as a parameter and returns a valid recording mode. There are 4 possible recording modes:

ValueDescription
NEWIf no tape matches the request, proxy it and save the response to a tape
OVERWRITEAlways proxy the request and save the response to a tape, overwriting any existing one
DISABLEDIf a matching tape exists, return it. Otherwise, don't proxy the request and use fallbackMode for the response
PROXYAlways proxy request and don't save any tapes

The fallbackMode option lets you choose what do you want flyback to do when recording is disabled and an unknown request arrives.

Same as with recordMode, this option accepts either one of the possible modes values to be used for all requests or a function that takes the request as a parameter and returns a mode.

There are 2 possible fallback modes:

ValueDescription
NOT_FOUNDLog an error and return a 404 response
PROXYProxy the request to host and return its response, but don't create a tape

flyback exports constants for the different options values:

const { RecordModes, FallbackModes } = require("flyback")

const opts = {
    record: RecordModes.OVERWRITE,
    fallbackMode: FallbackModes.PROXY
}

Tape matcher

By default, in order for a request to match against a saved tape, both request and tape need to have the exact same body.

There might be cases were this rule is too strict (for example, if your body contains time dependent bits) but enabling ignoreBody is too lax.

flyback lets you pass a custom matching function as the tapeMatcher option.

Example:

const tapeMatcher = (tape: TapeJson, request: RequestJson) => {
	return tape.request.pathname === request.pathname 
			&& tape.request.method === request.method
};

In this case we are matching tapes by their pathname and method

Tape decorator

If you want to change tape content before serializing it or before sending to server you can use the tapeDecorator option.

This can be useful for example if your response needs to contain an ID that gets sent on the request, or if your response has a time dependent field.

The function will receive a copy of the matching tape and it has to return the modified tape. Note that since you're receiving a copy of the matching tape, modifications that you do to it won't persist between different requests.

Example:

We're going to hit an /auth endpoint, and update just the expiration field of the JSON response that was saved in the tape to be a day from now.

const tapeDecorator = (tape: TapeJson) => {
     if (tape.request.headers.date) {
         tape.request.headers.data = new Date().toISOString();
     }
     
     return tape;
};

Inspiration

Talkback

Polly.js

Docker image

You can use docker image with flyback inside

docker pull gzaripov/flyback

provide your configuration file by mounting it into /usr/src/app/flyback-config.js

example of configuration file:

const path = require('path');
const { RecordModes } = require('flyback');

const CERT_PATH = path.resolve(__dirname, './flyback.cert.pem');

module.exports = {
    // use env variables for configuring image
    proxyUrl: process.env.FLYBACK_PROXY_URL,
    flybackUrl: process.env.FLYBACK_SERVER_URL,
    recordMode: RecordModes.DISABLED,
    https: {
        keyPath: CERT_PATH,
        certPath: CERT_PATH
    },
    ignoreAllHeaders: true,
    tapeFileExtension: 'json5'
};

Licence

MIT

3.3.1

4 years ago

3.3.0

4 years ago

3.2.3

5 years ago

3.2.2

5 years ago

3.2.1

5 years ago

3.1.1

5 years ago

3.2.0

5 years ago

3.1.0

5 years ago

3.0.0

5 years ago

2.1.0

5 years ago