Skip to main content

Task 02 — API to List Industry Names

Difficulty: Beginner
Goal: Add a new admin endpoint that returns a flat list of all industry names.


What you'll learn
  • The 6-file pattern for adding a new endpoint (route → service → formatter → model → query → DB method)
  • How admin routes are registered in app/apis/admin.py
  • How to query the industries container (database: standard-categories) in Cosmos DB

Endpoint spec

GET /api/admin/industries/names
Authorization: Bearer <admin-token>

Response 200:
{
"status": "success",
"status_code": 200,
"data": ["Industry A", "Industry B", "Industry C"]

// industryName is the real field name on industry documents

}

Files to create / edit

FileWhat to do
app/routes/admin/industry_names.pyDefine namespace + resource class
app/services/admin/industry_names_service.pyQuery DB and return raw list
app/formatters/admin/industry_names_formatter.pyExtract just the name field
app/models/industry_names_models.pySwagger response model
app/database/queires_list.pyAdd get_all_industry_names() query
app/database/database_supporter.pyAdd get_all_industry_names() DB method
app/apis/admin.pyRegister the new namespace

Step-by-step

Route

# app/routes/admin/industry_names.py
from flask_restx import Namespace, Resource, marshal
from flask_jwt_extended import jwt_required
from app.auth.auth import admin_required
from app.services.admin.industry_names_service import IndustryNamesService
from app.formatters.admin.industry_names_formatter import IndustryNamesFormatter
from app.models.success_models import GenericSuccessDataModel

industryNamesNamespace = Namespace('Industry Names', path='/industries/names')
industryNamesNamespace.add_model(GenericSuccessDataModel.name, GenericSuccessDataModel)

@industryNamesNamespace.route('')
class IndustryNamesRoute(Resource):
@jwt_required()
@admin_required()
@industryNamesNamespace.response(200, 'Success', model=GenericSuccessDataModel)
def get(self):
data = IndustryNamesService().get_all()
formatted = IndustryNamesFormatter(data).format()
return marshal({'status': 'success', 'data': formatted}, GenericSuccessDataModel), 200

Service

# app/services/admin/industry_names_service.py
from app.database.database_supporter import DatabaseSupporter

class IndustryNamesService:
def get_all(self):
return DatabaseSupporter.get_all_industry_names()

Formatter

# app/formatters/admin/industry_names_formatter.py
class IndustryNamesFormatter:
def __init__(self, data):
self.data = data

def format(self):
# Real field name on industry documents is 'industryName', not 'name'
return [item['industryName'] for item in self.data if item.get('industryName')]

Query

# app/database/queires_list.py — add inside the Queries class
@staticmethod
@validate_values()
def get_all_industry_names():
# Select only the fields you need — industryName and industryId are the real field names
return 'SELECT c.industryId, c.industryName FROM c'

DB method

# app/database/database_supporter.py — add as a static method
@staticmethod
def get_all_industry_names():
results = industries_container.query_items(
query=Queries.get_all_industry_names(),
enable_cross_partition_query=True
)
return list(results)
Existing method to reference

DatabaseSupporter.get_workspace_data() already fetches all industries with selected fields: industryId, industryName, meta.logo, meta.sector, meta.subSector. Look at how it's implemented before writing your own — you can follow the same pattern.


Done when
  • GET /api/admin/industries/names returns 200 with a list of name strings
  • Unauthenticated request returns 401
  • Non-admin JWT returns 1403