Category Archives: Web Development

Breaking the Internet

Unable to find a dom node for 19 – Slate.js

Hi everyone,

I ran into the following error while attempting to add an image to a slate.js editor today:

slate.js unable to find dom node for 19

The solution was to add a simple schema to my editor:


const schema = {
    blocks: {
        image: {
            isVoid: true
        }
    }
};
    spellCheck
    autoFocus
    ref={this.ref}
    value={this.state.value}
    onChange={this.onChange}
    onKeyDown={this.onKeyDown}
    onDrop={this.onDropOrPaste}
    onPaste={this.onDropOrPaste}
    renderNode={this.renderNode}
    renderMark={this.renderMark}
    className={classes.editor}
    readOnly={readOnly}
    onFocus={() => { this.setState({ changed: true }); }}
    schema={schema}

There’s more on schemas in the official documentation: https://docs.slatejs.org/guides/schemas

Advertisements

String to Color – Avatar Helpers

Hi everyone,

A quick post on a helper function I came across for generating avatars. This function generates a random color for the specified string:


export const stringToColor = string => {

let hash = 0;
let i;

for (i = 0; i < string.length; i += 1) {
hash = string.charCodeAt(i) + ((hash << 5) - hash);
}

let colour = '#';

for (i = 0; i > (i * 8)) & 0xff;
colour += `00${value.toString(16)}`.substr(-2);
}

return colour;
}

Thanks to oliviertassinari: https://github.com/oliviertassinari/SplitMe/blob/c25fe62187a856386fd0c43c51859d6f973d651e/src/main/member/Avatar.js#L8-L26

Access to fetch from origin has been blocked by CORS policy – AWS SAM Local

Hi everyone,

I’ve been using AWS SAM local lately and ran into a bit of an issue with CORS. It took a looong time to find a solution that worked for all of my local scenarios so hopefully this will be able to help someone else out.

Access to fetch at 'http://127.0.0.1:3000' from origin 'http://localhost:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

The error above is fairly typical when working with APIs. The request will work from tools such as postman and fiddler but browsers will block it. These are a few good links that explain why CORS is necessary:
https://medium.com/@electra_chong/what-is-cors-what-is-it-used-for-308cafa4df1a
https://stackoverflow.com/a/29167709/522859

As for the solution, add the following to your template.yml:

  PreFlightFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: functions/generic/cors.getPreflightHandler
      Runtime: nodejs8.10
      Events:
        GetEvent:
          Type: Api
          Properties:
            Path: /pages
            Method: options
            RestApiId: !Ref XXXApi
            Auth:
              Authorizer: NONE

If you haven’t already defined your api in your template.yml file there is a default/omitted one created for you. There are a few examples on the AWS github: https://github.com/awslabs/serverless-application-model/blob/release/v1.8.0/examples/2016-10-31/api_cognito_auth/template.yaml

The next thing to do is to create a handler for the options request:


/* Handles retrieving a specific page */
exports.getPreflightHandler = async (event, context, callback) => {
    callback(null, { body: {} }, headers: { 'content-type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', 'Access-Control-Allow-Methods': 'OPTIONS,GET,POST,PUT,PATCH,DELETE', 'Access-Control-Allow-Credentials': true }, statusCode: 200 })
};

I’ve moved all mine out to some helper methods but the above should be enough to get it working for you. Hopefully the AWS team will have a simpler solution soon but if you run into any issues in the meantime please let me know!

AWS SAM Request Extremely Slow – Fix

Hi everyone,

I’m currently using AWS SAM CLI with NodeJS and was surprised to find that the requests were significantly slower when run locally. Luckily, I came across a post that suggested adding –skip-pull-image to your start-api command:

sam local start-api --skip-pull-image

This brought my requests down to under a second. Thanks to the following link for the info: https://github.com/awslabs/aws-sam-cli/issues/134#issuecomment-406786704

this.query is not a function – error when using promisify with mysql

Hi everyone,

I ran into the following error while attempting to promisify my node.js mysql transactions:

TypeError: this.query is not a function
    at rollback (/var/task/node_modules/mysql/lib/Connection.js:179:15)
    at rollback (internal/util.js:230:26)

This took a while to track down but it turns out that I needed to bind the connection after promisifying the function. Instead of:

util.promisify(connection.query);

Add bind to the end of it:

util.promisify(connection.query).bind(connection)

