Category Archives: Web Development

How to solve Postman “Could not get any response” error

Trying to build a REST API can be really frustrating. You install Express.js with mongoose or mongodb, and then create a schema, just following the instructions, and you think everything should work. You set up Postman to test the API, hit the API, and Postman stays at “sending request..” for a while. You wait… and wait… and then eventually you see the message “Could not get any response”.

Postman Could not get any response
Postman Could not get any response

Sometimes, it works fine to set everything up all at once. But, it can often happen that there are just too many moving parts. When that happens, and something breaks, it can be very difficult to figure out the point of failure.

As an example, suppose you have an Express router which handles a POST request like this using a mongoose model:

const router = require('express').Router();
// ... mongoose code here
router.post('/registerKitten', async (req, res) => {
    const fluffy = new Kitten({ name: 'fluffy' });
    try {
        await fluffy.save();
        res.json(fluffy);
    } catch(err) {
        res.status(400).send(err);
    }
})

If Postman times out when hitting the API, you can’t know whether the problem is in Express.js or Mongoose.

The first, simple thing you can do is add some console logging to see if your route is executed:

const router = require('express').Router();
// ... mongoose code here
router.post('/registerKitten', async (req, res) => {
    console.log("registerKitten");
    const fluffy = new Kitten({ name: 'fluffy' });
    try {
        console.log("awaiting save...");
        await fluffy.save();
        console.log("save is finished");
        res.json(fluffy);
    } catch(err) {
        res.status(400).send(err);
    }
})

That won’t tell you the whole story, however. If you see “awaiting save…” but don’t see “save is finished”, then doing this has helped you locate the problem – mongoose is hanging.

At this point, you may be better off writing a small Node.js test script which will just exercise the code related to mongoose, independently of Express. That way, you can debug the problem without having to deal with Express code or restart your Express server.

Here’s some sample code. You’ll have to adjust this to your own specific case, but the idea is to put this code into a script (test.js) and run it from the command line with node test.js:

"use strict";
const mongoose = require('mongoose');
const Kitten = require('./models/Kitten');

mongoose.connect(process.env.MONGO_DB_URL, { useNewUrlParser: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));

// Set up some mock user data
const fluffy = new Kitten({ name: 'fluffy' });

// When the db is open, 'save' this data.
db.once('open', async function () {
    // we're connected!
    console.log("db opened... going to save the kitten");
    await fluffy.save();
    console.log("printing fluffy");
    console.log(fluffy);
    db.close();
});

// Print that db connection has been closed.
db.once('close', function () {
    console.log('close');
});

Notice that the code references an environment variable, process.env.MONGO_DB_URL. You’ll need to set that in your terminal. In Linux, you can do that by using the export command: export MONGO_DB_URL=mongodb://127.0.0.1:27017/myappdb.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to handle button clicks in React Native – Part II

Now that my Button responds to clicks (see previous post), I can program my React Native app to do something interesting in response to the click. Remember that my user is going to select a movie title from a dropdown list of movies, and then click a button to get a list of nearby movie theaters where the movie is showing.

There are REST APIs that will return the information we want. However, I’m not going to use them – at least not yet. Why not? Because I don’t want to go down a rabbit hole researching all the possible REST APIs. Even if it wouldn’t take very long, I don’t want to get sidetracked right now.

It’s important to note that if you’re building an app for business purposes, you should not lift one finger to code up your app until you’ve figured out what 3rd party services you need, and whether there is one available which will let you access it within your budget constraints. Suppose you’ve decided that you want to build an app which supplies turn-by-turn directions to every independent coffee shop across the world. This sounds kind of like a niche app, “Google Maps for coffee”. Well, just because the Google Maps app can do something like this, doesn’t mean that a REST service exists which will be available to you. Don’t make that kind of assumption! And even if the service does exist, it may not be affordable. Suppose it exists but there’s a charge for each API call… will your business model be profitable if you take into account the cost?

Since we’re not building a real app, but just messing around to become familiar with React Native, we don’t have to worry about the above business realities. Instead, I’m going to build a very simple REST API which returns a list of movie locations. By mocking the API, I can keep my flow of building the app working, and worry about third-party features later.

