Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Place Page Functionality to Flask Service #4627

Merged
merged 5 commits into from
Sep 27, 2024

Conversation

dwnoble
Copy link
Contributor

@dwnoble dwnoble commented Sep 14, 2024

Migrate Place Page Functionality to Flask Service with place_charts and related_places Endpoints

This PR migrates place page functionality from the Mixer service's /v1/internal/page/place endpoint to the Flask service by introducing two new endpoints: place_charts and related_places. This change centralizes application-specific logic within the Flask service and optimizes payload sizes by adjusting how observational data is handled.

TODO / Next steps:

  • Add childPlaceType
  • Fetch geo overlapping places?
  • Create new place page layout based on updated mockups
  • Use these new endpoints to fetch data for the updated place page

New Endpoints

/api/dev-place/charts/<place_dcid>

  • Returns chart definitions for a specified place, translated into the user's locale.
  • Features:
    • Filters charts based on data availability for the place.
    • Excludes observational data from the payload; web components will fetch this data as needed.
    • Supports localization for chart titles and category strings.

/api/dev-place/related_places/<place_dcid>

  • Provides related place data, including child, nearby, and similar places.
  • Features:
    • Fetches child places contained within the specified place.
    • Retrieves geographically nearby places.
    • Identifies similar places based on predefined cohorts.
    • Supports localization for place names.

Rationale

  • Application-Specific Logic: Moving the logic from Mixer to Flask keeps application-specific code within the application layer.
  • Optimized Payloads: Excludes inline observational data resulting in a smaller payloads. Observational data will be fetched separately by the client via web components.

Testing

  • Unit Tests: Added tests for both endpoints including basic localization tests

Copy link
Contributor

@beets beets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for the late review!

we actually started with these as separate calls processed in flask, then we combined it in flask, then we moved it to mixer -- each move was driven by page latency improvements.

would we make both api calls concurrently from the client? the results from both calls would be needed to start rendering charts so i wonder what would improve page performance (since it's flask, maybe it's better to keep it split like this).

thanks also for adding types & tests!

return wrapper


from flask import jsonify
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: this should be added to the list of includes above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, fixed

@@ -922,3 +923,44 @@ def post_body_cache_key():
else:
cache_key = full_path
return cache_key


def log_execution_time(func):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice!

}

# Define blueprint
bp = Blueprint("dev_place_api", __name__, url_prefix='/api/place')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any issues with shared_api/place.py also registering the same url_prefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout- it looks like blueprint allows for this, but it's a little confusing. Changing to /api/dev-place temporarily, and ill migrate it to /api/place before this makes it to production

# See the License for the specific language governing permissions and
# limitations under the License.
"""
Dev Place API dataclass types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can drop the "dev" prefix in the files so we don't forget to remove when these pages become the default place page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done



@dataclass
class Chart:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice - thanks for adding types

"""
charts = []
for page_config_item in chart_config:
denominator = next(iter(page_config_item.get("denominator", [])), None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i'm reading this right, this gets the first denominator from the list.

could you make sure it works in cases like this
the sv and denominator should come from the same index where the denominator.size() > 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! fixed

Comment on lines 327 to 328
Builds a dictionary of translated category strings for each unique category found in
the chart configuration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

place = place_utils.fetch_place(place_dcid, locale=g.locale)

# Retrieve available place page charts
chart_config = current_app.config['CHART_CONFIG']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't forget to make a deep copy of the chart_config before passing it along to functions that alter the config. in prod, the config will get permanently updated across requests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call-done!

"scale":
True,
"denominator":
"Count_Person_25OrMoreYears",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider adding another test with more denominators, and one without translations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

@@ -13,10 +13,18 @@
# limitations under the License.
"""Helper functions for development place page routes"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can drop "development" here too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@dwnoble
Copy link
Contributor Author

dwnoble commented Sep 26, 2024

sorry for the late review!

we actually started with these as separate calls processed in flask, then we combined it in flask, then we moved it to mixer -- each move was driven by page latency improvements.

would we make both api calls concurrently from the client? the results from both calls would be needed to start rendering charts so i wonder what would improve page performance (since it's flask, maybe it's better to keep it split like this).

thanks also for adding types & tests!

Good to know! I've been paying attention to the latency, and i'll put together some metrics about how this performs vs the mixer version.

Yes im thinking we can make both calls concurrently from the client, and we can have some logic to render the page after both calls return.

@dwnoble dwnoble enabled auto-merge (squash) September 27, 2024 20:50
@dwnoble dwnoble merged commit b204f85 into datacommonsorg:master Sep 27, 2024
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants