Updating my React Sudoku Solver app: Replacing Flux with Redux (part 2)

In the first part of converting my Sudoku solver React app from using Flux to Redux I looked at creating the Redux Store, Action Creators, reducers, and connecting Components to the Store. In this part 2 I’m taking a look at using redux-thunk for making my api calls.

Async API calls are integrated into a Redux app by using a ‘thunk’, support is provided by adding react-thunk to your app:

npm install --save redux-thunk

react-thunk is a middleware for your Redux Store. It looks at each Action dispatched to your Store and if it’s a function instead of an Action object it executes it.

Where you create your store with createStore(), add an import for applyMiddleware and thunk:

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const middlewares = [thunk];

Pass a call to applyMiddleware as a param to createStore() passing this middlewares array. In my app I’ve already passed the devToolsEnhancer() to createStore():

let store = createStore(puzzleDataReducer, devToolsEnhancer());

Naively, I thought I’d be able to add thunk and devToolsEnhancer() in the array and pass like this:

const middlewares = [thunk, devToolsMiddleware()];
let store = createStore(puzzleDataReducer, applyMiddleware(...middlewares));

… but this leads to some rather cryptic errors and I’ve honestly no idea what this means or how to resolve it:

VM1047:1 Uncaught TypeError: t.apply is not a function
     at :1:47480
     at :1:33759
     at :1:26192
     at eval (redux.js:602)
     at eval (redux.js:646)
     at createStore (redux.js:79)

Luckily a quick search found this article, suggesting the way to combine these enhancers is to use redux’s compose() function. Import compose from redux:

import { createStore, applyMiddleware, compose } from 'redux';

Use compose() to combine thunk and the devToolsEnhancer() call like this:

compose(
   applyMiddleware(thunk, otherMiddleware()),
   window.devToolsExtension ? window.devToolsExtension() : f => f
 )

In my case I don’t have other middleware to include, so my createStore() was originally this:

let store = createStore(puzzleDataReducer, devToolsEnhancer());

and now including thunk and using compose() it looks like this:

let store = createStore(puzzleDataReducer, compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : f => f
    )
);

Next I need to move my Flux Action that makes my api call to a function that is returned by an Action Creator. Since react-thunk looks for functions returned by Action Creators instead of Action objects and executes them. this was a relatively minor change moving the function from my original Action to my Action Creator.

At this point I’ve got a working app, migrated from Flux to Redux. You can check the final result on GitHub here. I’ve still got some cleanup to do – in particular I don’t have a clean separation between my reducer code and my Action Creator code. I’ll code back and do some cleanup later, and also deploy a parallel copy of the same app to AWS. Right now the original Flux based app is deployed here. I’ll deploy the final Redux based app shortly.

Creating a new AWS Lambda project with Serverless

Assuming the Serverless cli is already installed (here), init a new project with ‘serverless’ and answer the following questions:

% serverless       
 Serverless: No project detected. Do you want to create a new one? Yes
 Serverless: What do you want to make? AWS Node.js
 Serverless: What do you want to call this project? lambda-example
 Project successfully created in 'lambda-example' folder.

To deploy, run ‘serverless deploy’

AWS CloudFormation basics – part1

Collection of notes, templates and tips for building AWS CloudFormation templates.

The basic structure of CloudFormation files (in JSON):

{
  "Resources" : {
    "ExampleResourceName" : {
      "Type" : "AWS::?::?",
      "Properties" : {
        "Example" : "propertyvalue"
      }
    }
  }
}
  • Resources: the AWS services to be provisioned. There can be multiple repeating Resource elements in this section, to provision/configure multiple services in a stack
  • ExampleResourceName: a name for each resource being provisioned
  • Type: the AWS type for the resource, e.g. AWS::S3::Bucket
  • Properties: properties for the service being provisioned/configured

AWS CLI commands:

aws cloudformation create-stack --stack-name STACK-NAME
  --template-body file://template-file.json
  --parameters ParameterKey=example1,ParameterValue=value1    
    ParameterKey=example2,ParameterValue=value2
aws cloudformation list-stacks
aws cloudformation delete-stack --stack-name STACK-NAME

If your stack creates IAM resources, you’ll also need to pass:

--capabilities CAPABILITY_NAMED_IAM

Otherwise you’ll see this error:

An error occurred (InsufficientCapabilitiesException) when calling the CreateStack operation: Requires capabilities : [CAPABILITY_NAMED_IAM]

AWS CLI error “The provided token is malformed or otherwise invalid”

Starting getting this error when running a simple ‘aws s3 ls’

An error occurred (InvalidToken) when calling the ListBuckets operation: The provided token is malformed or otherwise invalid.

My current version:

% aws --version
aws-cli/2.0.59 Python/3.7.4 Darwin/20.1.0 exe/x86_64

Downloaded latest version and upgraded and problem fixed. New version is now:

% aws --version aws-cli/2.1.3 Python/3.7.4 Darwin/20.1.0 exe/x86_64