npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

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.

  1. Dispatch a custom command action, e.g. "FETCH_USERS".
  2. Listen to all "FETCH_USERS" command actions.
  3. Dispatch an Apium request action, passing the "FETCH_USERS" action as action.meta.origin.
  4. Let the Apium middleware fetch the data.
  5. Listen to actions passing the isApiumSuccess("FETCH_USERS") predicate or use the await syntax.
  6. 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:

  1. You shouldn't be using request() directly in your components. Instead, you should always dispatch custom actions, such as fetchUsers(), for better decoupling and readability.
  2. 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:

  1. Dispatch a configure({ baseHeaders: { Authorization: "Bearer <jwt>" } }) action.
  2. 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.
  3. 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.