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
industriescontainer (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
| File | What to do |
|---|---|
app/routes/admin/industry_names.py | Define namespace + resource class |
app/services/admin/industry_names_service.py | Query DB and return raw list |
app/formatters/admin/industry_names_formatter.py | Extract just the name field |
app/models/industry_names_models.py | Swagger response model |
app/database/queires_list.py | Add get_all_industry_names() query |
app/database/database_supporter.py | Add get_all_industry_names() DB method |
app/apis/admin.py | Register 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/namesreturns200with a list of name strings - Unauthenticated request returns
401 - Non-admin JWT returns
1403