Monthly Archives: March 2020

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.

MySQL Cannot delete or update a parent row: a foreign key constraint fails

TL;DR: If you can’t quickly see why your DROP TABLE statement is failing, check for typos in your table names.

In MySQL, foreign key constraints can stop you from dropping a table. But that’s not the only thing that can go wrong.

Let’s create a simple example using MySQL, in order to demo the problem. As the root user, sign in to MySQL using your favorite client. I like to use the command line mysql client, like this: mysql -u root -p.

Next, create a new test database, CREATE DATABASE hamsters;

Then:

USE hamsters;
create table toys (
   toy_id INT NOT NULL AUTO_INCREMENT,
   name VARCHAR(50) NOT NULL,
   PRIMARY KEY ( toy_id )
);
create table toy_makers (
   toy_maker_id INT NOT NULL AUTO_INCREMENT,
   toy_id INT,
   name VARCHAR(25),
   FOREIGN KEY ( toy_id ) REFERENCES toys ( toy_id ),
   PRIMARY KEY ( toy_maker_id )
);

After doing this, verify the tables exist.

mysql> show tables;
+--------------------+
| Tables_in_hamsters |
+--------------------+
| toy_makers         |
| toys               |
+--------------------+
2 rows in set (0.00 sec)

When experimenting with MySQL, you’ll often want to be running CREATE and DROP scripts. Here is my DROP script:

USE hamsters;
DROP TABLE IF EXISTS toys;
DROP TABLE IF EXISTS toy_makes;

Let’s look at the output:

mysql> USE hamsters;
Database changed
mysql> DROP TABLE IF EXISTS toys;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
mysql> DROP TABLE IF EXISTS toy_makes;
Query OK, 0 rows affected, 1 warning (0.00 sec)

Well, that’s a bit frustrating, but it’s actually a pretty simple problem. The primary key toy_id in table toys is referenced as a foreign key in table toy_makers. You cannot drop toys first, even though there’s no data in either table! You’ll have to drop any tables that reference toys.toy_id as a foreign key prior to dropping toys. In my case, the solution is simple. Just do a switcheroo on our DROP statements, and DROP the toys table last:

USE hamsters;
DROP TABLE IF EXISTS toy_makes;
DROP TABLE IF EXISTS toys;

Here’s the output:

mysql> USE hamsters;
Database changed
mysql> DROP TABLE IF EXISTS toy_makes;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> DROP TABLE IF EXISTS toys;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails

If you’re looking at this, you might be confused. I switched the order in which the tables were dropped, but, hm, I’m still getting the same complaint! Let’s look at our database by using the SHOW TABLES command:

mysql> SHOW TABLES;
+--------------------+
| Tables_in_hamsters |
+--------------------+
| toy_makers         |
| toys               |
+--------------------+
2 rows in set (0.00 sec)

At this point, I hope you’ve noticed the problem! There was a typo in my DROP TABLE script. The command DROP TABLE IF EXISTS toy_makes; ran without an error because it has the option IF EXISTS in it. There’s no table called toy_makes here – the table is called toy_makers.

What if we just run DROP TABLE toy_makes? That does produce an error: ERROR 1051 (42S02): Unknown table 'hamsters.toy_makes'.

Let’s fix my script:

USE hamsters;
DROP TABLE IF EXISTS toy_makers;
DROP TABLE IF EXISTS toys;

Both lines run successfully now, with output like Query OK, 0 rows affected (0.97 sec).

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

Adding a map to React Native

This is part of a series on building a movie locator app in React Native. The first post is available here.

In my last post, I’d given the user the ability to navigate to a new page in the app. In this post, I’ll add a map on that new page. It will display the location of the theater that the user picked.

This is the first part of my app build which requires that you do something different depending on whether you’re working with Android or iOS. The installation instructions are here (as of 2020/03/23). I will be following the build configuration on Android, because I’m using an Android emulator (and a Linux OS, not a Mac, for my builds).

There are 6 steps given in the “build config for Android” section. I went through each of them one by one. I created a separate page which describes exactly what I did to prepare to add a map to my React Native app. Take a look there if you want to know about it in more detail.

In my previous post, I listed the code in MapsScreen.js, which is the page where my map should be displayed:

import React, { Component } from 'react';
import { Text, View } from 'react-native';

export default class MapsScreen extends Component {
    render() {
        return (<View style={[{ flex: 1, justifyContent: 'center' },
        { flexDirection: 'row', justifyContent: 'space-around', padding: 10 }]}>
            <Text>A map goes here</Text>
        </View>);
    }
}

But there’s no map there, yet! I need to add the code that will display a map.

Fortunately, the React Native maps project has an example app on GitHub. I took the time to download this example project, and create an entirely separate React Native project which uses its code. This helped me get my feet wet, and I knew where to look for the code that I needed to add a map: StaticMap.js is a page which displays a simple map. I’m going to take some of that code and add it to my own, as follows:

import React, { Component } from 'react';
import { View, Text } from 'react-native';
import MapView from 'react-native-maps';

export default class MapsScreen extends Component {
    render() {
        return (<View style={[{ flex: 1, justifyContent: 'center' },
        { flexDirection: 'row', justifyContent: 'space-around', padding: 10 }]}>
            <MapView
                initialRegion={{
                    latitude: 37.78825,
                    longitude: -122.4324,
                    latitudeDelta: 0.0922,
                    longitudeDelta: 0.0421,
                }}
            />
        </View>);
    }
}

This is almost the same as my previous render method. The only difference is that I’ve added a MapView component. It includes a mocked initialRegion property (latitude and longitude are static). I just want to get maps working, before adding a real initialRegion.

Unfortunately, when I tested this, I just saw an empty display, aside from the Maps title bar. Ugh! No error messages – just nothing! It was frustrating! Since there were no error messages, I wondered if there was something wrong with the display. The StaticMap example uses a MapView that is styled. So I copied that style, which just specified a width and height, and pasted it into my MapView, like this:

<MapView
    style={{width: 250, height: 250}}
    initialRegion={{
        ...

It worked!! I saw a map, but it looked cramped. I changed the style to {{flex:1}}, and the map filled the page! Excellent! Here’s the current behavior:

map of San Francisco in React Native app

The source code for this example – App.js, MoviesScreen.js, and MapsScreen.js – is available online.

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

Adding a simple navigation system to React Native – Part II

In my last post, I started the process of adding a navigation system to my app. The idea is to make it easy for the developer to add more pages to the app, and easy for the user to move around from page to page. I’m using the React Navigation community project. I’ve got the right packages installed and imported into my app. It’s clear to me from the documentation that I need to add a new component as a new page.

So I add a rudimentary, blank component. I’ve decided that this page will show a map of the theater that the user picks on the first page, so I name the file MapsScreen.js, with this source:

import React, { Component } from 'react';
import { Text, View } from 'react-native';

export default class MapsScreen extends Component {
    render() {
        return (<View style={[{ flex: 1, justifyContent: 'center' },
        { flexDirection: 'row', justifyContent: 'space-around', padding: 10 }]}>
            <Text>A map goes here</Text>
        </View>);
    }
}

Then I edit App.js to include a route to this component. It looks like this:

import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import MoviesScreen from './MoviesScreen';
import MapsScreen from './MapsScreen';

const MainNavigator = createStackNavigator({
    Movies: { screen: MoviesScreen },
    Maps: { screen: MapsScreen }
});

const App = createAppContainer(MainNavigator);

export default App;

It was more trouble than I’d like to add the React Navigation packages, but now that they’re in place, it’s super easy to add a new page. According to the documentation, I just need to call a function called navigate in order for a button click to take me to a new page.

I’ve already attached a method handleShowTheaterClick to my “GO” button. Here’s the short navigation code that needs to be added:

handleShowTheaterClick() {
    const { navigate } = this.props.navigation;
    navigate('Maps', {});
}

This is all it takes to make the “GO” button functional. I click the button, and I’m taken to my “Maps” screen, which looks like this:

current app functionality selecting movie and theater

Notice there’s a back arrow in the title bar. I can click that to get back to the previous screen. I hardly needed to do any work at all to get built-in navigation functionality. This is the beauty of code reuse.

The source code for this example – App.js, MoviesScreen.js, and MapsScreen.js – is available online.

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

Adding a simple navigation system to React Native – Part I

In previous posts (start here), I’ve written about building a movie app that a person can use to pick a movie from a list, and then click a button to display theaters where the movie is being shown.

Let’s add some code which allows our user to select a specific theater. Upon doing that, a button will appear which will take them to a new page in the app.

I only want the new button to appear when the list of theaters is populated. Here’s how I ensure that:

render() {
    if (this.state && !this.state.isLoading) {
        ...
        var theatersPicker = null;
        var goButton = null;
        if (this.state.nearbyTheaters) {
            ...
            theatersPicker = <Picker>{theaters}</Picker>
            goButton = <Button onPress={this.handleShowTheaterClick.bind(this)} title="Go"></Button>;
        }
        return <View>
        ...
            <Button onPress={this.handleClick.bind(this)} title="Find Movie Near Me"></Button>
            {theatersPicker}
            {goButton}
        </View>;

The goButton has been initialized to null. It will only be set to a Button if the theatersPicker has a list of theaters. I also added a new, empty method called handleShowTheaterClick (not shown here). The new button will call handleShowTheaterClick when clicked, but since it’s empty, it won’t do anything yet. We’ll get to that later.

You’ll find that the {goButton}line doesn’t show anything if goButton is null. That’s the UX that we want.

At this point, I want handleShowTheaterClick to cause the app to display a new page. This behavior is new! So far, everything has been happening in a single page. We’re getting into navigation, also known as “routing”. It’s how users get around the app from one page to another.

Navigation is not built into the default React Native install. You have to install it as a separate package. I followed the instructions for doing this as given in the documentation, but I got a lot of warnings. It took me about 30 minutes to resolve them, ugh! I kept trying and retrying… One of the errors that I saw in the Metro server terminal window looked like this:

error: bundling failed: Error: Unable to resolve module `react-navigation-stack` from `App.js`: react-navigation-stack could not be found within the project.

If you are sure the module exists, try these steps:
 1. Clear watchman watches: watchman watch-del-all
 2. Delete node_modules: rm -rf node_modules and run yarn install
 3. Reset Metro's cache: yarn start --reset-cache
 4. Remove the cache: rm -rf /tmp/metro-*

This turned out to be misleading. I thought that I need to use yarn, so I installed it, and started using it according the instructions. It could be that this works for some setups, but I’m running Ubuntu 16.04, and I’ve been using npm throughout this exercise. I should have stuck with npm. I learned that if a message mentioned yarn, I should just use npm instead. I suggest you do the same, unless you’re already using yarn to run other commands.

When I finally switched back to using npm, I found there were some warnings about “peer dependencies”. Here is one example:

...
npm WARN @typescript-eslint/eslint-plugin@1.13.0 requires a peer of eslint@^5.0.0 but none is installed. You must install peer dependencies yourself.

I wound up installing each peer dependency when I saw that one was missing. Then I had to go back and install the package which required the dependency again (so it seemed). In the end, I did all these installs in my project root (where App.js lives), in the order given:

npm install eslint@^5.0.0
npm install typescript@>=3.7.0-dev
npm install react-native-gesture-handler@*
npm install @react-native-community/masked-view@^0.1.1
npm install react-native-safe-area-context@^0.6.0
npm install react-navigation-stack
npm install react-navigation

Installing all that stuff was kind of a headache, and I was happy when it was finally done.

A quick read of the navigation documentation told me that I should only have navigation code in my App.js file. My existing application logic should go into a separate “screen” page. I’ll call this new page MoviesScreen.

To do this, I copied all the source of App.js into a new file, which I named MoviesScreen.js. Then I replaced HelloWorldApp in that source with MoviesScreen. Really, just replace

export default class HelloWorldApp extends Component {

with

export default class MoviesScreen extends Component {

Next, I replaced all the code in App.js with this simple navigation code:

import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import MoviesScreen from './MoviesScreen';

const MainNavigator = createStackNavigator({
    Movies: { screen: MoviesScreen }
});

const App = createAppContainer(MainNavigator);

export default App;

After doing this, I ran npx react-native run-android in my project root. I’ve learned that running npx react-native run-android sometimes clears up errors, although I’m not exactly sure when or if it’s required (might be a superstition type thing!).

The net result was that my app looked almost exactly the same as it did before! That’s expected, and good, because I only made infrastructure changes, and no functional ones. The only difference now is that there’s a title bar at the top of the display. It reads “Movies”. It’s not beautiful, but I’ll figure out how to deal with that later.

In testing the latest version of my app, I notice there’s one problem: when I select a theater from my “theaters” Picker, the value doesn’t stay selected. I know how to fix that – the same way that I did it for the “movies” Picker. I add similar code for that in MoviesScreen‘s render method:

...
theatersPicker = <Picker selectedValue={this.state.theater}
    onValueChange={(itemValue, itemIndex) => this.setState({ theater: itemValue })
    }>{theaters}</Picker>
current app functionality selecting movie and theater

Now, my app just works, except for one little problem. The GO button does nothing! Clicking on it should take the user to a new page. I’ll work that out in my next post.

The source code for this new version of App.js and for MoviesScreen are 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 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.