Give your application an API service layer! Define Service Classes
that utilize the abstract ApiService
. The benefit to ApiService
is it has abstract api-typical methods so one can use it as a mocking service or as an implementation of your faviorite request library.
Generally you'll want to:
- Implement your own ApiService(s)
-
Create Service Classes that utilize your
ApiServices
(created in step 1) - Use the provided hooks to create memoizations of those services for your custom-hooks/components
npm install --save react-api-service-layer
You'll want to implement your own ApiService
classes. Perhaps you'll want to use Axios:
import { ApiService } from 'react-api-service-layer';
import axios from 'axios';
class AxiosApiService extends ApiService {
baseUrl: string = 'http://my-api.com';
// Override the get for this example
get(resourcePath: string, options?: any): Promise<any> {
return axios.get(`${this.baseUrl}${resourcePath}`);
}
post(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
put(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
patch(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
delete(resourcePath: string, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
}
Or maybe you'll want to create some data mocking service:
import { ApiService } from 'react-api-service-layer';
const mockGets = {
'/todos': []
}
class MockApiService extends ApiService {
// Override the get for this example
get(resourcePath: string, options?: any): Promise<any> {
return mockGets[resourcePath];
}
post(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
put(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
patch(resourcePath: string, payload: any, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
delete(resourcePath: string, options?: any): Promise<any> {
throw new Error('Method not implemented.');
}
}
Personally, I'm a big fan of composition pattern.
import { ApiService } from 'react-api-service-layer';
class TodoService {
apiService: APIService
getTodos() {
return this.apiService.get('path-to-my-service');
}
}
Surely you can inherit your api service well enough
class TodoService extends AxiosApiService {
getTodos() {
return this.get('/todos')
}
}
The hooks provided describe patterns for setting the ApiService
in your Service Classes
.
useService
is generically typed, so you'll need to provide the typing AND the class. Any additional constructor params are optional from there on out.
import { useService, ApiService, useConstructableApiService } from 'react-api-service-layer';
class TodoService {
apiService: APIService
constructor (apiService: ApiService) {
this.apiService = apiService;
}
getTodos() {
return this.apiService.get('path-to-my-service');
}
}
const MyComponent = () => {
const apiService = useService<AxiosApiService>(AxiosApiService);
const todoService = useService<TodoService>(TodoService, apiService);
React.useEffect( async () => {
const todos = await todoService.getTodos();
console.log('Todos:', todos);
}, []);
return (
<div>
Hello World
</div>
)
}
import { useService, ApiService, useConstructableApiService } from 'react-api-service-layer';
class TodoService {
apiService: APIService
setApiService(apiService: ApiService) {
this.apiService = apiService;
}
getTodos() {
return this.apiService.get('path-to-my-service');
}
}
const MyComponent = () => {
const apiService = useService<AxiosApiService>(AxiosApiService);
const todoService = useService<TodoService>(TodoService);
React.useEffect( async () => {
todoService.setApiService(apiService);
const todos = await todoService.getTodos();
console.log('Todos:', todos);
}, []);
return (
<div>
Hello World
</div>
)
}