Share this blog!

Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts
Hi all!

This is the final of the article series of building a simple JavaScript weather app!

Previous articles:

  1. Part 1 ~ API design
  2. Part 2 ~ Backend Application
  3. Part 3 ~ Frontend Application Basics 

In this article, we will be continuing our discussion on the frontend application mainly focusing on the implementation of components inside the src/components.

components/form.jsx file:

This file corresponds to the "Form" component and following are the main elements in it.

1. Optional error message: Note how error condition is checked and the error is displayed only if there is an error.

2. The title: The title of the application in an <h1> tag

3. The search bar: I used react-select to obtain a searchable select list (More information on react-select). Note how the onSubmit action handles the weather loading functionality.


import React from "react";
import "./form.style.css";
import Select from 'react-select';


const Form = props => {

  return (
    <div className="container">
      <form onSubmit={props.loadweather}>
        <div>{props.error ? error(props.errorMessage) : ""}</div>
        <div className="row">
            <div className="col-md-6 text-left">
                <h1>Weather App</h1>
            </div>
            <div className="col-md-4">
                    <Select
                        placeholder={"Search for a City..."}
                        className={"text-left"}
                        options={props.options}
                        isSearchable={true}
                        onChange={props.selectLocation}
                        name={"location"}
                        defaultValue={props.options.filter(option => option.value === props.selectedLocation)}
                    />
              </div>
              <div className="col-md-2">
                <button className="btn btn-primary">Get Weather</button>
             </div>
        </div>
      </form>
    </div>
  );
};

const error = props => {
  return (
    <div className="alert alert-danger mx-5" role="alert">
      {props}
    </div>
  );
};

export default Form;



components/weather.jsx file:

This component corresponds to the weather section of the application and this encapsulates the current weather condition and the forecasted weather data. When you look into the render returned, you can see how the data is passed into the child components.

Additionally, I used this component to hold 2 methods used by the child components:

  1. getConditionIcon: This method reads the condition name from data and returns the corresponding icon class name.
  2. getReadableDate: This method reads the unix timestamp from the data and returns a formatted date. E.g. converts "1580301692118" to "Thursday, 05/03/2020"


import React from "react";
import CurrentCondition from "./currentcondition";
import Forecast from "./forecast";
import 'react-table-6/react-table.css';
import './weather.style.css';

const Weather = props => {
    console.log(props);
    if (!props.location || !props.data) {
      return <div />;
    }

  return (
      <div>
      <CurrentCondition
        location={props.location}
        data={props.data[0]}
      />
      <Forecast
        data={props.data} />
    </div>
  );
};


export default Weather;

export const getConditionIcon = (conditionName) => {
    const weatherIcon = {
      Thunderstorm: "wi-thunderstorm",
      Hail: "wi-hail",
      Drizzle: "wi-sleet",
      Rainy: "wi-storm-showers",
      Snow: "wi-snow",
      Atmosphere: "wi-fog",
      Sunny: "wi-day-sunny",
      Cloudy: "wi-cloudy",
      Hurricane: "wi-day-hurricane",
      Windy: "wi-windy",
      Tornado: "wi-day-tornado"
    };
  return weatherIcon[conditionName];
}

export const getReadableDate = (dateToRead) => {
    //convert unix to human readabale date
    var d = new Date(dateToRead);
    var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

    var weekDay = days[d.getDay()];
    var date = d.getDate();
    var month = d.getMonth() + 1;
    var year = d.getFullYear();
    var readableDate = weekDay + ", " + date + "/" + month + "/" + year;
    return readableDate;
}



components/currentcondition.jsx file:

This file represents the "CurrentCondition" component that displays the weather of the current timestamp.

The returned rendering divides the row into 3 columns (using col-sm-4) and each data element is fed corresponding data.

The getReadableTime method converts the timestamp value to a readable time format using 12-hour clock. E.g. "19:12:00" is converted to "7.12 pm".



import React from "react";
import {getConditionIcon, getReadableDate} from './weather';

