Skip to content

Add a specialized agent to build API endpoints#2811

Merged
whabanks merged 3 commits intomainfrom
experiment/endpoint-builder-agent
Mar 30, 2026
Merged

Add a specialized agent to build API endpoints#2811
whabanks merged 3 commits intomainfrom
experiment/endpoint-builder-agent

Conversation

@whabanks
Copy link
Copy Markdown
Contributor

@whabanks whabanks commented Mar 25, 2026

Summary | Résumé

This PR adds a new custom agent rest-endpoint-builder that specializes in adding / creating new API endpoints. It's instructed on common patterns and code standards within Notify. A few examples:

  • Blueprint registration
  • When to use a simple JSON schema for validation vs class based Marshmallow schemas
  • How to determine when a new app/<module>/rest.py is appropriate vs adding to an existing rest.py
  • Auth and blueprint differences between admin endpoints and public facing v2 endpoints
  • Usage of `register_errors() to hook up standard error handlers to new endpoints
  • Unit test patterns, ensuring proper usage of existing fixtures (admin_request, client_request, sample_<entity> etc.)

The agent is selectable within vscode in the AI chat panel:

image

Simple example endpoint implemented using this custom agent:
#2812

More complex example(s) to come to test this out.

Related Issues | Cartes liées

Test instructions | Instructions pour tester la modification

TODO: Fill in test instructions for the reviewer.

Release Instructions | Instructions pour le déploiement

None.

Reviewer checklist | Liste de vérification du réviseur

  • This PR does not break existing functionality.
  • This PR does not violate GCNotify's privacy policies.
  • This PR does not raise new security concerns. Refer to our GC Notify Risk Register document on our Google drive.
  • This PR does not significantly alter performance.
  • Additional required documentation resulting of these changes is covered (such as the README, setup instructions, a related ADR or the technical documentation).

⚠ If boxes cannot be checked off before merging the PR, they should be moved to the "Release Instructions" section with appropriate steps required to verify before release. For example, changes to celery code may require tests on staging to verify that performance has not been affected.

@jzbahrai jzbahrai marked this pull request as ready for review March 25, 2026 19:54
@jzbahrai jzbahrai requested a review from jimleroyer as a code owner March 25, 2026 19:54
Copilot AI review requested due to automatic review settings March 25, 2026 19:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new custom Copilot agent definition (rest-endpoint-builder) intended to scaffold Notify REST API endpoints consistently across internal (admin) and v2 (public) APIs.

Changes:

  • Introduces .github/agents/rest-endpoint-builder.agent.md with guidance/templates for creating endpoints, DAOs, schemas, blueprint registration, and tests.
  • Documents internal vs v2 structural differences (blueprints, errors, validation, routing).
  • Provides example snippets for schema dicts, DAO functions, route handlers, and test stubs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
```

Available shared definitions: `uuid`, `nullable_uuid`, `personalisation`, `https_url`.
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The doc lists “Available shared definitions” but omits letter_personalisation, which is also defined in app.schema_validation.definitions. Consider either making this list explicitly non-exhaustive or pointing readers to the definitions module so the agent doesn’t miss existing shared definitions.

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +190
@<entity>_blueprint.route("/<uuid:<entity>_id>", methods=["GET"])
def get_<entity>_by_id(service_id, <entity>_id):
<entity> = dao_get_<entity>_by_id_and_service_id(<entity>_id, service_id)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The internal Blueprint route examples use an invalid Flask path-converter syntax (/<uuid:<entity>_id>). Flask expects /<uuid:<param_name>> (e.g., /<uuid:template_folder_id>), and the nested angle-bracket form will produce broken routes if copied/generated.

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +216
@<entity>_blueprint.route("/<uuid:<entity>_id>", methods=["POST"])
def update_<entity>(service_id, <entity>_id):
data = request.get_json()
validate(data, post_update_<entity>_schema)
<entity> = dao_get_<entity>_by_id_and_service_id(<entity>_id, service_id)
# Update fields from data
for key, value in data.items():
setattr(<entity>, key, value)
dao_update_<entity>(<entity>)
return jsonify(<entity>.serialize()), 200


@<entity>_blueprint.route("/<uuid:<entity>_id>", methods=["DELETE"])
def delete_<entity>(service_id, <entity>_id):
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Same issue as above for the update/delete examples: the route path uses /<uuid:<entity>_id>, which isn’t valid Flask syntax. Update these examples to use /<uuid:<param_name>> (for the template placeholder, something like /<uuid:{entity}_id> may be clearer and still renders to valid Flask code).

Copilot uses AI. Check for mistakes.
from app.v2.<module>.<module>_schemas import get_<entity>_by_id_request


@v2_<entity>_blueprint.route("/<entity_id>", methods=["GET"])
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The v2 route example has a parameter name mismatch: the route captures <entity_id> but the function argument is <entity>_id. Flask binds route variables by name, so this would raise a TypeError at runtime if generated as-is. Align the route variable and the function parameter name.

Suggested change
@v2_<entity>_blueprint.route("/<entity_id>", methods=["GET"])
@v2_<entity>_blueprint.route("/<<entity>_id>", methods=["GET"])

Copilot uses AI. Check for mistakes.
Comment on lines +397 to +399
from flask import current_app, jsonify, request

from app.authentication.auth import AuthError
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The v2 route example imports current_app, request, and AuthError but the snippet doesn’t use them. Since this repo runs Ruff with PyFlakes enabled on app/ and tests/, generated files with unused imports will fail CI. Adjust the example to only import what’s required (or explicitly show when/why those names are used).

Suggested change
from flask import current_app, jsonify, request
from app.authentication.auth import AuthError
from flask import jsonify

Copilot uses AI. Check for mistakes.
Comment on lines +254 to +260
import pytest
from flask import url_for

from app.models import <Model>
from tests.app.db import create_service


Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The test stub example includes several imports that aren’t used in the stub (pytest, url_for, <Model>, create_service). Because Ruff (PyFlakes) runs on tests/, generated stubs that keep these unused imports will fail lint. Suggest removing unused imports in the example (or include minimal, actually-used imports in the stub).

Suggested change
import pytest
from flask import url_for
from app.models import <Model>
from tests.app.db import create_service

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@jzbahrai jzbahrai left a comment

Choose a reason for hiding this comment

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

👏🏽

@whabanks whabanks merged commit 9fd1e1e into main Mar 30, 2026
9 checks passed
@whabanks whabanks deleted the experiment/endpoint-builder-agent branch March 30, 2026 19:11
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.

3 participants