react-restful
Version:
Another liblary for restful resources management for React app.
328 lines (265 loc) • 7.94 kB
Markdown
# react-restful
Another liblary for restful resources management for React app.
[](https://nodei.co/npm/react-restful/)
[](https://travis-ci.org/kenkz447/react-restful)
[](https://coveralls.io/github/kenkz447/react-restful?branch=master)
*Are you familiar with Swagger?*
## Why this is helpful?
- Centralized all API resources in one place, for management and maintenance.
- Monitor data changes and automatically update view.
- Based on typescript, no redux.
- Easy to learn, simple integration without compromising performance.
- Small size bundle.
## The simplest way to use
Minimum setup (for most projects), "keep it simple stupid" is a best in development process.
### Setup
To start, you need create `restful` folder at somewhere in your project. I prefer place under `/src`.
````typescript
/**
* File: /src/restful/restful-environment.ts
*/
import { setupEnvironment } from 'react-restful';
setupEnvironment({
entry: 'http//localhost:1337',
beforeFetch: (url: string, requestInit: RequestInit) => {
// Inject request headers here...
return requestInit;
},
afterFetch: async (response) => {
// Side-effects here
}
})
````
Define your first API resource, would you like to build an app to manage `pets` a in pet store?
````typescript
/**
* File: /src/restful/resources/pet.ts
*/
import {
RecordType,
Resource,
ResourceType,
getStore
} from 'react-restful';
export interface Pet extends RecordType {
id?: number;
name: string;
desciption?: string;
}
export const petResources = {
// API to get list of pet
find: new Resource<Pet[]>('/pet'),
}
````
Export `pet.ts` via `/src/restful/index.ts`, don't forget import `restful-environment.ts` at top of `/src/restful/index.ts` file.
```ts
/**
* File: /src/restful/index.ts
*/
export * from './restful-environment.ts';
export * from './resources/pet.ts';
```
### Implememnt
First, using `RestfulRender` to send GET request to get list of user,
Then passed down response data to `UserList`
````tsx
/**
* File: /src/components/PetContainer.tsx
*/
import * as React from 'react';
import { RestfulRender, request } from 'react-restful';
import { petResources } from '/src/restful';
import { PetList } from './PetList.tsx'
export class PetContainer extends React.Component {
render() {
return (
<RestfulRender
resource={petResources.find}
>
{
({ data }) => {
if (!data) {
return null;
}
return (<PetList pets={data}/>)
}
}
</RestfulRender>
);
}
}
````
Component to render data
````tsx
/**
* File: /src/components/PetList.tsx
*/
import * as React from 'react';
import { request } from 'react-restful';
import { petResources, Pet } from '/src/restful';
import { PetItem } from './PetItem';
interface PetListProps {
pets: Pet[];
}
export class PetList extends React.Component<PetListProps> {
render() {
const { pets } = this.props;
return (
<ul className="peting-list">
{
pets.map(pet => <PetItem key={pet.id} pet={pet}/>)
}
</ul>
);
}
}
````
And display pet info via `PetItem`
````tsx
/**
* File: /src/components/PetItem.tsx
*/
import * as React from 'react';
import {
petResources,
Pet
} from '/src/restful';
interface PetItemProps {
pets: Pet;
}
export class PetItem extends React.Component<PetItemProps> {
render() {
<li className="peting-item">
<h4>#{pet.id}</h4>
</li>
}
}
````
End yet? not yet. You have just undergone 'R' in the CRUD definition. Look down below to see how to complete the process:
1. add three resources:
```diff
/**
* File: /src/restful/resources/pet.ts
*/
export const petResources = {
// API to get list of pet
find: new Resource<Pet[]>('/pet'),
+ create: new Resource<Pet>({
+ method: 'POST',
+ url: '/user'
+}),
+ update: new Resource<Pet>({
+ method: 'PUT',
+ url: '/user'
+}),
+ delete: new Resource<Pet>({
+ method: 'DELETE',
+ url: '/user/:id'
+})
}
```
2. Add `delete` and `update` methods in `PetItem`
```diff
/**
* File: /src/components/PetItem.tsx
*/
import * as React from 'react';
+ import { request } from 'react-restful';
import {
petResources,
Pet
} from '/src/restful';
export class PetItem extends React.Component<PetItemProps> {
+ input: HTMLInputElement;
render() {
+ const { pet } = this.props;
return (
<li className="peting-item">
<h4>#{pet.id}</h4>
+ <form onSubmit={this.handleSubmit}>
+ <label>
+ Name: <input value={pet.name} ref={(input) => this.input = input} />
+ </label>
+ <input type="submit" value="Update" />
+ <a onClick={this.handleDelete}>Delete this pet</a>
+ </form>
</li>
)
}
+ handleSubmit = async (event) => {
+ const { pet } = this.props;
+ const updatePet = {
+ ...pet,
+ name: this.input.value
+ };
+
+ await request(petResources.update, [{ type: 'body', value: updatePet }])
+ }
+ handleDelete = (event) => {
+ const { pet } = this.props;
+
+ await request(
+ petResources.delete,
+ [{
+ type: 'path',
+ parameter: 'id,
+ value: pet
+ }]
+ );
+ }
}
```
Now, you can create a request to the server to delete or update a pet's information. But soon you will realize a very painful problem: After the server processes and responds back to the client, how do you let the Components display the data exactly as you want?
Use HOC to track data changes and rerender child component if needed
```diff
/**
* File: /src/restful/resources/pet.ts
*/
import {
RecordType,
Resource,
ResourceType,
+ restfulDataContainer
} from 'react-restful';
```
Add code below to bottom of `/src/restful/resources/pet.ts`
```ts
export interface WithPetsProps {
readonly pets: Array<Pet>;
}
export const withPets = <P extends WithPetsProps>(): any =>
restfulDataContainer<Pet, WithPetsProps, P>({
resourceType: petResourceType,
shouldTrackingNewRecord: (record, ownProps, trackedPets) => true,
registerToTracking: (ownProps, trackedPets, event) => {
if (trackedPets) {
return trackedPets;
}
return ownProps.pets;
},
mapToProps: (pets) => {
return {
pets: pets
};
}
});
```
and use withPets HOC to PetList
````diff
/**
* File: /src/components/PetList.tsx
*/
import {
petResources,
Pet,
+ WithPetsProps,
+ withPets
} from '/src/restful';
-interface PetListProps {
+interface PetListProps extends WithPetsProps {
- pets: Pet[];
}
+@withPets()
export class PetList extends React.Component<PetListProps> {
````
That all.