apium
v0.1.2
Published
Redux middleware for event-driven HTTP requests with async/await support.
Downloads
118
Readme
Installation
Use either of these commands, depending on the package manager you prefer:
yarn add apium
npm i apium
Quick Start
Add the middleware and the reducer to a Redux store.
import { createStore, applyMiddleware, combineReducers } from "redux"
import { apiumReducer, makeApiumMiddleware } from "apium"
const store = createStore(
combineReducers({ apium: apiumReducer }),
applyMiddleware(makeApiumMiddleware()),
)
Trigger a request in your React component by dispatching a custom command action.
const UserList = () => {
const users = useSelector(getUsers)
const dispatch = useDispatch()
useEffect(() => {
dispatch(fetchUsers())
}, [])
return <List items={users} />
}
Perform a request based on the custom action.
import { request } from "apium"
// With `redux-saga`.
function* fetchUsersSaga(action) {
const { payload } = yield putResolve(request({ url: "/users" }, { origin: action }))
yield put(storeUsers(payload))
}
function* watchFetchUsers() {
yield takeEvery(ActionTypes.fetchUsers, fetchUsersSaga)
}
// With `redux-observable`.
const fetchUsersEpic = action$ =>
action$.pipe(
ofType(ActionTypes.fetchUsers),
mergeMap(action => request({ url: "/users" }, { origin: action })),
map(({ payload }) => storeUsers(payload)),
)
// With `redux-thunk`.
const fetchUsers = () => async dispatch => {
const { payload } = await dispatch(request({ url: "/users" }, { origin: action }))
dispatch(storeUsers(payload))
}
// Without any additional libraries.
const fetchUsersMiddleware = ({ dispatch }) => next => async action => {
next(action)
if (action.type === ActionTypes.fetchUsers) {
const { payload } = await dispatch(request({ url: "/users" }, { origin: action }))
dispatch(storeUsers(payload))
}
}
Use the isFetching
selector factory.
import { isFetching } from "apium"
const isFetchingUsers = isFetching(ActionTypes.fetchUsers)
const UserManagement = () => {
const fetchingUsers = useSelector(isFetchingUsers)
if (fetchingUsers) {
return <Spinner />
}
return <UserList />
}
Core Concepts
You should probably read this entire section before using the library.
General Request Flow
Suppose we want to fetch all users from a RESTful API.
- Dispatch a custom command action, e.g.
"FETCH_USERS"
. - Listen to all
"FETCH_USERS"
command actions. - Dispatch an Apium request action, passing the
"FETCH_USERS"
action asaction.meta.origin
. - Let the Apium middleware fetch the data.
- Listen to actions passing the
isApiumSuccess("FETCH_USERS")
predicate or use theawait
syntax. - Store the users to display them.
This flow is slightly simplified when using Redux Thunk, which is not reliant on listening to certain types of actions.
Await Syntax
When an Apium request is dispatched, the Apium middleware does not use the action as its return value directly. Instead, it adds a .then
property to the action, making it a thenable. Thenables behave similarly to promises in that they are supported by the await
syntax.
Origin Meta Property
It is necessary to pass the action.meta.origin
property to all Apium requests. This is what makes it possible to use the isFetching
selector factories. You must always use a custom command action as the origin, i.e. you cannot use Apium actions directly. This is to encourage good coding practices:
- You shouldn't be using
request()
directly in your components. Instead, you should always dispatch custom actions, such asfetchUsers()
, for better decoupling and readability. - It will make the
isFetching
selector factory usable without any further changes to existing code.
Authentication
Should you need to automatically attach a JWT as the Authorization: Bearer <jwt>
HTTP header, you have several options on how to achieve this:
- Dispatch a
configure({ baseHeaders: { Authorization: "Bearer <jwt>" } })
action. - Configure the middleware:
makeApiumMiddleware({ transformRequestAction })
. This allows you to retrieve the JWT from Redux state and modify all request actions to have the JWT included in the header. - Write a custom middleware that sits in front of Apium middleware, modifying request actions before they are passed to the next middleware. This also allows you e.g. to pause all requests while a new access token is being fetched, resulting in the coolest authentication setup possible.
Changelog
See the CHANGELOG.md file.
License
All packages are distributed under the MIT license. See the license here.