how to access external API

130 views
Skip to first unread message

Alex Glaros

unread,
Sep 30, 2015, 2:29:47 PM9/30/15
to web2py-users
Am new to APIs.

How do I access this API and get data to w2p vars?


Goal is read user's IP address to determine what country/city they are in.

Thanks,

Alex Glaros

Leonel Câmara

unread,
Sep 30, 2015, 3:14:26 PM9/30/15
to web2py-users
I haven't tried it but, this should work and it's a simple enough example

# In the default controller

def locateme():
   
import json
   
from gluon.tools import fetch
    location_data
= json.loads(fetch('http://ipinfo.io/%s/json' % request.client))
   
return location_data


# In the view default/locateme.html

{{extend 'layout.html'}}


<dl>
 
<dt>City</dt>
  <dd>{{=city}}</
dd>
 
<dt>Region</dt>
  <dd>{{=region}}</
dd>
 
<dt>Country</dt>
  <dd>{{=country}}</
dd>
</dl>

Then you'll probably need to add some checking for cases where the API doesn't return a city/region/country

Alex Glaros

unread,
Sep 30, 2015, 3:59:05 PM9/30/15
to web2py-users
Leonel, this string works from a browser (http://ipinfo.io/8.8.8.8/json)  so your sample is very close to working, but am getting an error.  Also, is word supposed to be "load" or "loads" or doesn't matter?

<class 'urllib2.URLError'> <urlopen error [Errno 10061] No connection could be made because the target machine actively refused it>

Version

web2py™Version 2.12.2-stable+timestamp.2015.08.09.14.29.44
PythonPython 2.7.9: C:\alex\alt_web2py\web2py\web2py.exe (prefix: C:\Python27)

Traceback

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
Traceback (most recent call last):
File "C:\alex\alt_web2py\web2py\gluon\restricted.py", line 227, in restricted
exec ccode in environment
File "C:/alex/alt_web2py/web2py/applications/ES1/controllers/default.py", line 5824, in <module>
File "C:\alex\alt_web2py\web2py\gluon\globals.py", line 412, in <lambda>
self._caller = lambda f: f()
File "C:\alex\alt_web2py\web2py\gluon\tools.py", line 3769, in f
return action(*a, **b)
File "C:/alex/alt_web2py/web2py/applications/ES1/controllers/default.py", line 5770, in locate_me

location_data = json.loads(fetch('http://ipinfo.io/%s/json' % request.client
))
File "C:\alex\alt_web2py\web2py\gluon\tools.py", line 4749, in fetch
html = urllib2.urlopen(req).read()
File "urllib2.py", line 154, in urlopen
File "urllib2.py", line 431, in open
File "urllib2.py", line 449, in _open
File "urllib2.py", line 409, in _call_chain
File "urllib2.py", line 1227, in http_open
File "urllib2.py", line 1197, in do_open
URLError: <urlopen error [Errno 10061] No connection could be made because the target machine actively refused it>

Error snapshot help

<class 'urllib2.URLError'>(<urlopen error [Errno 10061] No connection could be made because the target machine actively refused it>)

Leonel Câmara

unread,
Sep 30, 2015, 4:37:53 PM9/30/15
to web...@googlegroups.com
Well the error says it all. Your connection is being refused. It appears you bumped into the 1k calls API limit by making too many calls.

It has to be json.loads because fetch returns a string.

Alex Glaros

unread,
Sep 30, 2015, 4:47:08 PM9/30/15
to web2py-users
only made a couple of attempts, not one thousand.  And the call from browser still works so doesn't appear that number of attempts is causing it to actively refuse my IP.  Also tried another company and got same error:  

is there another way to get the info without json or fetch or maybe loads?  Am wondering if they are adding anything.  

any work-around ideas would be appreciated

thanks

Alex

Leonel Câmara

unread,
Sep 30, 2015, 7:31:01 PM9/30/15
to web2py-users
There must be something wrong on your side (maybe a firewall blocking python or another network issue) because this works fine on my tests.

Alex Glaros

unread,
Sep 30, 2015, 7:42:16 PM9/30/15
to web...@googlegroups.com
I think you're right.   Will try from home tonight.  Thanks!

Alex Glaros

unread,
Oct 1, 2015, 12:37:13 AM10/1/15
to web2py-users
it pretty much works from PythonAnywhere, except it doesn't put data in the vars correctly .  Data looks like this with strange letter "u" in front:

{u'loc': u'38.5249,-121.9708', u'city': u'Winters', u'country': u'US', u'region': u'California', u'hostname': u'No Hostname', u'ip': u'108.70.229.156', u'org': u'AS7018 AT&T Services, Inc.', u'postal': u'95694'}

<type 'exceptions.NameError'> name 'city' is not defined


how to get clean data in the vars?  It did not accept location_data.city or location_data[city] either

thanks,

Alex

Leonel Câmara

unread,
Oct 1, 2015, 3:47:42 AM10/1/15
to web2py-users
That's not problem in python 2 a string like this u'' just means it's unicode you can convert it to utf-8 but there's no need.

If you notice how I do it in my example I use the dict the API returns as the dict my controller returns, so you access it's keys directly in the view. 

Alex Glaros

unread,
Oct 1, 2015, 11:26:45 AM10/1/15
to web2py-users
sure, I copied your view exactly, but is there anything different in the view that you tested on your side?
{{extend 'layout.html'}}
<dl>
 <dt>City</dt>
 <dd>{{=city}}</dd>
 <dt>Region</dt>
 <dd>{{=region}}</dd>
 <dt>Country</dt>
 <dd>{{=country}}</dd>
</dl>

Do I need to define "city" in my controller?  I get this error:

<type 'exceptions.NameError'> name 'city' is not defined

Version

web2py™Version 2.9.5-stable+timestamp.2014.03.16.02.35.39
PythonPython 2.7.6: /usr/local/bin/uwsgi (prefix: /usr)

Traceback

1.
2.
3.
4.
5.
6.
Traceback (most recent call last):
File "/home/alexglaros/web2py/gluon/restricted.py", line 220, in restricted
exec ccode in environment
File "/home/alexglaros/web2py/applications/engagementsquared/views/default/locate_me.html", line 83, in <module>
NameError: name 'city' is not defined

Error snapshot help

<type 'exceptions.NameError'>(name 'city' is not defined)

inspect attributes

Frames

  • File /home/alexglaros/web2py/gluon/restricted.py in restricted at line 220 code arguments variables

  • File /home/alexglaros/web2py/applications/engagementsquared/views/default/locate_me.html in <module> at line 83 code arguments variables

    Function argument list

    ()

    Code listing
    74.
    75.
    76.
    77.
    78.
    79.
    80.
    81.
    82.
    83.

    84.
    85.
    86.
    87.
    88.
    89.
    90.
    91.
    92.
    93.
        response.write('\n        </div>\n        ', escape=False)
    pass
    response.write('\n\n <div class="', escape=False)
    response.write(middle_columns)
    response.write('">\n ', escape=False)
    response.write('\n ', escape=False)
    response.write('\n\n', escape=False)
    response.write(location_data)
    response.write('\n<dl>\n <dt>City</dt>\n <dd>', escape=False)
    response.write(city)

    response.write('</dd>\n <dt>Region</dt>\n <dd>{=region}}</dd>\n <dt>Country</dt>\n <dd>{=country}}</dd>\n</dl>', escape=False)
    response.write('\n ', escape=False)
    response.write('\n </div>\n\n ', escape=False)
    if right_sidebar_enabled:
    response.write('\n <div class="span3">\n ', escape=False)
    response.write('\n <h3>Right Sidebar</h3>\n <p></p>\n ', escape=False)
    response.write('\n </div>\n ', escape=False)
    pass
    response.write('\n </section><!--/main-->\n\n <!-- Footer ================================================== -->\n\t <footer class="footer" id="footer">\n \n<table id="over_arching_footer_table" tr><td id="1st_column" width="33%" style="padding:25px">\n ', escape=False)
    response.write(' <!-- this is default footer -->\n <div class="copyright pull-left"><ul>\n <li>Version 1.0 - Engagement Squared </li>\n <li> ', escape=False)

thanks,

Alex

Diogene Laerce

unread,
Oct 1, 2015, 2:27:13 PM10/1/15
to web...@googlegroups.com


Le 01/10/2015 17:26, Alex Glaros a écrit :
> sure, I copied your view exactly, but is there anything different in
> the view that you tested on your side?
> |
> {{extend 'layout.html'}}
> <dl>
> <dt>City</dt>
> <dd>{{=city}}</dd>
> <dt>Region</dt>
> <dd>{{=region}}</dd>
> <dt>Country</dt>
> <dd>{{=country}}</dd>
> </dl>
> |
>
> Do I need to define "city" in my controller? I get this error:
>
>
> <type 'exceptions.NameError'> name 'city' is not defined
>

As a learned lesson, you need to make sure of its availability :

{{city = globals().get('city', '')}}

in the view. I guess you will have the same error with the other
variables.

Good luck,

--
“One original thought is worth a thousand mindless quotings.”
“Le vrai n'est pas plus sûr que le probable.”

Diogene Laerce


signature.asc

Alex Glaros

unread,
Oct 1, 2015, 3:05:24 PM10/1/15
to web2py-users
hi Laer,

it's available as can be seen from displaying contents of "location_data"

{u'loc': u'38.6071,-121.4633', u'city': u'Sacramento', u'country': u'US', u'region': u'California', u'hostname': u'No Hostname', u'ip': u'159.145.7.104', u'org': u'AS1226 California Technology Agency', u'postal': u'95815'}
City
Region
Country

but somehow the available data does not go into the var names

thanks,

Alex

Diogene Laerce

unread,
Oct 1, 2015, 4:01:48 PM10/1/15
to web...@googlegroups.com
I can see that your file is named locate_me.html, is your function
in the controller has the same name ?..
signature.asc

Alex Glaros

unread,
Oct 1, 2015, 4:15:10 PM10/1/15
to web...@googlegroups.com
sure, it is the same

maybe I need to define the globals or location_data as a dict?

as a work-around, I can read location_data as string, but seems that a simple answer might be available

Alex Glaros

unread,
Oct 1, 2015, 4:30:40 PM10/1/15
to web2py-users
This works.  But is it good programming?

in controller, convert into a dict:

    location_data = dict(json.loads(fetch('http://ipinfo.io/%s/json' % request.client)))

in view:

  <dd>{{=location_data['city']}}</dd>


Diogene Laerce

unread,
Oct 1, 2015, 4:38:27 PM10/1/15
to web...@googlegroups.com
As Leonel said, you should access it with "city" directly.

Kind regards,
signature.asc

Leonel Câmara

unread,
Oct 1, 2015, 6:31:29 PM10/1/15
to web2py-users
Alex I think you're slightly confused, let me explain.

This was the original controller function I suggested.

def locateme():
    
import json
    
from gluon.tools import
 fetch
    location_data 
= json.loads(fetch('http://ipinfo.io/%s/json' % request.client))
    
return location_data

Note that it returns location_data, what is location data? Well it's a dict because that's what the API returns and the json module takes care of that for us.

In web2py, controller functions that return dicts make the keys in that dictionary available in the view. So in the view you shouldn't be acessing location_data directly you should be accessing its keys. 

To further illustrate I could rewrite locateme like this

def locateme():
    
import json
    
from gluon.tools import
 fetch
    location_data 
= json.loads(fetch('http://ipinfo.io/%s/json' % request.client))
    
return dict(city=location_data[u'city'], region=location_data[u'region'], country=location_data[u'country'],)

But this would be superfluous because location_data is already a dict I can perfectly well return.

Alex Glaros

unread,
Oct 1, 2015, 6:45:11 PM10/1/15
to web2py-users
thanks Leonel,  

I get the logic but it didn't work in my configuration, however I'm very happy to have it work with the extra "dict" term.  

Appreciate for your patience.  It's my introduction to API and JSON.  

great to have these explanations!

Alex
Reply all
Reply to author
Forward
0 new messages