Tuesday, 4 April 2017

CORS & Preflight Requests

When you make a cross domain request from your website you may have your request fail. One of the potential causes for this is that the API you're calling does not handle preflight requests. You will know that this is the case because you will see an OPTIONS request to the API you made the call to, but this call will fail and no subsequent GET/POST/PUT or whatever other HTTP call you were trying to make will be made.

What's the point?

Preflight requests arose as CORS made it possible to specify more headers and requests methods in a request than was previously possible to make cross origin. This meant that some servers were developed under the assumption that they would not receive these cross-origin requests and would thus be protected from them. A preflight request provides a way for the server to opt into receiving these requests, as the server must respond to the OPTIONS request with the types of methods, headers, and origins that it accepts. This protects the server (particularly older servers), without the need for the server to change as if it doesn't respond to the OPTIONS request with headers that match the request, then the subsequent request will not be made.

Note: not all HTTP requests will have a preflight request. If the request was possible cross-origin prior to CORS, then a preflight request will not be made as older servers should have handled any security around these requests themselves.

How to get the preflight request to succeed?

Assuming that the server responds to the OPTIONS request successfully, the website should not need to make any further changes as the further requests will be handled by the browser. So if you are using a publicly exposed API and your request is failing on the OPTIONS request, you will need to confirm that the API is accepting your domain, headers and method you submitted the request with. You can do this by checking the OPTIONS response meets the following criteria:
  • Access-Control-Allow-Headers header with comma-separated list of headers you made your request with
  • Access-Control-Allow-Origin header with * or domain matching that which you are making the request from
  • Access-Control-Allow-Methods header with comma-separated list of methods you can access the endpoint with
  • Status is 200

If you want to enable your API to handle preflight requests, then you will need to be able to accept and OPTIONS request and respond to the requester with the above headers/status. The actually implementation of this will be down to the technologies you have developed your APIs using but there will commonly be APIs available to enable CORS. Note: your API that is available due cross-domain will also need to have GET/PUT/POST etc, with these headers.

References

CORS Access Control

Monday, 3 April 2017

React Native #8 - State

Previously, we discussed how we can make reusable components by passing data to a component using props. State can also be used to help us provide data to a component. However, the difference is that state is used to hold values that change, and when it changes it will trigger updates to the components that reference it. State should generally be initialised in the constructor, and set state should be used to update it.

As a simple example, consider a UI that has a text input for the users name and then a text component that greets them, it would appear as follows:

  // Import necessary components
  import React, { Component } from 'react';
  import { Text, View, TextInput, StyleSheet } from 'react-native';
  import { Constants } from 'expo';
  
  export default class App extends Component {
 
    // Initialise state to avoid state being undefined
    // state is just a javascript object with properties
    // want to keep track of the state of
    constructor(props) {
      super(props);
      this.state = { text: '' };
    }
    
    render() {
      return (
        <View style={styles.container}>
          // Render text input and when text changes
          // update state
          <TextInput
            placeholder='Name'
            style={styles.textInput}
            onChangeText={(text) => this.setState({text})}
            value={this.state.text}
          />
        
          // Render text when text changes for input
          // the hello message should update to match
          // the new state
          <Text style={styles.paragraph}>
            Hello {this.state.text}
          </Text>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      alignItems: 'center',
      justifyContent: 'center',
      paddingTop: Constants.statusBarHeight,
      backgroundColor: '#ecf0f1',
    },
    paragraph: {
      margin: 24,
      fontSize: 18,
      fontWeight: 'bold',
      textAlign: 'center',
      color: '#34495e',
    },
    textInput: {
      height: 40,
      borderColor: 'gray', 
      borderWidth: 1
    }
  });