const CurrentCondition = props => {

    const parts = props.location.split(",");
    const city = parts[0];
    const region = parts[1];
    const country = parts[2];

  return (
      <div className="row">
          <div className="col-sm-4  color-card">
              <div className="container">
                  <h4>{city}</h4>
                  <h6>{region}, {country}</h6>
                  <p>{getReadableDate(props.data.forecastDate)}</p>
              </div>
          </div>
          <div className="col-sm-4 color-card">
              <div className="container">
                  <h4>{props.data.conditionName}</h4>
                  <div className="container">
                    <i className={`wi ${getConditionIcon(props.data.conditionName)} display-1`}></i>

                  </div>
                  <h1>{props.data.temperature}&deg;C</h1>
                  <p>
                    <span className="temp-low">{props.data.low} &deg;C</span>
                    &&/&&
                    <span className="temp-high">{props.data.high} &deg;C</span>
                  </p>
              </div>
          </div>

          <div className="col-sm-4 color-card">
              <div className="container ">
                  <p>Humidity: {props.data.humidity}%</p>
                  <p>Visibility: {props.data.visibility}km</p>
                  <p>Pressure: {props.data.pressure}hPa</p>
                  <p>Wind: {props.data.windSpeed}km/h</p>
                  <p>Sunrise: {getReadableTime(props.data.sunrise)}</p>
                  <p>Sunset: {getReadableTime(props.data.sunset)}</p>
              </div>
          </div>
      </div>
  );
};

function getReadableTime(timeToRead){
    var time = timeToRead.split(":");
    var hours = parseInt(time[0]);
    var suffix = "am";
    if(hours > 12){
        suffix = "pm";
        hours -= 12;
    }
    return hours + "." + time[1] + " " + suffix;
}

export default CurrentCondition;



components/forecast.jsx file:

This file corresponds to the table that displays the forecasted weather information. I have used ReactTable (imported from react-table-6) to display the forecasted weather in a tabular format (More information on ReactTable).



import React from "react";
import {getConditionIcon, getReadableDate} from './weather';
import ReactTable from "react-table-6";

const Forecast = props => {

    const data = props.data;

    const columns = [
      {
        id: 'date',
        Header: 'Date',
        accessor: d => getReadableDate(d.forecastDate) // String-based value accessors!
      }, {
        Header: 'Condition',
        accessor: 'conditionName',
        //Cell: props => <span className='number'>{props.value}</span> // Custom cell components!
      }, {
        id: 'conditionIcon',
        Header: 'ConditionIcon',
        accessor: d => getConditionIcon(d.conditionName),
        Cell: row => (
            <span>
              <i className={`wi ${row.value} display-5`} />
            </span>
          )
      }, {
        Header: 'High',
        accessor: 'high',
        Cell: row => (
            <span className="temp-high">{row.value} &deg;C</span>
        )
      }, {
        Header: 'Low',
        accessor: 'low',
        Cell: row => (
            <span className="temp-low">{row.value} &deg;C</span>
        )
      }
];

    const TheadComponent = props => null
  return (
      <div className="row">
        <div className="container color-card">

          <ReactTable
            data={data}
            columns={columns}
            minRows={0}
            showPagination={false}
            TheadComponent={TheadComponent}
            />
        </div>
      </div>
  );
};


export default Forecast;


components/weather.style.css file:

Last but not least, I have used a few custom CSS for styling purposes:



.container {
  margin: 2.2rem auto;
  padding: 20px;
}

.color-card{
    background: rgba(256, 256, 256, 0.6);
}

.container input,
.container ::-webkit-input-placeholder {
  /* color: white !important; */
}
.container input:focus {
  background-color: transparent;
  box-shadow: none !important;
  border: none;
  border-bottom: 2px solid tomato;
}

.col-centered{
    margin: 0 auto;
    float: none;
}

.temp-high{
    color: Tomato;
}

.temp-low{
    color: DodgerBlue;
}

.display-5{
    font-size: 1.5rem;
    font-weight: 300;
    line-height: 1.2;
}

That's it!! After adding some custom CSS, the end result should look like below.



Cheers!


Hello all!

This is part 3 of the article series of building a simple JavaScript weather App.

In part 1, we discussed about the API design perspectives and the architecture of the application. In this article, we will be discussing about the backend implementation of the application, which is essentially about implementing the API we discussed previously.

In part 2, we implemented our backend application which deployed our weather API.

In this article, we will be implementing a front end (react) app that will be calling the APIs and retrieving information and then displaying them in the browser. Since it will be lengthy, we will look at the implementation of each component in the next article and look at the page design and data retrieval in this article.

So the plan is to allow the user to pick a location from a list of supported locations and then display the corresponding weather information in the screen. Additionally, we will use sticky sessions to let the browser remember the user's last-searched location.

If you have react installed already, you can use the following command format to create an application and start it.

npm install -g create-react-app
create-react-app weather-app
cd weather-app
npm start

The project skeleton that will be created would look like the following:


Project
|
|-------node_modules
|
|-------public
|
|-------src
| |-------assets
| |-------components
| |-------config
| |-------service
| |-------App.css
| |-------App.js
| |------- ...
|
|-------.gitignore  
|-------package-lock.json  
|-------package.json


And you guessed it right, we will be altering the files inside the "src" to get our app up and running.

Retrieving the data

We will start by implementing the Rest API calls, but before that, we will configure the Rest API endpoints in the src/config/config.js file:

config.js file:

'use strict'


const config = {
 locationsAPI: "http://localhost:8080/locations",
 forecastsAPI: "http://localhost:8080/forecasts?location="
}

module.exports = config

Once the endpoints are configured, we can call them using the following methods in src/service/apiservice.js file in a class called Api.

The class has 3 methods:

  1. loadLocations - Calls the location endpoint and retrieve a list of locations, format the items in the list (by calling the method explained next) and return the list. Note that we are returning the list in the format {options: ...}, which is used by the react-select component we will be using to display the search options. (More about it in the "Form Component" section below.
  2. formatLocationList - Format the list of locations by concatenating the city, region and country by commas (which could be directly fed into the select box)
  3. loadWeather - Calls the weather endpoint with the selected location and return the result


apiservice.js file:


import Config from './../config/config';

export default class Api{

  //retrieve the list of locations from the API call
  loadLocations(){
      return fetch(Config.locationsAPI).then((response) => {
            if(!response.ok){
                throw new Error(response.statusText);
            }
            else return response.json();
        })
        .then((data) => {
            return {
                options:this.formatLocationList(data),
                error: false
            };
        })
        .catch((error) => {
            return {
                error: true,
                errorMessage: error.message
            };
        });
  }

  //format the retrieved location list to map to required format
  formatLocationList(data){
      //convert result from api into objects with fields "label" and "value"
      var options = data.map(function(val, index){
              return {
                  value:val.city+","+val.region+","+val.country,
                  label:val.city+", "+val.region+", "+val.country
              };
      });
      return options;
  }


  //load the weather of the selected location
    loadWeather(location){

      return  fetch(Config.forecastsAPI+location).then((response) => {
            if(!response.ok){
                throw new Error(response.statusText);
            }
            else return response.json();
        })
        .then((data) => {

            return {
                location: location,
                data: data,
                error: false
            };
        })
        .catch((error) => {
            console.log("Error: " + error.message);
            return {
                location: location,
                data: undefined,
                error: true,
                errorMessage: location + ": " + error.message
            };
        });
  }
}

Components

Now let's take a step back and look at how we want the end application to look like. I like to keep things simple, so I came up with a single page app and the (desktop browser) wireframes look like below:

Since we are going to implement this in react, we need to divide them up into components and I used the following component structure and all the component implementations will be stored inside "src/components" folder:



When you take a look at the above, you can see that there is a search bar for which we will be using a searchable select input type. Once a user picks a location and hits the "Search" button, the related weather information should be displayed as shown above.


App.js file:


So let's start by App.js file, which contains the entire page.

1. constructor(): The constructor method initializes the state and the Api objects. In the state, I have kept track of the list of options (locations), the selected location, the weather data relevant to the location and error details.

2. componentDidMount(): This method is called once in the component lifecycle and is the best place to make API calls. Note that I have used localStorage to check if there is an existing location in the memory, if so, the weather for that location will be loaded. If there is no location in the memory, only the list of locations (the search bar) will be displayed to the end user.

3. getWeather : I have defined an asynchronous method to handle the form submit in the search bar. This method will be fed into the "Form" component as the onSubmit functionality. When the user selects a location and clicks the Search button, this method will be fired. This method will read the selected location, set the localStorage (for sticky sessions), call the weather API and set the state. When the state is updated, the page is rerendered, causing the weather data to be displayed.

4. render(): This method contains the components of the application. Note that we have included only the "Form" and "Weather" components, which are the outermost components of our app, and each sub components will be inside their respective parents. Also take a note on how the data is passed between components.



import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import "weather-icons/css/weather-icons.css";
import "./App.css";
import Form from "./components/form";
import Weather from "./components/weather";
import API from './service/apiservice';



class App extends React.Component {
  constructor() {
   super();
   
   this.state = {
    options: undefined,
    location: undefined,
    data: undefined,
    error: false,
    errorMessage: undefined
   };
   this.api = new API();
  }

  //get the list of locations
  //invoked immediately after a component is mounted
  componentDidMount() {

   //if local storage contains a saved value, load the saved location's weather
   var locationFromStorage = localStorage.getItem('weatherAppLocation');
   if (locationFromStorage) {
    this.api.loadWeather(locationFromStorage).then((response) => {
     this.setState(response);
    });
   }

   //load the list of locations in the dropdown
   this.api.loadLocations().then((response) => {
    this.setState(response);
   });

  }

  //define the function for getting the weather of selected city
  getWeather = async e => {
   e.preventDefault();

   //get the selected value of the dropdown
   const location = e.target.elements.location.value;

   if (location) {
    localStorage.setItem('weatherAppLocation', location);
    this.api.loadWeather(location).then((response) => {
     this.setState(response);
    });

   } else {
    this.setState({
     error: true,
     errorMessage: "Please enter a location"
    });
   }

  };

  render() {
              if(!this.state.options) return null;

              return (
                    <div className="App">
                 <div className="container col-centered">
                      <Form
                       options={this.state.options}
                       loadweather={this.getWeather}
                      selectedLocation={this.state.location}
                       error={this.state.error}
                       errorMessage={this.state.errorMessage}
                      />
                      <Weather
                     location={this.state.location}
                     data={this.state.data}
                      />
                   </div>
                    </div>
              );
           }
}

export default App;

Let's dig deep into each of the components in the next article! Cheers!
Hello all!

This is part 2 of the article series of building a simple JavaScript weather App.

In part 1, we discussed about the API design perspectives and the architecture of the application. In this article, we will be discussing about the backend implementation of the application, which is essentially about implementing the API we discussed previously.

In this tutorial, we will be:

  1. Initiating a node project
  2. Mapping API endpoints to functions
  3. Configuration and connecting to a database
  4. Querying the database and return result
  5. Testing the API

Things we will NOT be talking about and act as prerequisites:

  • Installing node, MySQL etc.
  • Setting up MySQL or generating mock data
  • Installing packages


A quick recap from the last article, the API we came up with has the following endpoints and use cases:

  1. GET   /locations - Retrieve list of locations that can be forecasted ordered alphabetically by the city
  2. GET   /conditions - Retrieve list of supported weather conditions
  3. GET /forecasts - Retrieve weather forecast of a city defined by query parameter, responding with an array of 10 forecast items. (Optional "limit" query parameter can define the expected forecast count)


Initializing the project

You can simply use npm init to start a node project.

In addition to the usual node project structure, I have added some extra packages so that the services, db management and configurations are separately stored.

Project 
|-------api 
|        |-------swagger.yaml
|-------config 
|        |-------config.js 
|-------db 
|        |-------db.js 
|-------node_modules 
|-------service 
|        |-------condition.service.js 
|        |-------forecast.service.js 
|        |-------location.service.js 
|-------.gitignore 
|-------index.js 
|-------package-lock.json 
|-------package.json

Swagger definition

The content of swagger.yaml can be found in this gist (https://gist.github.com/sachi-d/0f2c0af614723aab0c30095fdfcbe93c) and it was added to the project as a reference to the API definition we came up with. 

You can use swagger to generate the server code from the yaml, but in this tutorial, we will be writing the API functionality by hand simply because our API is not that complicated.

Index.js

The index.js file contains the mappings of the API endpoints and it is essentially the starting point of the application. 

You may notice that the endpoints are mapped into functions in the service layer and finally, the app is listening to the port defined in the configuration. Note how the headers are being used to enable CORS.


const express = require('express');
const app = express();
const mysql = require('mysql');
const config = require('./config/config.js');
const db = require('./db/db.js');
global.db = db;


const {getLocations} = require('./service/location.service');
const {getConditions} = require('./service/condition.service');
const {getForecasts, getForecastsByID} = require('./service/forecast.service');

//enable CORS
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

//map the endpoints with the functions
app.get('/locations', getLocations);
app.get('/conditions', getConditions);
app.get('/forecasts', getForecasts);


const port = config.port;
app.listen(port, () => console.log(`Listening on port ${port}..`));

Configuration file

My config.js file content are as follows, but you can add any kind of configuration/variable options in this, so that you can easily access/update them on the run.

'use strict'

const config = {
 port: process.env.PORT || 8080,
 db: {
  host: 'localhost',
  user: 'mydb-username',
  password: 'mydb-password',
  database: 'mydb-database-name',
  multipleStatements: true
 }
}

module.exports = config

Database connection

I used the db.js file as the database manager, to handle the connection creation.

const mysql = require('mysql');
const config = require('./../config/config.js');

const db = mysql.createConnection (config.db);

// connect to database
db.connect((err) => {
    if (err) {
        throw err;
    }
    console.log('Connected to database');
});

module.exports = db;

Endpoints

I used the service package to collect the data from the database and then expose them through the endpoint. Alternatively, you can achieve more coherency by using a separate DAO layer to retrieve the data and then using a service layer to handle the business logic.

The following code represents the SQL query execution, which retrieves the list of supported weather conditions and locations and then responds to the API requests with the collected data. 


condition.service.js


module.exports = {
 getLocations: (req, res) => {

  //retrieve a list of available locations
  let query = "SELECT * FROM `location` ORDER BY city";

  // execute query
  db.query(query, (err, result) => {
   if (err) {
    console.log(err);
    res.status(400).send("An unexpected error occurred while retrieving locations.");
    return;
   }
   res.send(result);
   return;
  });
 }
};


location.service.js


module.exports = {
 getConditions: (req, res) => {
  //returns a list of supported weather condition names and IDs
  let query = "SELECT * FROM `weathercondition` ORDER BY id ASC";

  db.query(query, (err, result) => {

   if (err) {
    console.log(err);
    res.status(400).send("An unexpected error occurred while retrieving weather conditions");
    return;
   }
   res.send(result);
   return;
  });
 },
};



forecast.service.js

The forecast endpoint implementation seems like the most complicated of all, but when you break down the functionalities, you can easily understand what is happening in the code.

The endpoint requires the location as a query parameter which should be defined by the city, region and the country, separated by commas (inspiration was from Yahoo weather API).

For example,

/weaptherAPI/forecasts?location=Sydney,NSW,Australia 

is a valid API call while

/weaptherAPI/forecasts?location=Sydney,Australia 
/weaptherAPI/forecasts?location=NSW,Australia 
/weaptherAPI/forecasts?location=Sydney

are invalid API calls.

Optionally, the limit query parameter can be used to limit the number of results retrieved, if limit is not defined, 10 results will be returned by default.

When analysing the following code, you may observe how the query parameters are parsed and validated. I have used error messages to handle validation failures. If validations are successful, the parameters will be fed into the SQL query which would return the results as an array.


module.exports = {
 getForecasts: (req, res) => {
  //returns a list of weather forecasts for the specified location

  //if limit is not set, return 10 results by default
  const limit = req.query.limit || 10;
  if(isNaN(limit)){
   res.status(400).send('Invalid request: Invalid limit parameter');
   return;
  }

  const location = req.query.location;

  //location is a required parameter
  if (!location){
   res.status(400).send('Invalid request: Missing location parameter');
   return;
  }


  const parts = location.split(",");

  if(parts.length != 3){
   res.status(400).send('Invalid location parameter');
   return;
  }
  const city = parts[0].trim();
  const region = parts[1].trim();
  const country = parts[2].trim();


  let query = `SELECT w.*, c.conditionName FROM
          (SELECT weather.* FROM weather, location WHERE idLocation = location.id
     AND location.city = "${city}"
     AND location.region = "${region}"
     AND location.country = "${country}"
            AND forecastDate >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY) * 1000
            ORDER BY forecastDate
            LIMIT ${limit}) as w
          LEFT JOIN
            (SELECT id as conditionID, name as conditionName FROM weathercondition) c
            ON w.idCondition = c.conditionID`;


  // execute query
  db.query(query, (err, result) => {
   if (err) {
    console.log(err);
    res.status(400).send("An unexpected error occurred while retrieving weather forecasts");
    return;
   }
   if(result.length == 0){
    res.status(404).send(`No data found for ${location}`);
    return;
   }
            res.send(result);
  });

 }
};



Testing the API

Now your application is ready to run. Use node index.js to start the application in your machine and since all the endpoints are GET type, you can simply use the browser to view the results. 

Access the following URLs to view your results in the browser:

  • http://localhost:8080/locations
  • http://localhost:8080/conditions
  • http://localhost:8080/forecasts?location=any+location+you+have+dummy+data+of

When implementing an API that can be called by a third party application, it is quite important to handle all possible scenarios. These scenarios include both valid and invalid inputs which need to be handled carefully in your implementation. In order to test your application, it is essential to list down the test scenarios that are applicable. The following depicts some of the test scenarios that need to be tested against our application.



Once the test scenarios are identified, testing needs to be carried out. This can be done either manually or programmatically, which we will talk about in a future article.

That's it for the the backend implementation and feel free to share anything you would find useful in the comment section.

Cheers!


Introduction

Hello all! 

This will be the first of the article collection that we will be going through to implement a simple weather app using JavaScript for the full stack. The weather app would have:

1. A Rest API that would give us current and forecasted weather for predefined locations
2. A web application that would display the current and forecasted weather of a selected location

To achieve the above, we would need to make some decisions. 

Since we are going to pursue everything using JS, we could easily use NodeJS to implement a backend server that would deploy the Rest API. For the front end app, we do have a lot of choices, but in this tutorial, we will be using React. We also need some sort of DB integration to read the weather data from. To limit the scope of this tutorial, let's skip how the data is entered and worry only about reading data from the database. 

In this tutorial, we will be talking about the following topics:

1. Part 1 - The architecture and API design
4. Part 4 - Front end implementation ~ Components


In Part 1, we will be discussing about the architecture and the design considerations of the API. We will be talking about:

  1. A proposed architecture for the backend and client apps
  2. A little introduction to Rest APIs
  3. Proposed API endpoints and their parameters and responses

The Architecture

As mentioned above, the purpose of this tutorial is to implement a simple weather app using JavaScript. It might sound like one big app, but it could be easily reusable and made more independent if we have 2 different apps for the backend and frontend respectively. Implementing a Rest API would basically mean the same thing.

In terms of the data, we could integrate a database and expose the data in the Rest API, which can be called by any third party app and display the data any way they like. Think of our backend as something similar to the Yahoo or the OpenWeatherMap API.

So the architecture I would go for would be as follows:


As you can see, the 3 main components would be our backend, frontend and the DB. 

Starting the implementation of the client app first would not be a very good idea, because you would not have an idea about the data you would be getting from the APIs. So the best course of actions (or the TODO list) would be as follows:

1. Design the APIs
2. Implement the APIs (backend)
3. Implement the client App

So let's get ready to tick-off our first to-do item!

API Design

If you're an expert on Rest APIs, you may skip the following section, but everyone else, gather up for a very brief introduction to Rest APIs and the bits of information you should absolutely know about Rest APIs.

A RESTful API is simply an application program interface (API) that uses HTTP requests to exchange data (communicate) between components. These communications can be of the following types:
  • GET - read data
  • PUT - update data
  • POST - insert data
  • DELETE - delete data

Restful APIs should always comply to the following constraints:
  1. Use of a uniform interface (UI) - The purpose of Rest APIs is to communicate with servers to get/update information on resources. And this constraint simply means that any resource should be defined using URIs (uniform resource identifiers) that should be self descriptive. For example, if an API is used to retrieve details of a book "/books/1234" is resource based and is a better design than "books/the+book+I+bought+today" as the latter doesn't seem like a uniform identifier for a book.
  2. Client-server based - There should be a clear delineation between the client and server. UI and request-gathering concerns are the client’s domain. Data access, workload management and security are the server’s domain. This loose coupling of the client and server enables each to be developed and enhanced independent of the other.
  3. Stateless operations - All client-server operations should be stateless, and any state management that is required should take place on the client, not the server.
  4. RESTful resource caching - All resources should allow caching unless explicitly indicated that caching is not possible.
  5. Layered system - REST allows for an architecture composed of multiple layers of servers. So it is valid if a client app doesn't know if he is directly calling a server or if it goes through multiple layers that would finally land on the server.
  6. Code on demand - Most of the time a server will send back static representations of resources in the form of XML or JSON. However, when necessary, servers can send executable code to the client.

Now let's think about how the weather APIs could be used and what kind of data to be exposed.

If the end user has the ability to select a location, he should be provided with a list of locations to choose from. Therefore we need one API to list the locations.

Secondly, when the end user picks a location, the current and the forecasted weather should be delivered, therefore the second API we need is the weather API which is bound to a selected location.

Additionally, I thought of letting the developers know the list of supported weather conditions, so that they can easily configure the icons and what not to show on their client applications. Therefore an additional weather condition API too would be implemented.

Considering all of the above, the following are the APIs that I came up with:

  1. GET   /locations - Retrieve list of locations that can be forecasted ordered alphabetically by the city
  2. GET   /conditions - Retrieve list of supported weather conditions
  3. GET /forecasts - Retrieve weather forecast of a city defined by query parameter, responding with an array of 10 forecast items. (Optional "limit" query parameter can define the expected forecast count)
You can use editor.swagger.io to interactively view the full API definition (with the input/output definitions) in yaml is hosted in Github, which is added in the end of this article to avoid clutter.

In order to make things easier, I designed the database to match the API design, which has exactly 3 tables following the ERD (make sure to populate dummy data to view in the app):

That will be all for now, and let's talk about implementing the backend in the next chapter!

The complete API definitions:

You can use editor.swagger.io to interactively view the full API definition (with the input/output definitions) in yaml is hosted in Github.


You may have already come across situations where web forms statically alert you about the availability of a username or email without loading another page or refreshing the page. In this post, we will be discussing how to achieve this using AJAX script and JSP.



Let's assume our html form is as follows. Please note that I'm adding only the relevant components. 

<form name="myForm" onsubmit="return validate()">
    <label>Username:</label>
    <input type="text" name="userName" onblur="checkUniqueness()" />
    <span id="eMsg" style="color:red;"></span>
</form>

In this example, I'm using onblur which is triggered when the focus is lost, for example when the user selects the next input or clicks somewhere else on the form after typing the username.There are many other options you can use such as a separate button to check it or check during validation.  I am also using a span with red color text to display the error message.

The onsubmit="return validate()" is also important. If the validate is returning true, or there is no validate, the form will be submitted while we are checking the username and the process after submission will be occurring. The validate method prevents a form from submitting under given conditions. Therefore it is important that there is a condition that prevents the form from submitting during our username checking AJAX call.

The JavaScript function with the AJAX call is as follows:

function checkUniqueness() {
          var xmlhttp = new XMLHttpRequest();
          var username = document.forms["myForm"]["userName"].value;
          var url = "exist.jsp?username=" + username;
          xmlhttp.onreadystatechange = function () {
               if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
                      if (xmlhttp.responseText.includes("NO")) {
                            document.getElementById("eMsg").innerHTML = "Username already exists";
                      }
               }
          };
          try {
                xmlhttp.open("GET", url, true);
                xmlhttp.send();
          } catch (e) {
                alert("unable to connect to server");
          }
}

As you can see, we need a JSP that has the ability to check the uniqueness by reading data from somewhere, probably a database. The following represents a comprehensive example of the JSP, including the database call.

<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="DB.DBConnectionHandler"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@page import="Controller.DBDataList"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%
    if (null != request.getParameter("username")) {   //check if parameter is there
        String uname = request.getParameter("username");  //extract username parameter
        try {

            //create connection and make the db call
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/highertradesmendb", "root", "hahaha");
            String query = "SELECT * FROM user where username=?";
            PreparedStatement ps = con.prepareStatement(query);
            ps.setString(1, uname);
            ResultSet rsetUser = ps.executeQuery();

            //check existance
            boolean stat = !rsetUser.first();
            con.close();

            //print the result
            if (stat) {
                out.print("YES");
            } else {
                out.print("NO");
            }

        } catch (Exception e) {
            System.out.println("get unique username error -  " + e);
        }
    }
%>

What is retrieved in the JavaScript is what we print to out.print and a string comparison is done in the JavaScript to define the results.



Bunny Hop is a simple JavaScript game developed using CreateJS.

The only control function is to click anywhere on the game canvas. Click to start playing, click to jump and click to start over when hit.

A spritesheet is used to animate the bunny, and a ticker keeps the game on the clock. EaselJS, a branch of CreateJS is used for the graphics and SoundJS, another branch of CreateJS provides sounds.

You can play the game using this link: http://sachi-d.github.io/myApps/Bunny_Hop/
You can find the source code on this link: https://github.com/sachi-d/Bunny-Hop

Bunny Hop - play

Bunny Hop - points

Bunny Hop - hit 

During the implementation of delete and clear container operations, I had to implement delete confirmation dialog boxes using Bootstrap Dialog. I thought of using a common confirmation function, which would take the action function as a parameter and call it if confirmed. (Note: jQuery's confirm provides similar functionality with the default dialog box)

I started by defining the following approach which works fine with global functions. But when Backbone view instances are concerned, it did not work. I assumed the problem was that the passed function has incorrect context - note that "this" prints different objects in the console.

var viewDemo = Backbone.View.extend({
    mainFunc: function(){
        this.intermediateFunc(this.ABC);
    }
    intermediateFunc : function(callback){
        console.log(this); //prints the correct view
        callback();
    }
    ABC : function(){
        console.log(this); //prints 'window' when passed through a function
    }
});


As usual, StackOverflow came up with the solution when I asked this question. The solution of mu is too short explains 3 approaches:

1. Using Function.prototype.bind


mainFunc: function(){
    this.intermediateFunc(this.ABC.bind(this));
}

2. Function.prototype.call or Function.prototype.apply


mainFunc: function(){
    this.intermediateFunc(this.ABC, this);
},
intermediateFunc : function(callback, context) {
    console.log(this); //prints the correct view
    if(context)
        callback.call(context);
    else
        callback();
}

Or the same could be used as:

mainFunc: function(){
    this.intermediateFunc(this.ABC, this);
},
intermediateFunc : function(callback, context) {
    console.log(this); //prints the correct view
    context = context || this;
    callback.call(context);
}

3. The old var self = this; trick


mainFunc: function() {
    var _this = this;
    this.intermediateFunc(function() { return _this.ABC() });
}
One of the tricky requirements faced during connector implementation was the right-click menus. I used a shared html ul components which were triggered by assigning classes, since it would be less-consumptive than creating menus for each component.

The connectors of the data mapper are used to connect input nodes to output nodes and they are implemented using svg polylines. The stroke-width of the lines were maintained at 2 and this made it hard to click on them. Therefore it was suggested to use a hidden background overlay that would be highlighted during mouse over and click and the right click menu was to be triggered on this overlay.

 As for the overlay, I used a copy of the connector, but with a wider stroke-width and defined mouseover and mouseleave event functions to change the opacity of the overlay.

It worked fine until it was observed that, when the mouse is hovered on the right click menu, mouseleave is triggered and the highlight is removed. I wished to keep the connector highlighted during its focus, which includes right click menu propagation.

After discussing with a team member on multiple solutions, it was decided to use a simple solution of manipulating classes to check if menu is displayed before triggering mouseleave.

The following needs improvement, but demonstrates the basic idea of the solution:

  1. Corresponding question on StackOverflow


As a requirement in my internship project (as described in this post), I had to insert new attributes to the JSON schema to a specified location, ie, to add an immediate sibling to the clicked node. Since JavaScript is an unordered list of properties, typical JSON methods could not be used. Therefore a solution where iterating over the keys and cloning them to a new object was used.

The sample code is as follows: 
The highlight of this week's implementation was updating the schema with the user input. The user is basically allowed to add nodes to a schema and that logic could be used to build a schema from scratch which needs an additional step of setting the root element.

The modal dialogs were implemented using BootstrapDialog which offered simple a simple template to create dynamic modal dialog boxes. I used a simple String operation to hide the add-as-child option.

var isLeaf = this.isLeafElement ? ' style="display:none;" ' : ' ';
BootstrapDialog.show({
    title: "Add new node",
    message: 'Title: <input id="title" type="text"><br>Type:<select id="type">' + this.getTypeOptionList("Object") + '</select><div ' + isLeaf + ' ><br>Add as child: <input type="checkbox" id="isChild" ></div> ',
    draggable: true,
    buttons: [{
        label: 'Add',
        cssClass: "btn-primary",
        action: function (dialogRef) {
            self.model.addNode(dialogRef.getModalBody().find('#title').val());
            dialogRef.close();
        }
    },
        {
            label: 'Cancel',
            action: function (dialogRef) {
                dialogRef.close();
            }
        }
    ]
});


The rules I assumed as optimum included:

  1. The options for the type of the root element are limited to Object and Array
  2. Only nodes of type Object or Array are allowed to add child nodes
  3. New nodes to the root element are added only as children nodes
  4. Sibling added to a node will be placed right after the triggered node
  5. Child added to a node will be placed as the last child of the triggered node
The initial goal was to update the schema, and to reload the container which will draw the tree-structure according to the updated schema. However, this will remove any current connectors attached to the container. Therefore dynamic node drawing was needed - which was kept for later consideration.

The schema-update was achieved using a recursive method, which was quite similar to the method I used to get the JSON path from a schema.

Initially, it would determine the relevant parent node of the expected new node and iterate the schema to find it. Adding as a child was not a big deal since it was to be added as the last child of the parent and simply updating the object as data[newAttribute] = newValue; would give the desired result.

Adding the sibling was the tough job since, it had to be added as the immediate sibling - to enhance user experience. The main reason was that JavaScript objects are unordered lists of properties. Therefore, in order to achieve the desired result of adding as the immediate sibling, I had to follow a String operation on parent data of the node.

The steps taken were:

  1. Select the parent data set - the target
  2. Detect the triggered node in the target set as a String
  3. Concatenate the triggered node string with the new node string
  4. Replace with the previously detected string
  5. Parse the new string as a JSON 
UPDATE: The string operation was replaced by an iterating function as in this post.

Previous PostOlder Posts Home