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

Add more parameters to BaseServer #70

Merged
merged 11 commits into from
Jun 4, 2024
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ var data = {
}
};
// initialize fake REST server
var restServer = new FakeRest.Server();
var restServer = new FakeRest.SinonServer();
restServer.init(data);

// use sinon.js to monkey-patch XmlHttpRequest
Expand Down Expand Up @@ -111,7 +111,7 @@ const data = {
preferred_format: 'hardback',
}
};
const restServer = new FakeRest.FetchServer('http://localhost:3000');
const restServer = new FakeRest.FetchMockServer({ baseUrl: 'http://localhost:3000' });
restServer.init(data);
fetchMock.mock('begin:http://localhost:3000', restServer.getHandler());
```
Expand Down Expand Up @@ -366,7 +366,7 @@ Operators are specified as suffixes on each filtered field. For instance, applyi

```js
// initialize a rest server with a custom base URL
var restServer = new FakeRest.Server('http://my.custom.domain'); // // only URLs starting with my.custom.domain will be intercepted
const restServer = new FakeRest.SinonServer({ baseUrl: 'http://my.custom.domain' }); // only URLs starting with my.custom.domain will be intercepted
restServer.toggleLogging(); // logging is off by default, enable it to see network calls in the console
// Set all JSON data at once - only if identifier name is 'id'
restServer.init(json);
Expand Down Expand Up @@ -406,24 +406,45 @@ restServer.setDefaultQuery(function(resourceName) {
restServer.setBatchUrl('/batch');

// you can create more than one fake server to listen to several domains
var restServer2 = new FakeRest.Server('http://my.other.domain');
const restServer2 = new FakeRest.SinonServer({ baseUrl: 'http://my.other.domain' });
// Set data collection by collection - allows to customize the identifier name
var authorsCollection = new FakeRest.Collection([], '_id');
const authorsCollection = new FakeRest.Collection({ items: [], identifierName: '_id' });
authorsCollection.addOne({ first_name: 'Leo', last_name: 'Tolstoi' }); // { _id: 0, first_name: 'Leo', last_name: 'Tolstoi' }
authorsCollection.addOne({ first_name: 'Jane', last_name: 'Austen' }); // { _id: 1, first_name: 'Jane', last_name: 'Austen' }
// collections have autoincremented identifier but accept identifiers already set
// collections have auto incremented identifiers by default but accept identifiers already set
authorsCollection.addOne({ _id: 3, first_name: 'Marcel', last_name: 'Proust' }); // { _id: 3, first_name: 'Marcel', last_name: 'Proust' }
restServer2.addCollection('authors', authorsCollection);
// collections are mutable
authorsCollection.updateOne(1, { last_name: 'Doe' }); // { _id: 1, first_name: 'Jane', last_name: 'Doe' }
authorsCollection.removeOne(3); // { _id: 3, first_name: 'Marcel', last_name: 'Proust' }

var server = sinon.fakeServer.create();
const server = sinon.fakeServer.create();
server.autoRespond = true;
server.respondWith(restServer.getHandler());
server.respondWith(restServer2.getHandler());
```

## Configure Identifiers Generation

By default, FakeRest uses an auto incremented sequence for the items identifiers. If you'd rather use UUIDs for instance but would like to avoid providing them when you insert new items, you can provide your own function:

```js
import FakeRest from 'fakerest';
import uuid from 'uuid';

const restServer = new FakeRest.SinonServer({ baseUrl: 'http://my.custom.domain', getNewId: () => uuid.v5() });
```

This can also be specified at the collection level:

```js
import FakeRest from 'fakerest';
import uuid from 'uuid';

const restServer = new FakeRest.SinonServer({ baseUrl: 'http://my.custom.domain' });
const authorsCollection = new FakeRest.Collection({ items: [], identifierName: '_id', getNewId: () => uuid.v5() });
```

## Development

```sh
Expand Down
42 changes: 42 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Upgrading to 4.0.0

## Constructors Of `FetchServer` and `Server` Take An Object

For `Server`:

```diff
import { Server } from 'fakerest';
import { data } from './data';

-const server = new Server('http://myapi.com');
+const server = new Server({ baseUrl: 'http://myapi.com' });
server.init(data);
```

For `FetchServer`:

```diff
import { FetchServer } from 'fakerest';
import { data } from './data';

-const server = new FetchServer('http://myapi.com');
+const server = new FetchServer({ baseUrl: 'http://myapi.com' });
server.init(data);
```

## Constructor Of `Collection` Take An Object

```diff
-const posts = new Collection([
- { id: 1, title: 'baz' },
- { id: 2, title: 'biz' },
- { id: 3, title: 'boz' },
-]);
+const posts = new Collection({
+ items: [
+ { id: 1, title: 'baz' },
+ { id: 2, title: 'biz' },
+ { id: 3, title: 'boz' },
+ ],
+});
```
35 changes: 32 additions & 3 deletions example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
import React from 'react';
import { Admin, ListGuesser, Resource } from 'react-admin';
import {
Admin,
Create,
EditGuesser,
ListGuesser,
Resource,
ShowGuesser,
} from 'react-admin';
import { dataProvider } from './dataProvider';

export const App = () => {
return (
<Admin dataProvider={dataProvider}>
<Resource name="books" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
<Resource
name="books"
list={ListGuesser}
create={BookCreate}
edit={EditGuesser}
show={ShowGuesser}
/>
<Resource
name="authors"
list={ListGuesser}
edit={EditGuesser}
show={ShowGuesser}
/>
</Admin>
);
};

import { Edit, ReferenceInput, SimpleForm, TextInput } from 'react-admin';

export const BookCreate = () => (
<Create>
<SimpleForm>
<ReferenceInput source="author_id" reference="authors" />
<TextInput source="title" />
</SimpleForm>
</Create>
);
4 changes: 3 additions & 1 deletion example/fetchMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import FakeRest from 'fakerest';
import { data } from './data';

export const initializeFetchMock = () => {
const restServer = new FakeRest.FetchServer('http://localhost:3000');
const restServer = new FakeRest.FetchServer({
baseUrl: 'http://localhost:3000',
});
if (window) {
// @ts-ignore
window.restServer = restServer; // give way to update data in the console
Expand Down
54 changes: 46 additions & 8 deletions src/BaseServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,58 @@ import type { CollectionItem, Query, QueryFunction } from './types.js';

export class BaseServer {
baseUrl: string | null = null;
identifierName = 'id';
loggingEnabled = false;
defaultQuery: QueryFunction = () => ({});
batchUrl: string | null = null;
collections: Record<string, Collection<any>> = {};
singles: Record<string, Single<any>> = {};
getNewId?: () => number | string;

constructor(baseUrl = '') {
constructor({
baseUrl = '',
batchUrl = null,
data,
defaultQuery = () => ({}),
identifierName = 'id',
getNewId,
loggingEnabled = false,
}: {
baseUrl?: string;
batchUrl?: string | null;
data?: Record<string, CollectionItem[] | CollectionItem>;
defaultQuery?: QueryFunction;
identifierName?: string;
getNewId?: () => number | string;
loggingEnabled?: boolean;
} = {}) {
this.baseUrl = baseUrl;
this.batchUrl = batchUrl;
this.getNewId = getNewId;
this.loggingEnabled = loggingEnabled;
this.identifierName = identifierName;
this.defaultQuery = defaultQuery;

if (data) {
this.init(data);
}
}

/**
* Shortcut for adding several collections if identifierName is always 'id'
* Shortcut for adding several collections if identifierName is always the same
*/
init(data: Record<string, CollectionItem[] | CollectionItem>) {
for (const name in data) {
const value = data[name];
if (Array.isArray(value)) {
this.addCollection(name, new Collection(value, 'id'));
this.addCollection(
name,
new Collection({
items: value,
identifierName: this.identifierName,
getNewId: this.getNewId,
}),
);
} else {
this.addSingle(name, new Single(value));
}
Expand Down Expand Up @@ -103,25 +137,29 @@ export class BaseServer {
return this.collections[name].getAll(params);
}

getOne(name: string, identifier: number, params?: Query) {
getOne(name: string, identifier: string | number, params?: Query) {
return this.collections[name].getOne(identifier, params);
}

addOne(name: string, item: CollectionItem) {
if (!Object.prototype.hasOwnProperty.call(this.collections, name)) {
this.addCollection(
name,
new Collection([] as CollectionItem[], 'id'),
new Collection({
items: [],
identifierName: 'id',
getNewId: this.getNewId,
}),
);
}
return this.collections[name].addOne(item);
}

updateOne(name: string, identifier: number, item: CollectionItem) {
updateOne(name: string, identifier: string | number, item: CollectionItem) {
return this.collections[name].updateOne(identifier, item);
}

removeOne(name: string, identifier: number) {
removeOne(name: string, identifier: string | number) {
return this.collections[name].removeOne(identifier);
}

Expand Down Expand Up @@ -205,7 +243,7 @@ export class BaseServer {

// handle collections
const matches = request.url?.match(
new RegExp(`^${this.baseUrl}\\/([^\\/?]+)(\\/(\\d+))?(\\?.*)?$`),
new RegExp(`^${this.baseUrl}\\/([^\\/?]+)(\\/(\\w))?(\\?.*)?$`),
);
if (!matches) {
return { status: 404, headers: {} };
Expand Down
Loading
Loading