Saturday, 27 March 2021

Two Lambdas Are Better Than One

 To refactor the single Lambda function and API previously, I created two Lambda functions:

  1. getNumbersGameHtml - to return the HTML string, which is the GUI page of the Numbers Game single page web application.
  2. solveNumbersGame - to return the array of solutions (strings of math expressions)
The Python code for getNumbersGameHtml function:


def lambda_handler(event, context):
    return {
        'body': myHtml
    }
    
myHtml = ('<!DOCTYPE html>\n'
'<html>\n'
'<head profile=\"http://www.w3.org/2005/10/profile\"><link rel=... />...\n'
'<body>\n'
'...'
'	<input type="submit" value="Solve Game" onClick="if (validate_inputs()) {solve_game();} else alert(\'Please ensure all numbers and targets are filled in and with valid values.\\nHover mouse over input boxes for rules details.\');" />&nbsp;&nbsp;&nbsp;&nbsp;    \n'
'	<input type="button" value="Reset Game" onClick="reset_game()"/> \n'
'...')

# alternatively
myHtml="""<!DOCTYPE html>
<html>
<head profile=\"http://www.w3.org/2005/10/profile\"><link rel=... />...
<body>
...
	<input type="submit" value="Solve Game" onClick="if (validate_inputs()) {solve_game();} else alert(\'Please ensure all numbers and targets are filled in and with valid values.\\nHover mouse over input boxes for rules details.\');" />&nbsp;&nbsp;&nbsp;&nbsp;
	<input type="button" value="Reset Game" onClick="reset_game()"/>
...
"""
The web page looks like this:

    


Copyright (c) Romen Law. All rights reserved.

The Javascript code for solveNumbersGame function:

exports.handler = async (event) => {
	var e=event;
	var numbers=[e.n1,e.n2,e.n3,e.n4,e.n5,e.n6], target=e.target;
	var answer=solveAllGames(numbers, target);
	
    const response = {
        statusCode: 200,
        body: JSON.stringify(answer)
    };
    
    return response;
};
An API is created at the API Gateway with two methods implemented:
  • GET method invokes the getNumbersGameHtml function
    • at the GET - Integration Response, for response 200, 
      • add a Header Mappings entry with Response header of content-type and the Mapping value of 'text/html' (notice the single quote - it represents literal string in the mapping language).
      • at Mapping Templates, add an entry for Content-Type of text/html with template code of $input.path('body') (don't forget to press the grey Save button at the bottom before the blue Save button at the top).
    • at the GET - Method Response, for HTTP status 200 
      • add header of content-type
      • add Response model of Empty for content-type text/html
  • POST method invokes the solveNumbersGame function
    • at the POST - Method Request, Request Body
      • set the Request Validator field to Validate body and click the tick.
      • add NumbersInput model for application/json. This will enforce the input data format and some validation rules
    • at the POST - Integration Response, Mapping Templates: add template code $input.path('body') for content type application/json. This will extract the 'body' field from the response of the Lambda function and return it as the API's response.
The NumbersInput model:


{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "n1": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "n2": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "n3": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "n4": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "n5": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "n6": {
      "type": "integer", "minimum": 1, "maximum": 100
    },
    "target": {
      "type": "integer", "minimum": 100, "maximum": 999
    }
  },
  "required": [
    "n1",
    "n2",
    "n3",
    "n4",
    "n5",
    "n6",
    "target"
  ]
}
See also:

No comments: