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 support for custom id generation #69

Merged
merged 9 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 27 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const data = {
preferred_format: 'hardback',
}
};
const restServer = new FakeRest.FetchServer('http://localhost:3000');
const restServer = new FakeRest.FetchServer({ 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.Server({ 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.Server({ 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 another type of identifiers (e.g. UUIDs), you can provide your own `getNewId` function at the server level:

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

const restServer = new FakeRest.Server({ 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.Server({ 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` Takes 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
33 changes: 26 additions & 7 deletions src/BaseServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ export class BaseServer {
batchUrl: string | null = null;
collections: Record<string, Collection<any>> = {};
singles: Record<string, Single<any>> = {};
getNewId?: () => number | string;

constructor(baseUrl = '') {
constructor({
baseUrl = '',
getNewId,
}: {
baseUrl?: string;
getNewId?: () => number | string;
} = {}) {
this.baseUrl = baseUrl;
this.getNewId = getNewId;
}

/**
Expand All @@ -21,7 +29,14 @@ export class BaseServer {
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: 'id',
getNewId: this.getNewId,
}),
);
} else {
this.addSingle(name, new Single(value));
}
Expand Down Expand Up @@ -103,25 +118,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 +224,7 @@ export class BaseServer {

// handle collections
const matches = request.url?.match(
new RegExp(`^${this.baseUrl}\\/([^\\/?]+)(\\/(\\d+))?(\\?.*)?$`),
new RegExp(`^${this.baseUrl}\\/([^\\/?]+)(\\/(\\w))?(\\?.*)?$`),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid this may break things

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't noticed any and I don't see any other way to support custom ids

);
if (!matches) {
return { status: 404, headers: {} };
Expand Down
Loading
Loading