Thanks to the following stackoverflow post for the insight: https://stackoverflow.com/a/51690276/522859

Overriding Global Variables – AWS SAM Local

Hi everyone,

Today I’ve added local overrides to the global variables in my template.yml file. This was pretty finicky – a lot of conflicting suggestions out there unfortunately. These are the settings that ended up working for me.

local-env-var-overrides.json:

{
    "Parameters": {
        "RDS_HOSTNAME_TEST": "192.168.0.31"
    }
}

template.yaml

Globals:
  Function:
    Environment:
      Variables:        
        RDS_HOSTNAME_TEST:
          Type: String
          Default: 'DEFAULT'

aws sam local command:

sam local start-api --env-vars "local-env-var-overrides.json"

create.js

exports.createTrapHandler = async (event, context, callback) => {

	try {

        console.log("RDS_HOSTNAME_TEST: " + process.env.RDS_HOSTNAME_TEST)
        // Outputs: 192.168.0.31

This link ended up being pretty useful: https://www.npmjs.com/package/aws-sam-local

Upload an Image to S3 Using Post and a Presigned Url

Hi everyone,

Today I’ve been converting my “PUT” upload to S3 to a “POST”. The main motivator for this was to restrict the file size of uploads using a signed policy. Unfortunately this was a pretty tedious process and the error responses from S3 were very vague. Thankfully it’s working now and here’s what I needed to do!

Here’s an excerpt from my nodejs lambda function that generates the presigned url:

/* Creates a pre-signed upload url and then stores a reference in a table */
exports.createUploadUrl = async params => {

    var { databaseHandler, bucketHandler } = params;

    // Create id for upload
    var uploadId = uuidv4();

    // Retrieve pre-signed url
    var bucketDataPromise = createPresignedPostPromise({
        Bucket: process.env.BUCKET_UPLOADS,
        Expires: 60 * 60,
        Conditions: [            
            ["content-length-range", 0, 300000], // 300kb
            [ "eq", "$key", uploadId],
            [ "eq", "$Content-Type", 'image/jpeg' ],
        ]
    });

    // var ddbData = await ddbDataPromise;
    var bucketData = await bucketDataPromise;

    // Wait for database handler to complete operation and then return
    return Helpers.generateResponse({
        data: {
            uploadData: bucketData,
            additionalFields: {
                key: uploadId,
                "Content-Type": 'image/jpeg',
            },
        },
        statusCode: 200
    });
}

You can then retrieve the upload details using a request like the following (Python):

resp = requests.put("https://f86caxqe9f.execute-api.ap-southeast-2.amazonaws.com/Prod/images", data=open(path, 'rb'))

This will return a response similar to the following:

{
    "messages": [],
    "data": {
        "uploadUrl": {
            "url": "YOUR UPLOAD URL",
            "fields": {
                "bucket": "YOUR BUCKET",
                "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
                "X-Amz-Credential": "XXX",
                "X-Amz-Date": "20190107T125044Z",
                "X-Amz-Security-Token": "SECURITY_TOKEN",
                "Policy": "YOUR BASE64 ENCODED POLICY",
                "X-Amz-Signature": "SIGNATURE"
            }
        },
        "uploadId": "UPLOAD_ID"
    }
}

And once you have those details you can use them to upload the image:

# Attempt to retrieve upload url etc
json = resp.json()
data = json["data"]
uploadUrl = data["uploadData"]["url"]
uploadFields = data["uploadData"]["fields"]
uploadFields.update(data["additionalFields"])

try:
    print("Uploading image...",end='')
    headers = {'Content-Type': 'multipart/form-data' }
    files = { 'file': open(path, 'rb')}
    resp = requests.post(uploadUrl, data=uploadFields, files=files)

    # Only show content if there's an error
    if resp.status_code == 200:
        print("Uploaded")
    else:  
        print("ERROR")                          
        print(repr(resp))
        print(repr(resp.content))

except Exception as e:
    print("\r\nFailed to upload image.")
    print("Upload data:")
    print(repr(uploadFields))
    print("Exception:")
    print(repr(e))
    traceback.print_exc()

Hopefully that’s been able to help you out, but feel free to let me know in the comments below if you need more info!

Thanks to these links for the info:
https://stackoverflow.com/a/35923104/522859
https://stackoverflow.com/a/49311831/522859