Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor interceptors as middlewares #72

Merged
merged 34 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
fda6faf
Refactor interceptors as middlewares
djhi Jun 3, 2024
c0c6b61
Fix Sinon
djhi Jun 3, 2024
af6b6e7
Rename BaseServer classes
djhi Jun 3, 2024
9096436
Add comment
djhi Jun 3, 2024
b1a0a00
Cleanup types
djhi Jun 4, 2024
5570922
Add withDelay middleware
djhi Jun 4, 2024
7e8e47e
Fix Sinon integration
djhi Jun 4, 2024
7b97ff8
Fix SinonServer tests
djhi Jun 4, 2024
a8d3050
Fix build
djhi Jun 5, 2024
d80d993
Update Upgrade Guide
djhi Jun 5, 2024
875b676
Fix upgrade guide
djhi Jun 6, 2024
d9a4982
Remove unnecessary sinon html file
djhi Jun 6, 2024
9ed57ce
Use FetchMockServer in example
djhi Jun 6, 2024
cb8e5f1
Refactor
djhi Jun 6, 2024
46a7912
Make msw example less verbose
djhi Jun 6, 2024
1ce980d
Remove debug code
djhi Jun 6, 2024
6d39911
Simplify sinon example
djhi Jun 6, 2024
e2f4c19
Better server side validation
djhi Jun 6, 2024
3c655d1
Remove unnecessary types
djhi Jun 6, 2024
8662b5e
Make sinon async compatible
djhi Jun 6, 2024
c59cce2
Reorganize tests
djhi Jun 6, 2024
7e883eb
Apply review suggestions
djhi Jun 6, 2024
0007f7b
Rename requestJson to requestBody
djhi Jun 6, 2024
f96e328
Update comments and readme
djhi Jun 6, 2024
b46a393
Simplify and document MSW
djhi Jun 6, 2024
6628014
Rewrite documentation
djhi Jun 6, 2024
a98bedd
Update documentation
djhi Jun 6, 2024
daf48e4
Don't extend Database
djhi Jun 6, 2024
55c76cb
Revert unnecessary changes
djhi Jun 6, 2024
f1c7732
Fix examples middlewares
djhi Jun 6, 2024
e0f62b9
Fix exports
djhi Jun 6, 2024
e993351
Add configuration section in docs
djhi Jun 6, 2024
f6ef7c2
Add concepts
djhi Jun 6, 2024
075ef27
Merge branch 'master' into refactor-interceptors
fzaninotto Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 75 additions & 29 deletions src/BaseServer.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import type { Collection } from './Collection.js';
import { Database, type DatabaseOptions } from './Database.js';
import type { QueryFunction } from './types.js';
import type { Single } from './Single.js';
import type { CollectionItem, QueryFunction } from './types.js';

export class BaseServer<RequestType, ResponseType> extends Database {
export class BaseServer<RequestType, ResponseType> {
baseUrl = '';
defaultQuery: QueryFunction = () => ({});
middlewares: Array<Middleware<RequestType>> = [];
database: Database;

constructor({
baseUrl = '',
defaultQuery = () => ({}),
database,
...options
}: BaseServerOptions = {}) {
super(options);
this.baseUrl = baseUrl;
this.defaultQuery = defaultQuery;

if (database) {
this.database = database;
} else {
this.database = new Database(options);
}
}

/**
Expand All @@ -23,13 +32,8 @@ export class BaseServer<RequestType, ResponseType> extends Database {
this.defaultQuery = query;
}

getContext(
context: Pick<
FakeRestContext,
'url' | 'method' | 'params' | 'requestBody'
>,
): FakeRestContext {
for (const name of this.getSingleNames()) {
getContext(context: NormalizedRequest): FakeRestContext {
for (const name of this.database.getSingleNames()) {
const matches = context.url?.match(
new RegExp(`^${this.baseUrl}\\/(${name})(\\/?.*)?$`),
);
Expand Down Expand Up @@ -61,11 +65,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {
return context;
}

getNormalizedRequest(
request: RequestType,
): Promise<
Pick<FakeRestContext, 'url' | 'method' | 'params' | 'requestBody'>
> {
getNormalizedRequest(request: RequestType): Promise<NormalizedRequest> {
throw new Error('Not implemented');
}

Expand Down Expand Up @@ -111,7 +111,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {

handleRequest(request: RequestType, ctx: FakeRestContext): BaseResponse {
// Handle Single Objects
for (const name of this.getSingleNames()) {
for (const name of this.database.getSingleNames()) {
const matches = ctx.url?.match(
new RegExp(`^${this.baseUrl}\\/(${name})(\\/?.*)?$`),
);
Expand All @@ -121,7 +121,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {
try {
return {
status: 200,
body: this.getOnly(name),
body: this.database.getOnly(name),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -143,7 +143,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {
}
return {
status: 200,
body: this.updateOnly(name, ctx.requestBody),
body: this.database.updateOnly(name, ctx.requestBody),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -165,7 +165,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {
}
return {
status: 200,
body: this.updateOnly(name, ctx.requestBody),
body: this.database.updateOnly(name, ctx.requestBody),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -190,15 +190,15 @@ export class BaseServer<RequestType, ResponseType> extends Database {
const params = Object.assign({}, this.defaultQuery(name), ctx.params);
if (!matches[2]) {
if (ctx.method === 'GET') {
if (!this.getCollection(name)) {
if (!this.database.getCollection(name)) {
return { status: 404, headers: {} };
}
const count = this.getCount(
const count = this.database.getCount(
name,
params.filter ? { filter: params.filter } : {},
);
if (count > 0) {
const items = this.getAll(name, params);
const items = this.database.getAll(name, params);
const first = params.range ? params.range[0] : 0;
const last =
params.range && params.range.length === 2
Expand Down Expand Up @@ -235,9 +235,11 @@ export class BaseServer<RequestType, ResponseType> extends Database {
};
}

const newResource = this.addOne(name, ctx.requestBody);
const newResource = this.database.addOne(name, ctx.requestBody);
const newResourceURI = `${this.baseUrl}/${name}/${
newResource[this.getCollection(name).identifierName]
newResource[
this.database.getCollection(name).identifierName
]
}`;

return {
Expand All @@ -250,15 +252,15 @@ export class BaseServer<RequestType, ResponseType> extends Database {
};
}
} else {
if (!this.getCollection(name)) {
if (!this.database.getCollection(name)) {
return { status: 404, headers: {} };
}
const id = Number.parseInt(matches[3]);
if (ctx.method === 'GET') {
try {
return {
status: 200,
body: this.getOne(name, id, params),
body: this.database.getOne(name, id, params),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -280,7 +282,11 @@ export class BaseServer<RequestType, ResponseType> extends Database {
}
return {
status: 200,
body: this.updateOne(name, id, ctx.requestBody),
body: this.database.updateOne(
name,
id,
ctx.requestBody,
),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -302,7 +308,11 @@ export class BaseServer<RequestType, ResponseType> extends Database {
}
return {
status: 200,
body: this.updateOne(name, id, ctx.requestBody),
body: this.database.updateOne(
name,
id,
ctx.requestBody,
),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -318,7 +328,7 @@ export class BaseServer<RequestType, ResponseType> extends Database {
try {
return {
status: 200,
body: this.removeOne(name, id),
body: this.database.removeOne(name, id),
headers: {
'Content-Type': 'application/json',
},
Expand All @@ -340,6 +350,36 @@ export class BaseServer<RequestType, ResponseType> extends Database {
addMiddleware(middleware: Middleware<RequestType>) {
this.middlewares.push(middleware);
}

addCollection<T extends CollectionItem = CollectionItem>(
name: string,
collection: Collection<T>,
) {
this.database.addCollection(name, collection);
}

getCollection(name: string) {
return this.database.getCollection(name);
}

getCollectionNames() {
return this.database.getCollectionNames();
}

addSingle<T extends CollectionItem = CollectionItem>(
name: string,
single: Single<T>,
) {
this.database.addSingle(name, single);
}

getSingle(name: string) {
return this.database.getSingle(name);
}

getSingleNames() {
return this.database.getSingleNames();
}
}

export type Middleware<RequestType> = (
Expand All @@ -352,6 +392,7 @@ export type Middleware<RequestType> = (
) => Promise<BaseResponse | null> | BaseResponse | null;

export type BaseServerOptions = DatabaseOptions & {
database?: Database;
baseUrl?: string;
batchUrl?: string | null;
defaultQuery?: QueryFunction;
Expand All @@ -371,3 +412,8 @@ export type FakeRestContext = {
requestBody: Record<string, any> | undefined;
params: { [key: string]: any };
};

export type NormalizedRequest = Pick<
FakeRestContext,
'url' | 'method' | 'params' | 'requestBody'
>;
48 changes: 24 additions & 24 deletions src/Collection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection } from './Collection.js';
import { Server } from './adapters/SinonServer.js';
import { Database } from './Database.js';
import type { CollectionItem } from './types.js';

describe('Collection', () => {
Expand Down Expand Up @@ -627,8 +627,8 @@ describe('Collection', () => {
const foos = new Collection({
items: [{ name: 'John', bar_id: 123 }],
});
const server = new Server();
server.addCollection('foos', foos);
const database = new Database();
database.addCollection('foos', foos);
expect(() => {
foos.getAll({ embed: ['bar'] });
}).toThrow(
Expand All @@ -641,9 +641,9 @@ describe('Collection', () => {
items: [{ name: 'John', bar_id: 123 }],
});
const bars = new Collection({ items: [] });
const server = new Server();
server.addCollection('foos', foos);
server.addCollection('bars', bars);
const database = new Database();
database.addCollection('foos', foos);
database.addCollection('bars', bars);
const expected = [{ id: 0, name: 'John', bar_id: 123 }];
expect(foos.getAll({ embed: ['bar'] })).toEqual(expected);
});
Expand All @@ -662,9 +662,9 @@ describe('Collection', () => {
{ id: 456, bar: 'bazz' },
],
});
const server = new Server();
server.addCollection('foos', foos);
server.addCollection('bars', bars);
const database = new Database();
database.addCollection('foos', foos);
database.addCollection('bars', bars);
const expected = [
{
id: 0,
Expand All @@ -686,8 +686,8 @@ describe('Collection', () => {
const foos = new Collection({
items: [{ name: 'John', bar_id: 123 }],
});
const server = new Server();
server.addCollection('foos', foos);
const database = new Database();
database.addCollection('foos', foos);
expect(() => {
foos.getAll({ embed: ['bars'] });
}).toThrow(
Expand All @@ -702,9 +702,9 @@ describe('Collection', () => {
const bars = new Collection({
items: [{ id: 1, bar: 'nobody wants me' }],
});
const server = new Server();
server.addCollection('foos', foos);
server.addCollection('bars', bars);
const database = new Database();
database.addCollection('foos', foos);
database.addCollection('bars', bars);
const expected = [{ id: 1, bar: 'nobody wants me', foos: [] }];
expect(bars.getAll({ embed: ['foos'] })).toEqual(expected);
});
Expand All @@ -724,9 +724,9 @@ describe('Collection', () => {
{ id: 456, bar: 'bazz' },
],
});
const server = new Server();
server.addCollection('foos', foos);
server.addCollection('bars', bars);
const database = new Database();
database.addCollection('foos', foos);
database.addCollection('bars', bars);
const expected = [
{ id: 1, bar: 'nobody wants me', foos: [] },
{
Expand Down Expand Up @@ -761,9 +761,9 @@ describe('Collection', () => {
{ id: 456, bar: 'bazz', foos: [2, 3] },
],
});
const server = new Server();
server.addCollection('foos', foos);
server.addCollection('bars', bars);
const database = new Database();
database.addCollection('foos', foos);
database.addCollection('bars', bars);
const expected = [
{ id: 1, bar: 'nobody wants me', foos: [] },
{ id: 123, bar: 'baz', foos: [{ id: 1, name: 'John' }] },
Expand Down Expand Up @@ -809,10 +809,10 @@ describe('Collection', () => {
{ id: 2, name: 'Russia' },
],
});
const server = new Server();
server.addCollection('books', books);
server.addCollection('authors', authors);
server.addCollection('countrys', countries); // nevermind the plural
const database = new Database();
database.addCollection('books', books);
database.addCollection('authors', authors);
database.addCollection('countrys', countries); // nevermind the plural
const expected = [
{
id: 1,
Expand Down
Loading
Loading