Skip to content

Instantly share code, notes, and snippets.

@kevinvoduy
Last active March 27, 2018 02:36
Show Gist options
  • Save kevinvoduy/a1ffd24be434e51cc97dae2747fbbb41 to your computer and use it in GitHub Desktop.
Save kevinvoduy/a1ffd24be434e51cc97dae2747fbbb41 to your computer and use it in GitHub Desktop.
Notes: Restful API, react 16, Sql injection, oop/ood, data warehouse

Notes to review

RESTful API

REST is an architectural style that defines a set of constraints and properties to allow communication between various systems on the web.

  • constraints

    • client-server architecture: separation of concerns, UI and API are have their own responsibilities, and therefore allow both to evolve independently
    • cacheability: responses are implicitly or explicitly defined as cacheable or not to prevent clients from reusing stale or inappropriate data in resonse to furth requests
    • statelessness: no client context is stored on the server between requests, each request from the client must contain all the information necessary to service the request
    • Layered System: like the MVC concept, server components are built on top of each other to build a heirarchy that helps create a more scalable and modular appliation
  • what is the difference between REST and SOAP?

    • SOAP
      • relies exclusively on XML to provide message services
      • is more rigid than REST
      • is highly extensible, pick and choose what you need from it
      • provides build in error handling with standardized codes for some automated error handling
    • differences
      • SOAP is standardized and language, platform, and transport independent
      • SOAP works will in distributed enterprise environments
      • REST is easier to learn, efficient, and fast

React 16

Whats new? New render return types - better error handling - portals - better server-side rendering - reduced file size

Render types

Fragments and strings: return an array of elements, string, or number from a component's render method

class MyArrayComponent extends React.Component {
  render() {
    return [
      <div key="1">first element</div>, 
      <div key="2">second element</div>
    ];
  }
}
class MyStringComponent extends React.Component {
  render() {
    return "hey there";
  }
}

Error handling

Error boundaries: special components that capture errors inside their subtree and display a fallback UI in its place - like try catch - instead of unmounting whole componenet from root

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

Then you can use it as a regular component:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

Note: error boundaries only catch errors in the components below them in the tree. It cannot catch an error within itself

Uncaught errors: errors that were not caught by any error boundary will result in unmounting the whole react component tree

We’ve built a generic way for components to suspend rendering while they load async data, which we call suspense. You can pause any state update until the data is ready, and you can add async loading to any component deep in the tree without plumbing all the props and state through your app and hoisting the logic.

Server-side rendering

New packaging stragety: by eliminating process.env from Node.js, React 16 is able to improve SSR by 300%

  • backwards compatible: syntax from react 15 works with react 16
  • client-side rendering
    1. render() when solely rendering on the client
    2. hydrate() when rendering on top of server-side rendered markup
  • not supported: error boundaries or portals in SSR

Reduced file size

Flat bundle format: consistent size no matter what react is shipped with

Speed

Node environment (ssr): only checks process.env.NODE_ENV once at the beginning so no need to compile. React 16 doesn't need to compile because there is no need to remove references to process.env like in react 15

Backpressure (ssr): if the network is backed up and can't accept more bytes, the renderer gets a signal and pauses rendering until clog is cleared up. The server uses less memory and is more responsive to I/O connections

SQL Injection

How to prevent it from happening

1. Prepared statements

Prevent hackers from forcing your sql queries to do things it was not intended to do. For SQLite, use sqlite3_prepare() to create a statement object. Try: strongly validate all data or excape all user-supplied input using an escaping routine specific to your database vendor.

2. Escaping all user-supplied input

Should be used as a last resort, when nothing else is feasible - this method is frail when compared to other methods and cannot guarantee it will prevent all sql injection. This is only recommended to retrofit legacy code or low risk tolerance applications.

3. Web applicaiton firewall

Use something like ModSecurity's ever-evovlving set of rules to filter potentially dangerous we requests (avail free for Apache, Microsoft IIS, and Nginx).

4. Limit database privileges

Create multiple databases with minimum levels of privilege for their usage environment. This way, a breach through one channel cannot be leveraged to compromise the entire database.

5. Avoid SQL queries with user input

6. Suppress error messages

Keep them local and if needed in external use, keep them generic

7. Escaping in MySql

Caution These methods of escaping only works when the NO_BACKSLASH_ESCAPES SQL mode is disabled (it is enabled by defaul in MySQL servers).

In order to avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the mysql.escape(), connection.escape(), or pool.escape() methods:

var userId = 'some user provided value';
var sql    = 'SELECT * FROM users WHERE id = ' + connection.escape(userId);

connection.query(sql, function (error, results, fields) {
  if (error) throw error;
  // ...
});

Alternatively, you can use ? characters as placeholders for values you would want to escape. Multiple placeholders are mapped to values in the same order as passed. For example, in the following query foo equals a, bar equals b, baz equals c, and id will be userId:

connection.query('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', ['a', 'b', 'c', userId], function (error, results, fields) {
  if (error) throw error;
  // ...
});

Escaping query identifiers: if you can't trust an sql identifier (database/table/column_name) use mysql.escapeId(identifier), connection.escapeId(identifier) , or pool.escapeId(identifier) .

var sorter = 'date';
var sql    = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter);
connection.query(sql, function (error, results, fields) {
  if (error) throw error;
  // ...
});

Preparing queries: you can use mysql.format() to prepare query with multiple insertion points. This method safely prepares a query for the database.

var sql = "SELECT * FROM ?? WHERE ?? = ?";
var inserts = ['users', 'id', userId];
sql = mysql.format(sql, inserts);