I can easily mock the API because I’ve got a domain name and a shared server. All I have to do is upload a PHP file with the following content:

<?php
$theaters = array();
$theaters[] = array( "name" => "Paris Theatre", "phone" => "(212)688-3800", "address1" => "4 West 58th Street", "city" => "New York", "state" => "NY", "zip" => "10019");
$theaters[] = array( "name" => "French Institute Alliance Francaise", "phone" => "(212)355-6160", "address1" => "55 East 59th Street", "city" => "New York", "state" => "NY", "zip" => "10022");
$theaters[] = array( "name" => "Roxy Cinema Tribeca", "phone" => "(212)519-6820", "address1" => "2 Avenue of the Americas", "city" => "New York", "state" => "NY", "zip" => "10013");

$out = json_encode($theaters);
echo $out;
?>

The list of movie theaters gives this static output:

[{"name":"Paris Theatre","phone":"(212)688-3800","address1":"4 West 58th Street","city":"New York","state":"NY","zip":"10019"},
{"name":"French Institute Alliance Francaise","phone":"(212)355-6160","address1":"55 East 59th Street","city":"New York","state":"NY","zip":"10022"},
{"name":"Roxy Cinema Tribeca","phone":"(212)519-6820","address1":"2 Avenue of the Americas","city":"New York","state":"NY","zip":"10013"}]

You can do that with a static HTML page if you want, it doesn’t matter. If you don’t have a server and don’t want to spend time setting one up, just reuse my URL.

I’m going to do a little copy/paste here. People rant against copying and pasting code, and there are reasons not to do it, but it’s actually pretty reasonable to do this in rapid application development of prototypes. The idea is “let’s just get this done, since the code might be thrown out tomorrow.” Yes, doing this will lead to technical debt. However, you may never have to pay off the debt, if the application is just an experiment. Further, you’re not at a stage where refactoring for reusability makes sense, yet. So I just copy the code that was used to fetch in componentDidMount, paste it, and make some small changes. Ditto for my setMovieState and handleMoviesResponse methods. Here’s what I wind up with:

...
setNearbyTheatersState(theaters) {
    this.setState({
        isLoading: false,
        nearbyTheaters: theaters,
    });
}
...
handleNearbyTheatersResponse(theaters, delay) {
    if (delay && delay > 0) {
        const timer = setTimeout(function () {
            this.setNearbyTheatersState(theaters);
        }.bind(this), delay);
    } else {
        this.setNearbyTheatersState(theaters);
    }
}
...
handleClick() {
    console.log("handleClick");
    return fetch('https://www.fullstackoasis.com/rnb/theaters.php')
        .then((response) => response.json())
        .then((responseJson) => {
            // TODO FIXME handle timeout / delay
            this.handleNearbyTheatersResponse(responseJson);
        })
        .catch((error) => {
            // TODO FIXME replace the red screen with something informative.
            console.error(error);
        });
}
...

This is pretty much a repeat of the REST call to get the list of movies, only now I’m calling my own mocked API, and setting a state parameter named “nearbyTheaters”. Looks good! But when I click the button, I see a RedBox which reads "TypeError: _this2.handleNearbyTheatersResponse is not a function. (In '_this2.handleNearbyTheatersResponse(responseJson)', '_this2.handleNearbyTheatersResponse' is undefined)".

You might think that copy/paste didn’t work so well for us… but I’d disagree. It got us to an error faster than if we wrote all the code from scratch. Now it’s just a matter of figuring out what’s gone wrong.

To help debug this problem, I add a comment just before the call to this.handleNearbyTheatersResponse:

handleClick() {
    console.log("handleClick");
    return fetch('https://www.fullstackoasis.com/rnb/theaters.php')
        .then((response) => response.json())
        .then((responseJson) => {
            // TODO FIXME handle timeout / delay
            console.log(this);
            this.handleNearbyTheatersResponse(responseJson);
        })
        .catch((error) => {
            // TODO FIXME replace the red screen with something informative.
            console.error(error);
        });
}

Then I click the button again. I see the following logged in my terminal:

