Obtain last edit date from REST API using Python

7820
6
Jump to solution
06-26-2015 04:12 PM
RandyBurton
MVP Alum

In the JSON file for a feature there is a property called "lastEditDate."  Has anyone developed a python script to access this information they would be willing to share?  Thanks.

Tags (3)
1 Solution

Accepted Solutions
RandyBurton
MVP Alum

As I mentioned in a previous post, using the ArcREST package is the way to go.  I also found some code in this blog that explains using the REST API to update a feature layer.  With that, I came up with the following code.  There are three basic steps, get a token, use the token to get the JSON for the feature, and extract the portion of data you are interested in.

import urllib
import urllib2
import json
import sys
import time
import collections

# Credentials and feature service information
username = "<username>"
password = "<password>" 
# Feature server url, change to your server url
fsURL = "http://services1.arcgis.com/<aaa123>/arcgis/rest/services/<feature>/FeatureServer/0"

# 1: obtain a token
referer = "http://www.arcgis.com/"
query_dict = { 'username': username, 'password': password, 'referer': referer }
query_string = urllib.urlencode(query_dict)
url = "https://www.arcgis.com/sharing/rest/generateToken"
token = json.loads(urllib.urlopen(url + "?f=json", query_string).read())

if "token" not in token:
    print(token['error'])
    sys.exit(1)

# 2: request the json data for the feature
query_dict = { "f": "json", "token": token['token'] }
jsonResponse = urllib.urlopen(fsURL, urllib.urlencode(query_dict))

# lastEditDate is in the editingInfo section of the json response
# to access other sections, change "editingInfo" to the section name ("types" for example)
# using OrderedDict keeps the file ordered as sent by server, but is not necessary
jsonOutput = json.loads(jsonResponse.read(),
                      object_pairs_hook=collections.OrderedDict)[u'editingInfo']

#3: extract the data required
editTime = int(jsonOutput['lastEditDate'])/1000
print "Last Edited: " + time.strftime('%c', time.localtime(editTime))

View solution in original post

6 Replies
XanderBakker
Esri Esteemed Contributor

Can you attach a sample json file, so I can have a look at it?

0 Kudos
RandyBurton
MVP Alum

Hello Xander,

I have included a sample json file below.

While researching my question I came across the ArcREST package on github. In it's samples folder I found a script (query_agol_layer.py) that connects to a Feature Layer's json data.  After some study of the python code, I was able to use the script to extract the lastEditDate information and convert it to a standard time format.  The code also accesses other sections of the json data - the types section is one that I'm also interested in.

Here's the json file.  LastEditDate is on line 11.  To save space, I've deleted most of the drawingInfo section at line 44 and some other parts.

{
  "currentVersion" : 10.3, 
  "id" : 0, 
  "name" : "<Name>", 
  "type" : "Feature Layer", 
  "displayField" : "<Display>", 
  "description" : "", 
  "copyrightText" : "", 
  "defaultVisibility" : true, 
  "editingInfo" : {
    "lastEditDate" : 1433103130499
  }, 
  "relationships" : [], 
  "isDataVersioned" : false, 
  "supportsCalculate" : true, 
  "supportsAttachmentsByUploadId" : true, 
  "supportsRollbackOnFailureParameter" : true, 
  "supportsStatistics" : true, 
  "supportsAdvancedQueries" : true, 
  "supportsValidateSql" : true, 
  "supportsCoordinatesQuantization" : true, 
  "advancedQueryCapabilities" : {
    "supportsPagination" : true, 
    "supportsQueryWithDistance" : true, 
    "supportsReturningQueryExtent" : true, 
    "supportsStatistics" : true, 
    "supportsOrderBy" : true, 
    "supportsDistinct" : true
  }, 
  "geometryType" : "esriGeometryPoint", 
  "minScale" : 0, 
  "maxScale" : 0, 
  "extent" : {
    "xmin" : -20037507.842788249, 
    "ymin" : -30240971.458386172, 
    "xmax" : 20037507.842788249, 
    "ymax" : 30240971.458386205, 
    "spatialReference" : {
      "wkid" : 102100, 
      "latestWkid" : 3857
    }
  }, 
  "drawingInfo":{
.......
  }, 
  "allowGeometryUpdates" : true, 
  "hasAttachments" : false, 
  "htmlPopupType" : "esriServerHTMLPopupTypeAsHTMLText", 
  "hasM" : false, 
  "hasZ" : false, 
  "objectIdField" : "OBJECTID", 
  "globalIdField" : "GlobalID", 
  "typeIdField" : "Color", 
  "fields" : [
    {
      "name" : "OBJECTID", 
      "type" : "esriFieldTypeOID", 
      "alias" : "OBJECTID", 
      "sqlType" : "sqlTypeOther", 
      "nullable" : false, 
      "editable" : false, 
      "domain" : null, 
      "defaultValue" : null
    }, 
    {
      "name" : "<FieldName>", 
      "type" : "esriFieldTypeInteger", 
      "alias" : "<FieldAlias>", 
      "sqlType" : "sqlTypeOther", 
      "nullable" : false, 
      "editable" : true, 
      "domain" : 
      {
        "type" : "codedValue", 
        "name" : "Colors", 
        "codedValues" : [
          {
            "name" : "Red", 
            "code" : 1
          }, 
          {
            "name" : "Yellow", 
            "code" : 2
          }
        ]
      }, 
      "defaultValue" : null
    } 
  ], 
  "types" : [
    {
      "id" : 1, 
      "name" : "Red", 
      "domains" : 
      {
        "Color" : {"type" : "inherited"}
      }, 
      "templates" : [
        {
          "name" : "Red", 
          "description" : "", 
          "drawingTool" : "esriFeatureEditToolPoint", 
          "prototype" : {
            "attributes" : {
              "Color" : 1, 
              "Note" : null
            }
          }
        }
      ]
    }, 
    {
      "id" : 2, 
      "name" : "Yellow", 
      "domains" : 
      {
        "Color" : {"type" : "inherited"}
      }, 
      "templates" : [
        {
          "name" : "Yellow", 
          "description" : "", 
          "drawingTool" : "esriFeatureEditToolPoint", 
          "prototype" : {
            "attributes" : {
              "Color" : 2, 
              "Note" : null
            }
          }
        }
      ]
    }
  ], 
  "templates" : [], 
  "supportedQueryFormats" : "JSON", 
  "hasStaticData" : false, 
  "maxRecordCount" : 1000, 
  "capabilities" : "Create,Delete,Query,Update,Editing,Sync"
}
XanderBakker
Esri Esteemed Contributor