OOP

Programming paradigm based upon objects that aims to be modular and reusable

OOP is a programming paradigm organized around objects rather than "actions" and data rather than logic.

Important features

  • bottom-up approach in programming
  • programs organized around objects, grouped in classes
  • focus on data with methods to operate upon object's data
  • interaction between objects through functions
  • reusability of design through creation of new classes by adding features to existing ones

SOLID is a basic object oriented design (OOD) principle. Its purpose is to ensure that you construct your classes in maintainable and reusable manner, and to limit any modification pain.

Letter Concept Explanation
S Single Responsibility Principle Classes should have only one responsibility
O Open/Closed Principle Objects should be open for extension, but closed for modification
L Liskov Substitution Principle Subtypes of an object should be able to substitute other objects of that subtype
I Interface Segregation Principle Clients should not be forced to depend upon interfaces they don't use
D Dependency Inversion Principle Entities must depend on abstractions not on concretions

I've attached great articles to read on each principle but let me try to condense it into easily digestable segments

Single Responsibility Principle

a class should have only ONE responsibiliy.

Why? - If a class has too many responsibilities, any change to one class may cascade down to all the other classes.

Good Example:

class User {
	fetchUser() {
		return db.query(SQL-STATEMENT)
	}
	createUser() {
		return db.query(SQL-STATEMENT)
	}
}

Bad Example:

class User {
	fetchUser() {
		return db.query(SQL-STATEMENT)
	}
	fetchPosts() {
		return db.query(SQL-STATEMENT)
	}
	createPosts() {
		return db.query(SQL-STATEMENT)
	}
}

Very simple, in the bad example, the User class is, for some reason, responsible for fetching and creating posts. The problem inherent in this is that if you wanted to change a method in the parent class, then you'll have to change all the subclasses created from that parent object. unrelated some shit

Open/Closed Principle

write code that doesn't have to be changed every time the requirements change.

Example:

Let's say we wanted to create a class that can calculate the area of a rectangle.

We start by creating a class for a rectangle:

class Rectangle {
	constructor(height, width) {
		this.height = height;
		this.width = width;
	}
}

Then we create a class for an area calculator:

class AreaCalculator {
	calculateArea(height, width) {
		return height * width;
	}
}

Now we can instantiate an instance for both classes and pass in the rectangle specs to the area calculator:

const rect = new Rectangle(5,3);
const area = new AreaCalculator();

area.calculateArea(rect.height, rect.width); // => 15

The problem becomes evident here. If you wanted to be able to calculate the area of another shape like a triangle, then you'd have to rewrite the AreaCalculator class to handle another shape.

This violates the 'closed for modification' clause as now you are forced to rewrite some code.

Solution?

const areaCalculator = (shapes) => {
	let area = 0;
	shapes.forEach((shape) => {
		area += shape.area();
	})
	return area;
}

class Shape {
	area() {
		return area;
	}
}

class Rectangle extends Shape {
	constructor(height, width) {
		this.height = height;
		this.width = width;
	}
	area() {
		return this.height * this.width;
	}
}

class Circle extends Shape {
	constructor(radius) {
		this.radius = radius
	}
	area() {
		return this.radius * this.radius * Math.PI
	}
}

const rect = new Rectangle(5,3);
const circ = new Circle(2);

areaCalculator([rect, circ]);

Now we have this nice global area calculator that will give you the total area of any number of shapes.

Liskov Substitution Principle

This is where it starts to get a little convoluted...

If S is a subtype of T, then objects of type T may be replaced by objects of type S.

What...?

That basically means subtypes must be able to substitute for their base types.

Still what? Here's an example.

Example:

class Car {
	drive() {
		return 'we driving';
	}
	fillUpGas() {
		return 'filling up!';
	}
}

class Tesla extends Vehicle {
	
}

class Driver {
	constructor(vehicle) {
		this.vehicle = vehicle;
	}
	start() {
		this.vehicle.fillUpGas();
		this.vehicle.drive();
	}
}

const myCar = new Tesla();
const me = new Driver(myCar); // => this will throw an error 

Driver using a Tesla will run into an error as a Tesla does not have the fillUpGas method. Thus, in programming and according to our definition, a Tesla really isn't a car.

The LSP forces us to think about reality and definitions in a different way. Although a Tesla is in fact a car in real life, our current class does not support it. Thus, in our own definition, a Tesla is not a car but a mere representation of a car.

Interface Segregation Principle

clients should not be forced to depend upon interfaces they don't use

Example:

class Shape {
	area() {
		return area;
	}
	volume() {
		return volume;
	}
}

Not all shapes will have a volume associated with it. Thus, it's better to simply create two separate classes; one for each operation.

class Area {
	calculate() {
		return area;
	}
}

class Volume {
	calculate() {
		return volume;
	}
}

Now, we don't have any unnessary methods associated to a class!

Dependency Inversion Principle

depend on abstractions not on concretions

Bad Example:

class PasswordReminder {
	connect(mySQL) {
		mySQL.connect();
	}
}

Good Example:

class DBConnector {
	constructor(db) {
		this.db = db;
	}
	connect() {
		this.db.connect();
	}
}

class PostgreSQL extends DBConnector {
	connect() {
		return 'Database connected';
	}
}

class PasswordReminder {
	connect(DBConnector) {
		return 'connected';
	}	
}

So, as you can see, if we wanted to change DBs then we'd have to change password reminder to reflect that. This violates the Open/Closed principle.

So instead, we create a different class that simply connects the DB for us. That way, any changes in the DB is simply extending the class of DBConnector.

Data warehouse

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment