Set up an Amazon Book Store on Google App Engine – 1

23 Feb

Who said good things don’t come for free? They do! Amazon Product Advertising API and Google App Engine are 2 such powerful things that all web developers should know! Google App Engine lets you host your websites/apps for FREE, completely running on Google’s resources, whereas Amazon Product Advertising API allows you to showcase Amazon’s product data on your website for free, and you get a commission of 5% – 15% per purchase made via your site.

We’ll learn to integrate these 2 services in a single app by setting up an Amazon book store on Google app engine.

Divide the app in 3 parts:
1) Set up the basic structure of our app. Make sure all the request handlers are in place and working.

2) The Amazon part of our app: We learn to construct and sign the request url for getting the book data from Amazon.

3) The templating part. We’ll display the books data in a tabular format on our site.

Prerequisites:
1) Amazon Associates Account: Sign up ‘FREE’ over here: Amazon Associates. You’ll get all the credentials required to access Amazon product data: Access keys, Associate tag etc.

2) Python 2.5 and Google App Engine: Download the GAE sdk for Python from Google App Engine downloads page. It works only with Python 2.5. Download Python 2.5. Install GAE and complete the ‘Hello World’ and ‘Guestbook’ tutorials from the docs for Google App Engine. Those are the best tutorials on getting started with GAE. And most important, this tutorial will assume that you have completed those 2 tutorials, and hence know the folder structure and basic files needed.

3) Python programming skills: Yes, you need to know atleast the basics of Python programming. Loops, conditional statements, lists, dictionaries etc. would do.

4) XML: As we will be dealing with XML data, you should know how an XML doc is and it would be very nice if you know how to parse it in Python ( don’t worry if you don’t know to, we will solve that problem later !)

Demo: Click to see my store in action!
Download: blogapp.rar


Let’s get started then…

Make a new project. Just like the ‘Guestbook’ application, make a new folder for our app in a directory of your choice, you can name it whatever you want, I named it blogapp. Add the following files to it:
i) app.yaml: The configuration file.
ii) amazon.py: The main file. This file will handle everything, building and signing the requests, parsing the XML that contains the product data and routing the data to the templates for rendering our website’s pages.

These are just the initial files, we’ll add more files/folders as we require along the way.

Code for the app.yaml file:

application: blogapp
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: amazon.py

‘app.yaml’ is the main configuration file that tells which urls will be handled by which files. In our ‘app.yaml’ file we’re specifying that all the urls will be handled by the ‘amazon.py’ file. The top 4 lines are some info about our app.

i) application: This is the identifier for our app. It’s ‘blogapp’. Locally you can use whatever you want, but after registering the app, you’ll have to replace this with whatever identifier you registered the app with. Name it wisely, the identifier should be unique. When the app is live, its address will be www..appspot.com

ii) version: Our app’s version.

iii) runtime: As we’re using ‘Python’ for making our app, the runtime used is ‘Python’.

iv) api_version: The GAE API version. It’s 1 currently.

The next 3 lines ‘-url:/.*’ mean that all urls, will be handled by the ‘script: amazon.py’.

Now open the ‘amazon.py’ file and add the following code to it:

import cgi, os
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template

class Init(webapp.RequestHandler):
    def get(self):
        path = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, {}))

application = webapp.WSGIApplication(
                                     [('/', Init)],
                                     debug = True)

# Main function runs the app
def main():
    run_wsgi_app(application)

if __name__=="__main__":
    main()

We’re importing all the modules we need for our app, at the top. The class ‘Init’ does nothing but load our homepage, i. e. ‘index.html’. We’re not passing any values to the template, and hence an empty dictionary is passed to the ‘template.render’ function. Next we define a request handler named ‘application’ and tell it that when the root url (‘/’) is accessed, instantiate the ‘Init’ class. Instantiating the ‘Init’ class will call the ‘get’ function automatically. The ‘get’ function then renders our homepage. So when the root url is accessed, our homepage ‘index.html’ will be displayed. The ‘main’ function is called automatically and it runs the app using ‘run_wsgi_app(application)’.

Create a new file ‘index.html’ in our app’s folder. Add the following code to it:

<html>
<head>
 <title>Amazing Amazon Store</title>
 <link type='text/css' rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
 <div id='wrapper'>
 	 <div id='head'>
	   <p>You bought it here!</p>
	   <span>Buy anything you want from Amazon. Best quality, best price!</span>
	 </div>
	 <div id='nav'>
	   <ul>
	     <li><a href ='/'>Home</a></li>
 	     <li><a href ='http://www.blog.rutwick.com'>Learn to make it!</a></li>
	  </ul>
   </div>
   <div id='content'>
	  <div id='form'>
	   <p>Which books do you want?</p>
	   <form method='post' action='/fetch'>
	    <input type='text' name='keyword' id='keyword'></input>
	    <input type='submit' value='Show' />
	  </form>
	 </div>
   </div>
  <div id='footer'>
	<p>2011. All rights reserved.</p>
	</div>
 </div>
</body>
</html>

This is our homepage, ‘index.html’. It’s plain html/css. Notice the line where we’re adding the stylesheet for the website, ‘ ‘. It will not load the stylesheet directly, unless we make a little change to the config file, ‘app.yaml’.

Add the following code to app.yaml, just below the line ‘handlers:’:

application: blogapp
version: 1
runtime: python
api_version: 1

handlers:
- url: /stylesheets
  static_dir: stylesheets
  
- url: /.*
  script:  amazon.py

We won’t need to edit the app.yaml file anymore, so the final version of app.yaml should look like this.

The line ‘-url: /stylesheets’ tells that when ‘stylesheets’ is referenced, the static directory ‘stylesheets’ should be loaded. As the app.yaml file is read from top to bottom, it will load the ‘stylesheets’ directory right when the application loads. Our css stylesheet lies in that folder. We use the same method to load any static files that our app/website requires. Be it images, javascripts etc.

Create a new folder ‘stylesheets’ and create a ‘style.css’ file in it. Put the following styles in this file:

body{ font-family:sans-serif; }
td{ border-bottom:1px solid #ff9900; padding:10px;}

#wrapper{ 
	margin:0 auto; 
	padding:10px; 
	width:880px; 
	background-color:beige; 
	}

#head{  
	background-color: #FF9900;
	padding: 10px 40px;
	}
	
#head p{  
	font-family:serif;
	color: #FFFFFF;
	font-size: 40px;
	font-style: italic;
	font-weight: bold;
	margin: 0; 
	}

#head span{  
	color: #D23F56;
	font-size: 18px;
	}

#nav ul{
	margin:0;
	background-color:#D23F56;
}

#nav ul li{
	list-style-type:none;
	padding :2px 0;
	display:inline;
}

#nav ul li a{
	text-decoration:none;
	color:#fff;
	font-size:14px;
}

#content { 
	background-color: #FFCC66;
	min-height: 150px;
	padding: 10px;
	}

#form { 
	background-color: #FFFFFF;
	border: 2px solid #FF9900;
	margin-left: 240px;
	margin-top: 30px;
	padding: 0 40px;
	width: 236px;
	}

#form p{ 
	color: #444444;
	font-size: 20px;
	margin: 5px 0 10px;
	}

#footer{
	height:50px;
	background-color:#ff9900;
}

#footer p{
	margin: 0;
	font-size:14px;
	color:#fff;
	text-align:center;
	padding-top:15px;
}

.title{
	font-weight:bold; 
	color:#444; 
	font-size: 16px
	}

.author{
	font-size:14px;
}

.asin{
	font-size:12px;
}

.details{
	text-decoration: none;
	font-size:13px;
	color:#442;
}

This stylesheet is for the entire website, so you won’t need to edit it anymore.

At this point we can run the app, by using the command ‘dev_appserver.py . Visit the url: http://localhost:8080/ while the server is still running, and you should see our app’s homepage.

With this we have our app’s basic structure is up and running. Jump to the next part to see how we construct and sign the request for Amazon book data, and parse the returned XML to get our values.

7 Responses to “Set up an Amazon Book Store on Google App Engine – 1”

  1. Steve Greenberg July 24, 2011 at 6:33 pm #

    When I try to use http://amazingamazonstore.appspot.com/, it gives me a python traceback.

    I search for “clifford”, and receive:

    Traceback (most recent call last):
    File “/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py”, line 702, in __call__
    handler.post(*groups)
    File “/base/data/home/apps/amazingamazonstore/1.348536955453416601/main.py”, line 23, in post
    books = instance.processurl(url)
    File “/base/data/home/apps/amazingamazonstore/1.348536955453416601/main.py”, line 80, in processurl
    values['image'] = book.MediumImage.URL
    AttributeError: ‘NoneType’ object has no attribute ‘URL’

    • rutwick August 31, 2011 at 4:08 am #

      Hi Steve,
      It’s probably due to an error XML that is returned when no results for the entered keyword are found or the keyword is wrong. I’ve noticed the error too, I guess I’ve missed handling the error condition (or mishandled the keyword). I’ll fix it soon. Thanks a lot !

  2. Mark April 19, 2012 at 8:28 pm #

    Hi Rutwick,

    Thanks for a very helpful post. I can’t get it to work though and I wonder if you have a link available to download the complete source code?

    (The download link in your article is missing)

    Thank you!!!

    Mark

    • rutwick April 24, 2012 at 10:06 am #

      Hi,
      The source is what I’ve pasted throughout! Just copy paste it into files and use it.

      - Rutwick

  3. JoJo1956 September 26, 2013 at 9:19 am #

    interesting! on Steve’s remark: if i search for ‘Bob Dylan’ i get the error. if i only enter ‘Dylan’ it works. probably some url encoding to be done.

    • rutwick September 28, 2013 at 1:32 pm #

      True that! I have a fixed version of the code if you’re interested! Just don’t seem to find the time to upgrade the post!
      It works here: http://rutwicksamazonstore.appspot.com/

Trackbacks and Pingbacks

  1. Tweets that mention Set up an Amazon Book Store on Google App Engine – 1 | Rutwick Gangurde's Blog -- Topsy.com - February 23, 2011

    [...] This post was mentioned on Twitter by Rutwick Gangurde, Rutwick Gangurde. Rutwick Gangurde said: Set up an Amazon Book Store on Google App Engine -3 part tutorial.. http://blog.rutwick.com/set-up-an-amazon-book-store-on-google-app-engine [...]

Leave a Reply