{"accessibilityLabel": undefined, "accessibilityRole": "button", "accessibilityStates": [], "background": {"attribute": "selectableItemBackground", "type": "ThemeAttrAndroid"}, "children": <RCTView style={[[Object]]}><ForwardRef(Text) style={[Array]}>FIND MOVIE NEAR ME</ForwardRef(Text)></RCTView>, "disabled": undefined, "hasTVPreferredFocus": undefined, "nextFocusDown": undefined, "nextFocusForward": undefined, "nextFocusLeft": undefined, "nextFocusRight": undefined, "nextFocusUp": undefined, "onPress": [Function handleClick], "testID": undefined, "touchSoundDisabled": undefined}

At this point I was a little puzzled; it looked to me like this was a reference to my Button, and not my app. I expected the latter. Here’s the relevant part of the render method, again:

<Button onPress={this.handleClick} title="Find Movie Near Me"></Button>

In fact, JavaScript’s correct behavior is a little hazy to me. I could find discussions that made claims about the standard behavior, but no references to the specification, and I didn’t go hunting for the official answer. Let’s not waste time tracking this down right now. Let’s assume this refers to the Button being pressed. That may be useful in some cases, but in my case, I want this to reference the app itself so that I can call handleNearbyTheatersResponse within the handleClick method.

I took a stab at fixing the problem by binding the Button‘s onPress method to this:

<Button onPress={this.handleClick.bind(this)} title="Find Movie Near Me"></Button>

That worked! Once I do that, clicking the button does not produce an error. The call to setState in setNearbyTheatersState is made. I verified this by adding a new Picker which is populated with theater listings if this.state.nearbyTheaters exists.

Here’s the new code in my render method:

if (this.state && !this.state.isLoading) {
    let items = [];
    var length = this.state.dataSource.length;
    for (var i = 0; i < length; i++) {
        var item = this.state.dataSource[i];
        // Really, really important to not put quotes around these braces:
        items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
    }
    var theatersPicker = null;
    if (this.state.nearbyTheaters) {
        let theaters = this.state.nearbyTheaters.map(function (t, i) {
            return <Picker.Item label={t.name} value={t.name} key={i} />;
        });
        theatersPicker = <Picker>{theaters}</Picker>
    }
    return <View>
        <Picker selectedValue={this.state.movie}
            onValueChange={(itemValue, itemIndex) =>
                this.setState({ movie: itemValue })
            }>
            {items}
        </Picker>
        <Button onPress={this.handleClick.bind(this)} title="Find Movie Near Me"></Button>
        {theatersPicker}
    </View>;
    ...

The source code for this experiment is available online.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to handle Button clicks in React Native – Part I

I’ve been building an app which lets me find movies “near me” using mocked data. In my last post, I added a progress loader to display when there’s networking latency. I have a dropdown with a list of movie names in my app, and the user can select any movie in the list. Let’s suppose the user wants to see one of these movies, and would like to see a list of closest locations where the movie is showing. We’re going to need a button so that the user can click it to get results.

You might wonder why you shouldn’t just load results when the user selects a movie name from the Picker. Well, it depends on how you feel about UX. Some apps will immediately give you results when an element is selected from a dropdown. However, just because a user selects an item doesn’t mean that is their final choice. Maybe they lifted their finger too soon, and wound up selecting something that they didn’t want. Or, maybe they’re just thinking about their different options.

My personal preference for dealing with a select is to add a confirmation button when the result of selecting an item from the Picker is a resource intensive task, like hitting a database or making a network call. You don’t want to waste resources every time a user selects an item from a dropdown.

So in this example, making a network call should only happen if the user clicks a button. Let’s add a button to our view – just below the Picker:

import { View, Picker, ActivityIndicator, Button } from 'react-native';
...
render() {
    ...
    return <View>
        <Picker...
        </Picker>
        <Button title="Find Movie Near Me"></Button>
    </View>;
    ...
}

You can’t add a Button without a title; you’ll see a warning if you do.

The button is probably the easiest control to add in React Native! Here’s what I see after I add just a couple of lines:

However, clicking the button is a different story. If you’re used to web development, you might expect an “onClick” property. Nope, it’s onPress. And you can’t just add a method like this:

...
handleClick() {
    console.log("Handled");
}
...
    <Button onPress="handleClick" title="Find Movie Near Me"></Button>
...

The app won’t complain if you do this, but if you click the button you’ll see an error: "TypeError: this.props.onPress is not a function. (In 'this.props.onPress(e);, 'this.props.onPress' is "handleClick")".

The method handleClick is actually a function of “this”, the app. So you have to reference it correctly. It doesn’t help to replace onPress="handleClick" with onPress="this.handleClick" because anything in quotes is a “literal”, treated as a string, in JSX. Instead, you have to do as follows:

...
handleClick() {
    console.log("handleClick");
}
...
    <Button onPress={this.handleClick} title="Find Movie Near Me"></Button>
...

Now the button responds to clicks, as you can see below!

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to write SQL queries using MySQLi in PHP

MySQLi is the “MySQL Improved Extension” for PHP. You might have seen simple examples of it being used like this:

$sql = "SELECT * FROM persons";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons in the database\n";

This particular example works. In my case, the output is “There are: 2 persons in the database”. Many queries are not so simple, however. Suppose you wanted info about a particular person named “Smith”. The following code will work (assuming $name has been set in the code somewhere above):

$name = "Smith";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";

The output is “There are: 1 persons named Smith”.

Because it works, it may lull you into a false sense of security; you might think that’s all there is to it. And it may work for quite a while before you run into a problem. The problem is that some names contain special characters that will break the code above. One example is the name O’Hara. This is what happens when “Smith” is replaced by “O’Hara” in the above code:

$name = "O'Hara";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";

When I run this code, I see an error:

PHP Fatal error:  Uncaught TypeError: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/fullstackdev/tests/single-select-sql-apostrophe.php:29
Stack trace:...

This error might be confusing because the error is thrown from the line with mysqli_num_rows. That’s because the call to mysqli_query returned false, a sign that there was an error. Let me call mysqli_error before trying to use the $result, and print out the error, if there was one:

$name = "O'Hara";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
$error = mysqli_error($conn);
if ($error) {
        echo "$error\n";
} else {
        echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";
}

Now, the output looks like:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Hara'' at line 1

This error is more helpful than the previous one, but if you’re new to SQL, it might still be confusing. The problem is that there’s an apostrophe in the name O’Hara, but the apostrophe is a special character with special meaning in SQL. It is used to signify the beginning or ending of a string. If I print out my SQL statement from the above code, it looks like this:

SELECT * FROM persons WHERE lastname = 'O'Hara'

That’s three apostrophes. There’s an unmatched apostrophe, and that means MySQL was expecting more characters; it doesn’t know what to do with this statement.

The way to handle this type of query is to “escape” the apostrophe in the SQL by putting a backslash character in front of it, like this:

SELECT * FROM persons WHERE lastname = 'O\'Hara'

That backslash notifies MySQL to treat the next character as part of the string, not as a special character delimiting a string.

Of course you don’t want to have to write special code to replace all instances of apostrophe in your string with backslash followed by apostrophe. There’s already a special PHP method which will do this for you. It’s called mysqli_real_escape_string.

Let’s use this in our code above:

$name = "O'Hara";
...
$esc_name = mysqli_real_escape_string($conn, $name);
$sql = "SELECT * FROM persons WHERE lastname = '$esc_name'";
echo "$sql\n";
$result = mysqli_query($conn, $sql);
$error = mysqli_error($conn);
if ($error) {
        echo "$error\n";
} else {
        echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";
}

The output looks like this:

SELECT * FROM persons WHERE lastname = 'O\'Hara'
There are: 1 persons named O'Hara

As you can see, the SQL which I printed out has a properly “escaped” apostrophe in it. The function mysqli_real_escape_string should always be used to escape strings in cases like this.

Once you get to this point, you might think everything is hunky-dory and start writing all your code this way. However, it’s generally considered a really bad idea to write code like this, because it’s not safe against a SQL injection attack. To prevent this type of black-hat hacking on your website and database, you should always use prepared statements. It’s slightly more labor intensive, but it’s safe:

$sql = "SELECT * FROM persons WHERE lastname = ?";
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_bind_result($stmt, $id, $firstname, $lastname);
mysqli_stmt_execute($stmt);
$row = mysqli_stmt_fetch($stmt);
echo "Person $firstname $lastname was found\n";

The output here is Person Karen O'Hara was found.

As a final note, while MySQLi is fine to work with, IMHO, but you’ll also want to become familiar with PDO because it’s also quite popular (and different).

PS if you want to play around with the sample code above, you’ll need a MySQL database installed. Here are my dead simple database commands:

CREATE DATABASE testing;
USE testing;
CREATE TABLE persons (
    id INT AUTO_INCREMENT PRIMARY KEY,
    firstname varchar(128),
    lastname varchar(128)
);
INSERT INTO persons (firstname, lastname) VALUES ("John", "Smith");
INSERT INTO persons (firstname, lastname) VALUES ("Karen", "O'Hara");

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to create a scrollable list of items on an html page

If you have a long list of items, they can be displayed very easily using an HTML list.

Some people don’t like the way that looks, though, and they’d rather print out the list in one div after another, like this:

<div>Dashing through the snow</div>
<div>In a one-horse open sleigh</div>
<div>O'er the fields we go</div>
<div>Laughing all the way.</div>

That’s all great, but suppose your list is very long? Maybe most of your users don’t really care about the entire list, and will be satisfied to see just a few lines of it. You don’t want your users to have to scroll pages down to get past all the list items and see more content below it. It’s kind of a tricky problem, but one easy way to solve it is to follow a few simple steps:

(1) List all of your items in individual divs.
(2) Put all items into a containing div, and limit the height of that div to a fixed size.
(3) Then, style the containing div to set overflow: scroll.

The result is that your content is displayed inside a scrollable div. Click that link to see a demo page of how it works; you can take a look at the source code by right-clicking and choosing the view page source menu item. Here’s a screenshot of what it looks like:

If you found this interesting, click the subscribe button below! I write a new post about once a week.

PHP in_array or array_search vs JavaScript includes or indexOf

In my previous post, I’d created a bug in my PHP code by improper use of PHP’s array_search function. If you only write PHP, this kind of thing will probably never happen to you. I also write Java and JavaScript code, and at some point, your memory banks overflow, and you forget stuff!

JavaScript has a couple of different methods for searching through an array to find an item. Let’s use the array method includes to search for an item in JavaScript, just like I did in my PHP example.

var foods = new Array();
foods.push('ice cream');
foods.push('hamburger');
foods.push('brussels sprouts');

var do_important_things = function() { console.log('Important!'); };

if (foods.includes('ice cream')) {
    do_important_things();
}
...

If you print out foods, you can verify that ‘ice cream’ is located at index 0. The code foods.includes('ice cream') returns true because that string is found in the array. No confusion there – a boolean is returned, not an index.

If I’m doing a more complicated comparison, I might use JavaScript’s some, like this:

if (foods.some(function(el) { return el.toLowerCase() === 'ice cream'; })) {
    do_important_things();
}

The some method loops over all elements in the array until the callback method returns true, at which point it stops, and returns true. If no item is found which satisfies the condition in the callback, then false is returned. Again, since a boolean is returned and not an index, there’s no room for error.

There’s a JavaScript method which is the equivalent of the PHP array_search function: indexOf. It returns the index of the matching item, if found, and otherwise returns -1. Here’s an example:

if (foods.indexOf('ice cream')) {
    do_important_things();
}

Oops, this method of searching exhibits the same bug as array_search in PHP! In my opinion, the indexOf JavaScript method is more appropriately named – it makes it clear that you are going to get an index as a return value. So it makes it less likely that the all-too-human developer will create the bug that I demonstrated in my previous post.

Now, when researching this topic, I found that PHP has a function that is more appropriate than array_search for my use case. It’s the in_array function. It returns TRUE if the item being sought is found in the input array. That’s really what I wanted! Here’s the example code that I used in my previous post, only now it uses in_array:

$foods = Array();
$foods[] = 'ice cream';
$foods[] = 'hamburger';
$foods[] = 'brussels sprouts';

function do_important_things() {
    echo 'Important!';
};

if (in_array('ice cream', $foods)) {
    do_important_things();
}

In this example, do_important_things is called.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

The Coding Blacklist. No 52: PHP array_search

PHP has a few “gotchas” which have bitten me in the past. I just got bitten again, today!

I used this PHP code:

$foods = Array();
$foods[] = 'ice cream';
$foods[] = 'hamburger';
$foods[] = 'brussels sprouts';

function do_important_things() {
	echo 'Important!';
};

if (array_search('ice cream', $foods)) {
	do_important_things();
}

I banged my head against the wall for a few minutes when the do_important_things function never got called. I printed out the $foods array and could see that 'ice cream' was in it. So, array_search should return true, right?

So what was going on? Go figure it out for yourself if you want…. or scroll down to get the quick answer.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

PHP’s array_search returns the key of the first value that was matched in the array. Since 'ice cream' had key zero (first item in the array), 0 was returned. In PHP, 0 evaluates to FALSE when it is used in a boolean sense. Like here. They kind of warn you about that in the array_search documentation, but who looks up the docs every time they use an array function?

I kind of went ‘Doh!’ when this happened, because I’ve had this experience once before. I’d just forgotten it. This is a case where an editor plugin might help, but I don’t know of any good solution, except to be careful when using PHP array functions.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Quirks of HTML forms – can you GET and POST at the same time?

TL;DR: You can effectively GET and POST information using a single form. The trick is to set a query string in your action – the form is still POSTed, but the server will see the query string as GET data. Also, if a user comes to your web page with a query string already set, that query string will be retained when POSTing a form, as long as you use the empty action (action="") for your form.


HTML forms are a rudimentary part of web deveopment, but you can be productive implementing them without a lot of specialized knowledge. That’s a plus and a minus, since there are some “gotchas”. Here is a quick review of some things that might have escaped your notice.

an empty action attribute?

You can add a form to a page simply by enclosing some content with the <form> tag. This tag does not require any attributes. Here’s an example:

<form>
  <div><label>topping: <input></label></div>
</form>

In this example, nether the method nor the action attribute are specified. What happens in this case? Can this form be submitted? Here’s a sample page which has only this form on it so you can experiment with it. (The quick answer is yes, the form submits in Chrome, but no actual data is submitted, so the form is not useful.)

In this next example, the form also has no attributes. However, the input is named – it has a name attribute, like this:

<input name="topping" value="pepperoni">

Take a look to see if this example with a named input works to send request data to the server. (It does! You will have to type something into the form and hit enter for it to work.)

Here’s a page which submits two variables, “topping” and “crust”, using a blank form (<form>), again. Does it work? Try it! (The quick answer is “no!” – even though both inputs are named.) I only tested this in Chrome, and I don’t think the spec is clear about how to deal with this case. It does show you that it’s important to be very clear about the contents of your forms. In this case, adding a submit button fixes the problem. Here’s a demo which fixes the problem by adding the submit button.

be specific

Given the quirkiness of those forms above, usually you will want to specify the form’s method and action attributes, and also name all the inputs, like this:

<form action="topping.php" method="POST">
  <div><label>topping: <input name="topping"></label></div>
</form>

Notes about the action:

  • The action should be a valid URI; the spec doesn’t say what will happen if your URI is not valid.
  • URIs can be relative, like ../pizza.cgi or customer.php.
  • Important: the URI can include a query string, like ../pizza.cgi?topping=pepperoni.
  • If the form’s action is the empty string, then the action defaults to the URL of the document that contains the form – the URL of the page that you’re currently looking at. I couldn’t find anything in the spec that says what happens if the form does not even specify the action. I think most browsers treat this as the empty string.

Here’s a page which contains several different forms, with different actions set. You can play around with that demo to see how the different types of action attributes work.

what about that query string?

If a user comes to a web page that has a query string, and your form’s action is empty, then when you submit the form, the URL for the resulting page will contain the original query string (the address bar will show the URL with the query string). Here’s an example – this link has a query string, and the form on the page has an empty action. Notice that when you submit the form, the server sees both GET data and POST data. Try it!

So this is a quirk when using a form with an empty action attribute. It will retain the query string with which the user came to the page – this can be useful when sharing links. Some users will copy the URL in the address bar for sharing, and if that query string is important for what displays on the page, you want it to remain even after a form submission.

It’s also useful for reloading a page. If a user submits a form using a POST, and then tries to reload the page, they’ll get a question asking them if they want to re-POST the data. If the user doesn’t want to re-POST, but does want to reload the page, then they can copy the URL – including its query string – and paste it into the browser’s address bar, and hit enter to avoid the re-POST.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

What’s a PWA?

What’s a progressive web app (PWA)?

A progressive web app is a special type of web application (a software application that you use in a web browser). It maintains some functionality even when you’re offline. It can also be installed, like an app, on your cell phone.

Why take the trouble to develop a technology that makes it possible to use a web app offline, and make it act like an installed app on your cell phone? This may not seem useful, at first glance. Many web applications, like gmail, started out at home in a web browser, being used on a desktop computer. On desktops, you’re usually working online, so why take the extra effort to deal with the rare Internet outage at home?

Well, more and more people are using web apps on mobile devices. Even if you live in a heavily populated area, you may find that once in a while you get no Internet service on your cell phone. For most applications, that puts a hard stop to many of the uses for your phone. It’s frustrating for users. In some cases, a web app doesn’t really need a constant Internet connection to be useful. For example, you may want to visit your email client in a web browser to write an email even if you’re offline. You can queue up the draft to be emailed later, when you enter an area where data service is available.

This is where Progressive Web Apps (PWAs) enter the picture. If you run a web application that could be useful to people even when it’s offline, it can make sense to turn your app into a PWA.

Why Not Build a Native App?

If you’ve already built a web application, you could also build a native app for your users (an Android app, for example). From the provider’s viewpoint, this can be a big project – building a native app requires an entirely different set of development skills from web development, and it’s an additional cost. Aside from that, there’s a hurdle for users to install a native app, even if you’ve taken the trouble to build one. They have to go to the Google Play store, search for the app, wait for it to download, and then they might find that it’s not used very often or it’s just taking up space on their phone, so they wind up uninstalling it.

What if it were possible to download a “light” version of an app directly from the web app’s website? That’s what you can do if you build a PWA.

Properties of a PWA

According to Google’s Developers site, my PWA must fulfill some requirements:

  1. It must run in a web browser and as an app in mobile devices.
  2. It must be “fast and reliable” (even native apps aren’t always fast and reliable, so this requirement is a bit funny!). This just means it loads really fast, and does something useful even if you aren’t connected to the Internet. No “ERR_INTERNET_DISCONNECTED” errors like you’d get when your browser is offline, please.
  3. It must be installable. When installed, it appears in Android’s “Apps drawer” (where all apps are listed), and you can add a shortcut to it on your home screen (or desktop on a PC). When running on a mobile device, it’s a top-level app in the task switcher.

What you want, more than anything, is just to make sure that the web app does something useful when the user is offline. Instead of seeing a blank page with an error message, you get some functionality. You also want it to be easily accessible (hence installable) for people who will want to use it frequently.

How to Build a PWA

I’ve written a page which explains how to build a PWA, step by step. Take a look there if you’d like to follow the tutorial.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

how to port your LAMP PHP 5.x web app to AWS in an afternoon

In the past, I’ve thought about moving a web app that I run to Amazon AWS, so that it runs in the “cloud”. I haven’t been very tempted, though. I think it will cost more than what I’m paying to my current, managed web hosting service. I also think it will be more of a pain to deal with AWS. My hosting services manages pretty much everything: email, SSL certificates, domain name registration, etc. The cost is only about $100/year.

Despite these misgivings, I decided to try migrating my application, just to see how much work it would be. I also thought it would be a fun experiment, and that I’d get a feel for running a service in the cloud.

The post is rather lengthy, so I set up an entirely separate web page about how I did it. If you are interested in AWS, and maybe were thinking of doing something similar, read about how I migrated my web app here.

Although I did get my web app to run successfully on AWS, I don’t think I’ll move it there. I’m very happy with my current web hosting service.

If you found this interesting, click the subscribe button below! I write a new post about once a week.