Select to view content in your preferred language

Create a new Hosted Feature Service in ArcGIS Online and add a Feature Layer with the ArcGIS API for Python

2782
3
02-15-2025 05:01 AM
Clubdebambos
MVP Regular Contributor
3 3 2,782

 

Introduction

The ArcGIS API for Python is a powerful Python library that allows users to interact with and automate tasks in ArcGIS Online (or Portal). The API is excellent for programmatically creating, maintaining, and updating components of ArcGIS Online along with performing analysis tasks. In this blog post we will focus on creating a new Hosted Feature Service and adding a Feature Layer. We will see the minimum viable Feature Layer definition required to add a new Feature Layer to an existing Feature Service.

arcgis modules

The API provides access to your organisations ArcGIS Online via the GIS class in the gis module. This GIS class is the gateway to ArcGIS Online. We also need to import the FeatureLayerCollectionclass. A FeatureLayerCollection object represents a Feature Service in ArcGIS Online.

 

from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection

 

Accessing ArcGIS Online

Our first port of call is to access your ArcGIS Online via the GIS class. There are a handful of ways to achieve access, if you are logged into your ArcGIS Online in ArcGIS Pro you can simply use "home", otherwise, another common way is to provide the ArcGIS Online URL, followed by your username and password.

 

## Access AGOL
agol = GIS("home")
## Access AGOL
agol = GIS(
    url = "https://your_organisation.maps.arcgis.com/",
    username = "Your_Username",
    password = "Your_Password"
)

 

The Name/Type of the Feature Service to Create

I'm sure you already have a name for the Feature Service in mind. This name is what gets embedded in the URL for the Feature Service, it is locked-in once the Feature Service is created. This is also the title of the Feature Service, which you see in the Contents of ArcGIS Online, which you can alter at any time after the Feature Service is created. 

 

 

service_name = "API_CREATED_SERVICE"
service_type = "featureService"

 

Create the Feature Service

We utilise the ContentManager create_service()method to create the new Hosted Feature Service. This method will return an Item object representing our newly created Feature Service content item.

 

empty_service_item = agol.content.create_service(
    name = service_name,
    service_type = service_type,
)

 

The Feature Layer Definition (Dictionary)

The aim in this blog is to look at the minimum Feature Layer definition required and we achieve that below with the exception of adding in some extra fields just to see the different field definitions. One of the main requirements is the indexes and setting the unique field for the Feature Layer.

 

fl_definition = {
    "type" : "Feature Layer",
    "name" : "API_CREATED_POINT_LAYER",
    "geometryType" : "esriGeometryPoint", # esriGeometryPolygon, esriGeometryPolyline
    "fields" : [
        {
            "name" : "OBJECTID",
            "type" : "esriFieldTypeOID",
            "actualType" : "int",
            "alias" : "OBJECTID",
            "sqlType" : "sqlTypeInteger",
            "nullable" : False,
            "editable" : False
        },{
            "name": "INTEGER_FIELD",
            "type": "esriFieldTypeInteger",
            "actualType": "int",
            "alias": "Integer Field",
            "sqlType": "sqlTypeInteger",
            "nullable": True,
            "editable": True
        },{
          "name": "STRING_FIELD",
          "type": "esriFieldTypeString",
          "actualType": "nvarchar",
          "alias": "String Field",
          "sqlType": "sqlTypeNVarchar",
          "length": 25,
          "nullable": True,
          "editable": True
        },
        {
          "name": "DOUBLE_FIELD",
          "type": "esriFieldTypeDouble",
          "actualType": "float",
          "alias": "Decimal Field",
          "sqlType": "sqlTypeFloat",
          "nullable": True,
          "editable": True
        },
        {
          "name": "DATE_FIELD",
          "type": "esriFieldTypeDate",
          "alias": "Date Field",
          "sqlType": "sqlTypeOther",
          "nullable": True,
          "editable": True
        }
    ],
    "indexes" : [ # required index for Primary Key
        {
            "name" : "PK_IDX",
            "fields" : "OBJECTID",
            "isAscending" : True,
            "isUnique" : True,
            "description" : "clustered, unique, primary key"
        }
    ],
    "objectIdField" : "OBJECTID",
    "uniqueField" : { # a unique field is required
        "name" : "OBJECTID",
        "isSystemMaintained" : True
    }
}

 

What other definitions could we add?

We could add in the symbology (drawingInfo) definition for the Feature Layer, the Popup (popupInfo) definition, Label (labelingInfo) definitions, and other properties such as id (not required as ArcGIS Online will handle this for you), and description amongst others.