Good to hear that you solved it, and thanks for posting back how you did it.

Kind regards, Xander

0 Kudos
RandyBurton
MVP Alum

As I mentioned in a previous post, using the ArcREST package is the way to go.  I also found some code in this blog that explains using the REST API to update a feature layer.  With that, I came up with the following code.  There are three basic steps, get a token, use the token to get the JSON for the feature, and extract the portion of data you are interested in.

import urllib
import urllib2
import json
import sys
import time
import collections

# Credentials and feature service information
username = "<username>"
password = "<password>" 
# Feature server url, change to your server url
fsURL = "http://services1.arcgis.com/<aaa123>/arcgis/rest/services/<feature>/FeatureServer/0"

# 1: obtain a token
referer = "http://www.arcgis.com/"
query_dict = { 'username': username, 'password': password, 'referer': referer }
query_string = urllib.urlencode(query_dict)
url = "https://www.arcgis.com/sharing/rest/generateToken"
token = json.loads(urllib.urlopen(url + "?f=json", query_string).read())

if "token" not in token:
    print(token['error'])
    sys.exit(1)

# 2: request the json data for the feature
query_dict = { "f": "json", "token": token['token'] }
jsonResponse = urllib.urlopen(fsURL, urllib.urlencode(query_dict))

# lastEditDate is in the editingInfo section of the json response
# to access other sections, change "editingInfo" to the section name ("types" for example)
# using OrderedDict keeps the file ordered as sent by server, but is not necessary
jsonOutput = json.loads(jsonResponse.read(),
                      object_pairs_hook=collections.OrderedDict)[u'editingInfo']

#3: extract the data required
editTime = int(jsonOutput['lastEditDate'])/1000
print "Last Edited: " + time.strftime('%c', time.localtime(editTime))
by Anonymous User
Not applicable

Randy, I am trying to use your code provided and run into the following errors from line 19 in your provided code:

  • token = json.loads(urllib.urlopen(url + "?f=json", query_string).read())
  • The errors I receive are as follows and was hoping you could shed some light

Runtime error
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python27\ArcGIS10.3\Lib\urllib.py", line 89, in urlopen
    return opener.open(url, data)
  File "C:\Python27\ArcGIS10.3\Lib\urllib.py", line 210, in open
    return getattr(self, name)(url, data)
  File "C:\Python27\ArcGIS10.3\Lib\urllib.py", line 437, in open_https
    h.endheaders(data)
  File "C:\Python27\ArcGIS10.3\Lib\httplib.py", line 991, in endheaders
    self._send_output(message_body)
  File "C:\Python27\ArcGIS10.3\Lib\httplib.py", line 844, in _send_output
    self.send(msg)
  File "C:\Python27\ArcGIS10.3\Lib\httplib.py", line 806, in send
    self.connect()
  File "C:\Python27\ArcGIS10.3\Lib\httplib.py", line 1198, in connect
    self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
  File "C:\Python27\ArcGIS10.3\Lib\ssl.py", line 392, in wrap_socket
    ciphers=ciphers)
  File "C:\Python27\ArcGIS10.3\Lib\ssl.py", line 148, in __init__
    self.do_handshake()
  File "C:\Python27\ArcGIS10.3\Lib\ssl.py", line 310, in do_handshake
    self._sslobj.do_handshake()
IOError: [Errno socket error] [Errno 1] _ssl.c:510: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

I am truly interested in utilizing your solution and appreciate whatever assistance you can provde. Thanks!

0 Kudos
RandyBurton
MVP Alum

Since the error is happening at line 19, it suggests that there is a problem connecting to your server to obtain a token.  There are a couple of help pages Generate Token and Generate Token (2) that may be of assistance.

My code shows a simple connection to ArcGIS Online.  You will need to change the fsURL in line 12 to point to your feature service.  If you are using your own ArcGIS server the token and referrer urls in lines 15 and 18 will need to be changed; possibly you will need to use the client parameter.

The following code snippet illustrates how you could connect to your own server instead of a feature hosted on AGO.

tokenURL = 'http://' + server + '/arcgis/admin/generateToken'
params = {'username': username, 'password': password, 'client': 'requestip', 'f': 'pjson', 'expiration': 1440}
req = urllib2.Request(tokenURL, urllib.urlencode(params))
response = urllib2.urlopen(req)
data = json.load(response)        
token = data['token']