Skip to content

Commit

Permalink
enhance: Resource uses endpoint (#365)
Browse files Browse the repository at this point in the history
- Resource.listShape() -> Resource.list() (only deprecation)
- rest-hooks & @rest-hooks/core both export @rest-hooks/endpoint members

BREAKING CHANGE: getFetchOptions() -> getEndpointExtra()
  • Loading branch information
ntucker committed Jul 14, 2020
1 parent d0ab945 commit 4472106
Show file tree
Hide file tree
Showing 50 changed files with 656 additions and 649 deletions.
21 changes: 10 additions & 11 deletions __tests__/common.ts
Expand Up @@ -7,11 +7,10 @@ import {
} from 'rest-hooks';
import {
AbstractInstanceType,
FetchOptions,
MutateShape,
SimpleRecord,
} from '@rest-hooks/core';
import { Endpoint } from '@rest-hooks/endpoint';
import { Endpoint, EndpointExtraOptions } from '@rest-hooks/endpoint';
import React from 'react';

export class UserResource extends Resource {
Expand Down Expand Up @@ -113,7 +112,7 @@ export class ArticleResource extends Resource {
return {
...super.partialUpdateShape(),
options: {
...this.getFetchOptions(),
...this.getEndpointExtra(),
optimisticUpdate: (params: any, body: any) => ({
id: params.id,
...body,
Expand All @@ -128,7 +127,7 @@ export class ArticleResource extends Resource {
return {
...(super.deleteShape() as any),
options: {
...this.getFetchOptions(),
...this.getEndpointExtra(),
optimisticUpdate: (params: any, _body: any) => params,
},
};
Expand Down Expand Up @@ -173,7 +172,7 @@ export class ArticleResourceWithOtherListUrl extends ArticleResource {
return {
...super.createShape(),
options: {
...this.getFetchOptions(),
...this.getEndpointExtra(),
optimisticUpdate: (
params: Readonly<object>,
body: Readonly<object | string> | void,
Expand Down Expand Up @@ -203,9 +202,9 @@ export class IndexedUserResource extends UserResource {
}

export class InvalidIfStaleArticleResource extends CoolerArticleResource {
static getFetchOptions(): FetchOptions {
static getEndpointExtra(): EndpointExtraOptions {
return {
...super.getFetchOptions(),
...super.getEndpointExtra(),
dataExpiryLength: 5000,
errorExpiryLength: 5000,
invalidIfStale: true,
Expand All @@ -214,9 +213,9 @@ export class InvalidIfStaleArticleResource extends CoolerArticleResource {
}

export class PollingArticleResource extends ArticleResource {
static getFetchOptions(): FetchOptions {
static getEndpointExtra(): EndpointExtraOptions {
return {
...super.getFetchOptions(),
...super.getEndpointExtra(),
pollFrequency: 5000,
};
}
Expand All @@ -236,9 +235,9 @@ export class PollingArticleResource extends ArticleResource {
export class StaticArticleResource extends ArticleResource {
static urlRoot = 'http://test.com/article-static/';

static getFetchOptions() {
static EndpointExtraOptions() {
return {
...super.getFetchOptions(),
...super.getEndpointExtra(),
dataExpiryLength: Infinity,
};
}
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Expand Up @@ -6,7 +6,7 @@
## 💬 API

- [Resource](api/Resource.md)
- [FetchShape](api/FetchShape.md)
- [Endpoint](api/Endpoint.md)
- Hooks:
- [useResource](api/useResource.md)
- [useFetcher](api/useFetcher.md)
Expand Down
95 changes: 80 additions & 15 deletions docs/api/Endpoint.md
Expand Up @@ -2,8 +2,14 @@
title: Endpoint
---

Endpoint defines a standard interface that describes the nature of an networking endpoint.
It is both strongly typed, and encapsulates runtime-relevant information.

<!--DOCUSAURUS_CODE_TABS-->
<!--Interface-->

```typescript
interface EndpointInterface {
interface EndpointInterface extends EndpointExtraOptions {
(params?: any, body?: any): Promise<any>;
key(parmas?: any): string;
schema?: Readonly<S>;
Expand All @@ -12,8 +18,10 @@ interface EndpointInterface {
}
```

<!--Class-->

```typescript
class Endpoint<F extends () => Promise<any>> implements EndpointInterface {
class Endpoint<F extends (...args: any) => Promise<any>> implements EndpointInterface {
constructor(fetchFunction: F, options: EndpointOptions);

key(...args: Parameters<F>): string;
Expand All @@ -32,7 +40,11 @@ export interface EndpointOptions extends EndpointExtraOptions {
sideEffect?: true | undefined;
schema?: Schema;
}
```

<!--EndpointExtraOptions-->

```typescript
export interface EndpointExtraOptions {
/** Default data expiry length, will fall back to NetworkManager default if not defined */
readonly dataExpiryLength?: number;
Expand All @@ -52,6 +64,8 @@ export interface EndpointExtraOptions {
}
```

<!--END_DOCUSAURUS_CODE_TABS-->

## Endpoint Members

Members double as options (second constructor arg). While none are required, the first few
Expand All @@ -69,10 +83,9 @@ Default:

### sideEffect: true | undefined

Disallows usage in hooks like `useResource()` since they might call fetch
an unpredictable number of times. Use this for APIs with mutation side-effects like update, create, deletes.

Defaults to undefined meaning no side effects.
Used to indicate endpoint might have side-effects (non-idempotent). This restricts it
from being used with [useResource()](./useresource) or [useRetrieve()](useRetrieve) as those can hit the
endpoint an unpredictable number of times.

### schema: Schema

Expand Down Expand Up @@ -108,33 +121,36 @@ const UserDetail = new Endpoint(({ id }) ⇒ fetch(`/users/${id}`));
const UserDetailNormalized = UserDetail.extend({ schema: User });
```

### dataExpiryLength?: number
### EndpointExtraOptions

#### dataExpiryLength?: number

Custom data cache lifetime for the fetched resource. Will override the value set in NetworkManager.

### errorExpiryLength?: number
#### errorExpiryLength?: number

Custom data error lifetime for the fetched resource. Will override the value set in NetworkManager.

### pollFrequency: number
#### pollFrequency: number

Frequency in millisecond to poll at. Requires using [useSubscription()](./useSubscription.md) to have
an effect.

### invalidIfStale: boolean
#### invalidIfStale: boolean

Indicates stale data should be considered unusable and thus not be returned from the cache. This means
that useResource() will suspend when data is stale even if it already exists in cache.

### optimisticUpdate: (params, body) => fakePayload
#### optimisticUpdate: (params, body) => fakePayload

When provided, any fetches with this shape will behave as though the `fakePayload` return value
When provided, any fetches with this endpoint will behave as though the `fakePayload` return value
from this function was a succesful network response. When the actual fetch completes (regardless
of failure or success), the optimistic update will be replaced with the actual network response.

## Examples

### 1) Define the function
<!--DOCUSAURUS_CODE_TABS-->
<!--Basic-->

```typescript
import { Endpoint } from '@rest-hooks/endpoint';
Expand All @@ -144,7 +160,47 @@ const UserDetail = new Endpoint(
);
```

### 2) Reuse with different hooks
<!--With Schema-->

```typescript
import { Endpoint } from '@rest-hooks/endpoint';
import { Entity } from 'rest-hooks';

class User extends Entity {
readonly id: string = '';
readonly username: string = '';

pk() { return this.id; }
}

const UserDetail = new Endpoint(
({ id }) ⇒ fetch(`/users/${id}`).then(res => res.json()),
{ schema: User }
);
```

<!--List-->
```typescript
import { Endpoint } from '@rest-hooks/endpoint';
import { Entity } from 'rest-hooks';

class User extends Entity {
readonly id: string = '';
readonly username: string = '';

pk() { return this.id; }
}

const UserList = new Endpoint(
() ⇒ fetch(`/users/`).then(res => res.json()),
{ schema: [User] }
);
```
<!--END_DOCUSAURUS_CODE_TABS-->

<!--DOCUSAURUS_CODE_TABS-->
<!--React-->


```tsx
function UserProfile() {
Expand All @@ -155,12 +211,21 @@ function UserProfile() {
}
```

### 3) Or call directly
<!--JS/Node-->

```typescript
const user = await UserDetail({ id: '5' });
console.log(user);
```
<!--END_DOCUSAURUS_CODE_TABS-->

### Additional

- [Custom endpoints](../guides/extending-endpoints)
- [Pagination](../guides/pagination)
- [Mocking unfinished endpoints](../guides/mocking-unfinished)
- [Optimistic updates](../guides/optimistic-updates)


## Motivation

Expand Down
4 changes: 2 additions & 2 deletions docs/api/Entity.md
Expand Up @@ -186,7 +186,7 @@ export class UserResource extends Resource {
```
```tsx
const user = useResource(UserResource.detailShape(), { username: 'bob' });
const user = useResource(UserResource.detail(), { username: 'bob' });
```
#### useCache()
Expand Down Expand Up @@ -216,7 +216,7 @@ class AssetResource extends Resource {
Some top level component:
```tsx
const assets = useResource(AssetResource.listShape(), {});
const assets = useResource(AssetResource.list(), {});
```
Nested below:
Expand Down

0 comments on commit 4472106

Please sign in to comment.