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

@focuson-nw/poster

v2.0.37

Published

This allows for declarative 'posting'

Downloads

22

Readme

@focuson-nw/poster is a project to help with 'post' commands in react applications.

Many react applications can be split up as follows:

  • Getting data from an api to display it
  • Rendering the data
  • Editing the data
  • Doing things with the data (checkout / payment )

This project addresses the last goal. It provides a declarative mechanism, that is very easy to test, that controls when data is sent to the backend. i.e. the 'doing things'.

Post Commands

The react application communicates with the 'poster' only through state. In the state there is a place that has an array of post commands. The exact place is configurable using a lens. Typically there will be only one post command.

The post command has the signature

interface PostCommand<State, Details extends Posters<State>, K extends keyof Details> {
    poster: K,
    args: any  
}

That's complicated until it is realised that K is just a 'legal post name'. The list of legal post names is in the PostDetails (see below).

An example that represents a single call to 'updateAccountDetails' could be

{postCommands: [{poster: "updateAccountDetails", args: {id: 12335, accountDetails: {some: "accountDetails"}}}]}

Note how easy it is now to test the react components. The 'event' that would normally do the side effect, instead just updates the state. This is very easy to test without complex mocks, containers or an acceptance environment

From a mental concept point of view this is very similar to 'dispatching' in redux. The only difference is that instead of 'calling dispatch' (which causes an immediate side effect) this simply writes to the state the parameters that would be sent to the dipatcher.

Life cycle

  • The post method is called
  • For each post command
    • the fetch parameters are calculated
    • fetch is called. this returns a status and body
    • If the status is a 2xx,
      • the body is 'shaped' (i.e. turned into a format suitable to go into the state)
      • and added at the location defined by the targetLens (typically this will result in a message, but could hold concrete data that is needed)
    • If the status isn't 2xx
      • The errorFn is called and added to the status (typically this will result in an error message)

PostDetails

export interface Posters<State> {
    [name: string]: PostDetails<State, any, any>
}
export interface PostDetails<State, Args, Returned,Result> {
    urlFn: (args: Args) => [RequestInfo, RequestInit | undefined],
    shaper: (r: Returned) => Result,
  errorFn: ErrorFn<State>,
    targetLn: Optional<State, Result>
}
  • urlFn the arguments come from PostCommand (i.e. typically the react component that triggers this)
  • shaper turns the Returned value from the api into Result. This is needed because quite often the values returned from the API need to be turned into a message or reshaped
  • errorFn what to do if there is an error (either a failed promise, or a non 200 status code)
  • targetLn Where to put the returned result

Example

interface UpdateAccountDetails {
    //here we have the type of the data that will be sent to the api
}
interface UpdateAccountResult{
    //This is the type that is returned from the api. It might be empty, or it might has a message like 'succeeded'
}
//This is the actual configuration of the poster for updateAccountDetails
const updateAccountDetails = <MainState>(targetLens: Optional<MainState, UpdateAccountResult>): PostDetails<MainState, String, UpdateAccountDetails, UpdateAccountDetails> => ({
  urlFn: (accountId: string) => [`/someapi/updateAccount/${accountId}`, { method: 'post' }],
  errorFn: addDebugErrorMessage(errorLens),
  shape: s => s,
  targetLens
})

In this example the data from the API was directly inserted into the state because of shape: s => s. Other options include setting a string such as 'succeeded'

Posters

This is were we 'tie it all together'. All the posters in the application are added here, giving each action a unique name. The is the type of the global state

const allPosters : Posters<MainState> = {
    updateAccountDetails: updateAccountDetails
}

At this point updateAccountDetails (the key) can be used in a post command with some arguments

Using the Poster

Given a state MainState with postCommands in it somewhere (postCommand points to them) the following updates the state with the results of the post commands

const poster = post<MainState, Posters<MainState>>(fetchFn, postDetails, postCommandsL, postDebugL)
  • fetchFn delegates to fetch
  • postDetails is the structure shown above that links the names of post commands to the details of how to implement them
  • postCommandsL is a lens from the MainState to the list of post commands
  • postDebugL is an optional lens from the MainState to a place where the postDebug data structure can be find. This turns on and off console.log messages about the posting