Skip to content

feat: add NangoConnection<I> extractor for nango-powered integration routes#3962

Open
devin-ai-integration[bot] wants to merge 5 commits intomainfrom
devin/1771044867-nango-connection-extractor
Open

feat: add NangoConnection<I> extractor for nango-powered integration routes#3962
devin-ai-integration[bot] wants to merge 5 commits intomainfrom
devin/1771044867-nango-connection-extractor

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 14, 2026

feat: add NangoConnection<I> extractor for nango-powered integration routes

Summary

Introduces a generic NangoConnection<I> axum extractor that resolves a user's Nango connection_id from a Supabase nango_connections table, removing the need for clients to pass connection_id in every request body. The extractor uses marker types (Option B from design discussion) for type-safe integration identification.

Key pieces:

  • Supabase migration (nango_connections table) — stores user_id ↔ connection_id per integration, populated by webhook
  • OwnedNangoProxy + OwnedNangoHttpClient in crates/nango — owned variants to solve lifetime issues in extractors
  • NangoIntegrationId trait + GoogleCalendar/GoogleDrive marker types in crates/api-nango
  • NangoConnection<I> extractor — reads AuthContext for user_id, queries Supabase PostgREST for connection_id, builds ready-to-use HTTP client
  • Webhook handler extended to upsert/delete rows on Nango auth events
  • api-calendar and api-storage refactoredconnection_id removed from all request bodies, duplicated config.rs/state.rs deleted

Before → After (handler example):

// Before: 3-line preamble + connection_id in body
pub async fn list_calendars(
    State(state): State<AppState>,
    Json(payload): Json<ListCalendarsRequest>, // had connection_id field
) -> Result<...> {
    let proxy = state.nango.integration("google-calendar").connection(&payload.connection_id);
    let http = NangoHttpClient::new(proxy);
    let client = GoogleCalendarClient::new(http);

// After: extractor does it all
pub async fn list_calendars(
    nango: NangoConnection<GoogleCalendar>,
) -> Result<...> {
    let client = GoogleCalendarClient::new(nango.into_http());

Review & Testing Checklist for Human

  • Breaking API change: connection_id is removed from all calendar/storage request bodies. Verify frontend/client code is updated accordingly or this is intentional for a new flow.
  • Supabase migration: Review 20250214000000_create_nango_connections.sql — RLS policies, FK constraint, unique index on (user_id, integration_id).
  • Webhook upsert: Verify end_user.end_user_id from Nango webhook matches Supabase auth.users.id format (UUID string).
  • Extension layer ordering: Confirm NangoConnectionState extension is available to calendar routes (added after .nest("/calendar", ...) but before auth middleware).
  • Test end-to-end: Connect a Google Calendar integration via Nango → verify webhook populates nango_connections → call /calendar/calendars with just auth token → verify it resolves connection and returns data.

Notes

  • supabase_service_role_key env var is optional — webhooks will log errors but return ok if not set
  • list_calendars is now a POST with no request body (just the extractor)
  • The OwnedNangoProxy duplicates method signatures from NangoProxy — shared header logic extracted to apply_proxy_headers

Link to Devin run: https://app.devin.ai/sessions/95a166d9b051412fb31184ba37b3b80f
Requested by: @yujonglee


Open with Devin

…routes

- Add nango_connections supabase migration table
- Add OwnedNangoProxy + OwnedNangoHttpClient to nango crate
- Add NangoIntegrationId trait with GoogleCalendar/GoogleDrive marker types
- Add NangoConnection<I> axum extractor (resolves connection_id from DB)
- Extend webhook handler to upsert/delete nango_connections
- Refactor api-calendar to use NangoConnection<GoogleCalendar>
- Refactor api-storage to use NangoConnection<GoogleDrive>
- Remove connection_id from request bodies (server-side lookup)
- Remove duplicated config.rs/state.rs from api-calendar and api-storage

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 57d2c4d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6990149032842200083c6a70

@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit 57d2c4d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69901490441c920008440eea

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Open in Devin Review

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

devin-ai-integration bot and others added 3 commits February 14, 2026 05:57
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
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.

1 participant