Add the Feature Layer Definition to the Feature Service

The final hurdle, adding the Feature Layer definition to the Feature Service. We first create a FeatureLayerCollection object from the Item object. A FeatureLayerCollection represents the Feature Service. 

 

## Create a FeatureLayerCollection object from the Item object
flc = FeatureLayerCollection.fromitem(empty_service_item)

## Update the JSON definition of the Service to include the layer
flc.manager.add_to_definition({"layers": [fl_definition]})

 

The Output

The create Feature Service content item.

Clubdebambos_0-1739624227070.png

The service item homepage.

Clubdebambos_1-1739624264503.png

The fields created.

Clubdebambos_2-1739624306251.png

The Full Script

 

from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection

## Access AGOL
agol = GIS("home")

## the service name and type to create
service_name = "API_CREATED_SERVICE"
service_type = "featureService"

## create the feature service
empty_service_item = agol.content.create_service(
    name = service_name,
    service_type = service_type,
)

fl_definition = {
    "type" : "Feature Layer",
    "name" : "API_CREATED_POINT_LAYER",
    "geometryType" : "esriGeometryPoint", # esriGeometryPolygon, esriGeometryPolyline
    "fields" : [
        {
            "name" : "OBJECTID",
            "type" : "esriFieldTypeOID",
            "actualType" : "int",
            "alias" : "OBJECTID",
            "sqlType" : "sqlTypeInteger",
            "nullable" : False,
            "editable" : False
        },{
            "name": "INTEGER_FIELD",
            "type": "esriFieldTypeInteger",
            "actualType": "int",
            "alias": "Integer Field",
            "sqlType": "sqlTypeInteger",
            "nullable": True,
            "editable": True
        },{
          "name": "STRING_FIELD",
          "type": "esriFieldTypeString",
          "actualType": "nvarchar",
          "alias": "String Field",
          "sqlType": "sqlTypeNVarchar",
          "length": 25,
          "nullable": True,
          "editable": True
        },
        {
          "name": "DOUBLE_FIELD",
          "type": "esriFieldTypeDouble",
          "actualType": "float",
          "alias": "Decimal Field",
          "sqlType": "sqlTypeFloat",
          "nullable": True,
          "editable": True
        },
        {
          "name": "DATE_FIELD",
          "type": "esriFieldTypeDate",
          "alias": "Date Field",
          "sqlType": "sqlTypeOther",
          "nullable": True,
          "editable": True
        }
    ],
    "indexes" : [ # required index for Primary Key
        {
            "name" : "PK_IDX",
            "fields" : "OBJECTID",
            "isAscending" : True,
            "isUnique" : True,
            "description" : "clustered, unique, primary key"
        }
    ],
    "objectIdField" : "OBJECTID",
    "uniqueField" : { # a unique field is required
        "name" : "OBJECTID",
        "isSystemMaintained" : True
    }
}

## Create a FeatureLayerCollection object from the Item object
flc = FeatureLayerCollection.fromitem(empty_service_item)

## Update the JSON definition of the Service to include the layer
flc.manager.add_to_definition({"layers": [fl_definition]})

 

 

3 Comments
mikaël
Frequent Contributor

Glad to finally have this info documented and all in one post!

Just a quick note: you mention that we could add other properties such as the name, although it is already included in your feature layer definition ("API_CREATED_POINT_LAYER").

Thanks!

PeterKnoop
MVP Regular Contributor

Great starting point for folks learning how to do this! 

I might suggest adding a call to is_service_name_available to verify the service_name is not already in use; in our org with over 10,000 users, most of the common variations on "test" are already taken!

Clubdebambos
MVP Regular Contributor

@mikaël thanks for pointing that out, I meant to say description over name. I'll edit that.

@PeterKnoopthats the content for the next blog 😅 I initially had that in there and took it out just to focus on the task at hand. I want o clearly explain the difference between the service name and title. 

Thank you both for the comments.

Contributors
About the Author
Glen Bambrick is GIS Consultant with extensive experience utilising skills for GIS project management, quality map production, data management, geospatial analysis, standardisation, and workflow automation across a range of industries such as agriculture, oil & gas, telecommunications and engineering. Going beyond map production there is a passion for the technologies behind GIS, the databases, the programming languages, the analysis and statistical output, and continued professional development associated with GIS. You will mainly find me contributing in the Python and ArcGIS API for Python Communities.