Skip to content

Add support for extensions to the HTTP protocol #3461

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

Merged
merged 23 commits into from
May 17, 2025

Conversation

omarzouk
Copy link
Contributor

@omarzouk omarzouk commented Apr 19, 2024

Description

The GQL spec specifies a field called extensions as part of the request parameters spec in the HTTP protocol. We are missing support for this

Adding the field to be parsed and propagating it as part of the Info object. This is done by wrapping the entire context object in a temporary container, and then unwrapping it inside the Info context getter. A new function is also added to the Info class called input_extensions. It exposes the extensions data.

Example usage by the end-user:

@strawberry.field
def value_from_extensions(self, key: str, info: strawberry.Info) -> str:
    return info.input_extensions[key]

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

Summary by Sourcery

This pull request introduces support for the 'extensions' field in HTTP requests, allowing it to be parsed and included in the ExecutionContext. This change is accompanied by updates to the documentation and new tests to ensure proper functionality.

  • New Features:
    • Added support for the 'extensions' field in HTTP requests, allowing it to be parsed and propagated as part of the ExecutionContext.
  • Documentation:
    • Updated documentation to reflect the new support for the 'extensions' field in HTTP requests.
  • Tests:
    • Added tests to verify the correct handling and propagation of the 'extensions' field in both GET and POST HTTP requests.

@omarzouk omarzouk marked this pull request as draft April 19, 2024 17:38
@botberry
Copy link
Member

botberry commented Apr 19, 2024

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


This release adds support for input extension (To explain and document)

Here's the tweet text:

🆕 Release (next) is out! Thanks to Omar Marzouk for the PR 👏

Get it here 👉 https://strawberry.rocks/release/(next)

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @omarzouk - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Docstrings: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

Copy link

codecov bot commented Apr 19, 2024

Codecov Report

Attention: Patch coverage is 65.51724% with 20 lines in your changes missing coverage. Please review.

Project coverage is 95.01%. Comparing base (4db5a0d) to head (bacfce9).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3461      +/-   ##
==========================================
- Coverage   95.06%   95.01%   -0.06%     
==========================================
  Files         508      508              
  Lines       33018    33072      +54     
  Branches     1712     1719       +7     
==========================================
+ Hits        31388    31422      +34     
- Misses       1356     1370      +14     
- Partials      274      280       +6     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

codspeed-hq bot commented Apr 19, 2024

CodSpeed Performance Report

Merging #3461 will not alter performance

Comparing omarzouk:add_http_extensions (bacfce9) with main (4db5a0d)

Summary

✅ 21 untouched benchmarks

@strawberry-graphql strawberry-graphql deleted a comment from botberry Jun 22, 2024
Copy link
Member

@erikwrede erikwrede left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! Can you add a test to ensure the exension dict is actually correctly passed down the chain? 🙂

Additionally, we can investigate merging the http protocol extensions with subscription extensions (need to double check if we support this already in strawberry). It might also make sense to add the protocol extensions to Info

@omarzouk
Copy link
Contributor Author

omarzouk commented Jun 24, 2024

@erikwrede Hi! yea I think I need to do a fresh take on this, I think I hit a dead end with my current approach, I've been investigating how to do it, and I think we have a couple options:

1- Wrap the context field in another object that holds the extensions and the context, i.e. wrap the field before this line, then unwrap it inside the Info class. We would then introduce an input_extensions or protocol_extensions field to Info that reads the extensions from the wrapper.

2- Extend the definition of the get_context function, add a 3rd parameter called extensions. However, this would require moving the body parsing and data fetching to happen before the get_context is called, i.e. this operation would have to move above this line. It will also require some refactoring to get a similar pattern to work with subscriptions.

The benefit of doing Option 1 would be that we can add this right away to http, without having to modify other protocols, and just include a type check for the wrapper in the info.context getter. It can then be added to other protocols over time, in other PRs.

What do u think? should I go ahead and do Option 1?

@omarzouk omarzouk requested a review from erikwrede June 24, 2024 14:16
@omarzouk
Copy link
Contributor Author

hi @erikwrede, I went ahead and implemented Option 1 mentioned above, which is to wrap the context object and unwrap it in the Info getter. I also added a new test that is passing successfully. Please let me know what you think. 🙏

@omarzouk omarzouk marked this pull request as ready for review June 24, 2024 14:24
Copy link
Contributor

sourcery-ai bot commented Jun 24, 2024

Reviewer's Guide by Sourcery

This pull request adds support for the 'extensions' field in the HTTP protocol for GraphQL requests. The changes involve parsing the 'extensions' field from the request, propagating it through the ExecutionContext, and making it accessible to applications. Additionally, tests have been added to ensure the new functionality works correctly.

File-Level Changes

Files Changes
tests/http/clients/base.py
tests/http/clients/channels.py
tests/http/clients/aiohttp.py
tests/http/clients/asgi.py
tests/http/clients/chalice.py
tests/http/clients/django.py
tests/http/clients/fastapi.py
tests/http/clients/flask.py
tests/http/clients/litestar.py
tests/http/clients/quart.py
tests/http/clients/sanic.py
tests/http/clients/starlite.py
Added 'extensions' parameter to various HTTP client request functions and updated request body construction to include 'extensions'.
strawberry/http/async_base_view.py
strawberry/http/sync_base_view.py
Wrapped context in ContextWrapper to include 'extensions' in execute_operation and parse_http_body functions.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @omarzouk - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟡 Testing: 1 issue found
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

@omarzouk
Copy link
Contributor Author

pinging @patrick91 as well, since we discussed this originally in #3224

Copy link
Member

@bellini666 bellini666 left a comment

Choose a reason for hiding this comment

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

Some comments, but I'm not totally aware of this, so other @strawberry-graphql/core will be able to do a better review :)

@dataclass
class ContextWrapper:
context: Optional[Any]
extensions: Optional[Dict[str, Any]]
Copy link
Member

Choose a reason for hiding this comment

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

Same suggestion as above

Suggested change
extensions: Optional[Dict[str, Any]]
extensions: Optional[Dict[str, Any]] = None

omarzouk and others added 5 commits July 6, 2024 21:18
@DoctorJohn DoctorJohn mentioned this pull request Jul 7, 2024
11 tasks
@omarzouk
Copy link
Contributor Author

hello! sorry to keep pinging, we are really eager to use this in our APIs, do u think its possible to get some traction on it? I'm happy to help any way I can @patrick91 🙏

@patrick91
Copy link
Member

@omarzouk sure, I think I'll have time this week(end) (I'm currently travelling) 😊

And please consider sponsoring us, so we can prioritise issues better ;)

@patrick91
Copy link
Member

@omarzouk an update on this, I think I found a nice way to pass the request extensions to info, but it is quite different from this, so I might try it in another PR

@omarzouk
Copy link
Contributor Author

omarzouk commented Feb 3, 2025

And please consider sponsoring us, so we can prioritise issues better ;)

@patrick91 Hi Patrick! I talked with our management about it, it took a while to get done because github's invoice system for sponsorships is a big mess, but Soundtrack Technologies is now a 🍓 Sponsor! you guys built an awesome library, we use it for a lot of our apps, so it makes all the sense in the world to help you maintain it!

@patrick91
Copy link
Member

@omarzouk looks there's an alpha version of GraphQl-core which makes passing data around much easier, would you be ok with using their alpha?

@omarzouk
Copy link
Contributor Author

omarzouk commented Feb 6, 2025

@omarzouk looks there's an alpha version of GraphQl-core which makes passing data around much easier, would you be ok with using their alpha?

yea sure, building towards the future setup of GraphQl-core is definitely the for the best 👍

@omarzouk
Copy link
Contributor Author

omarzouk commented May 6, 2025

hi @patrick91 what is the status of this now? I see graphql-core have implemented some support for it in the alpha version. Are we working on something in Strawberry so we can make use of the new capability?

@patrick91
Copy link
Member

@omarzouk I'll take a look at this tomorrow! sorry!

@patrick91 patrick91 force-pushed the add_http_extensions branch from 2dd8a98 to 73dca8d Compare May 13, 2025 16:39
@patrick91 patrick91 force-pushed the add_http_extensions branch from 600f07e to 43e274e Compare May 13, 2025 16:43
@patrick91
Copy link
Member

/pre-release

@patrick91
Copy link
Member

@omarzouk I think we (@bellini666) got a nice implementation, would be interested in trying the pre-release? 😊

@botberry
Copy link
Member

Pre-release

👋

Releasing commit [832ad16] to PyPi as pre-release! 📦

@botberry
Copy link
Member

Pre-release

👋

Pre-release 0.269.0.dev.1747164009 [832ad16] has been released on PyPi! 🚀
You can try it by doing:

poetry add strawberry-graphql==0.269.0.dev.1747164009

@@ -113,6 +113,11 @@ def context(self) -> ContextType:
"""The context passed to the query execution."""
return self._raw_info.context

@property
def input_extensions(self) -> dict[str, Any]:
Copy link
Contributor Author

@omarzouk omarzouk May 14, 2025

Choose a reason for hiding this comment

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

@patrick91 First of all, thanks a lot for taking the time to do it! I tested it in one of our APIs, the data does go through all the way! However it is returned as a string and not as a dict, so we need to json.loads the data before we return it from this function. The spec states that the parameter is expected to be a map so parsing it should be safe to do.

Edit: I was wrong, its actually correct

Copy link
Contributor Author

@omarzouk omarzouk May 14, 2025

Choose a reason for hiding this comment

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

@patrick91 actually nvm I was wrong, I was wrongly escaping the input in my curl request, totally my bad. The implementation is actually correct! and I can confirm it works end to end 👍

Copy link
Member

Choose a reason for hiding this comment

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

@omarzouk awesome! I'll release this after we fix the unrelated issue with GlobalID :D

Copy link
Contributor Author

@omarzouk omarzouk left a comment

Choose a reason for hiding this comment

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

The pre-release works perfectly, thanks a lot guys! ❤️

@patrick91 patrick91 merged commit 0cfb7f6 into strawberry-graphql:main May 17, 2025
100 of 103 checks passed
@botberry
Copy link
Member

Thanks for contributing to Strawberry! 🎉 You've been invited to join
the Strawberry GraphQL organisation 😊

You can also request a free sticker by filling this form: https://forms.gle/dmnfQUPoY5gZbVT67

And don't forget to join our discord server: https://strawberry.rocks/discord 🔥

@mdgilene
Copy link
Contributor

Input extension information only being available from the Info object seems pretty limiting. It would make sense that someone would want to implement a custom extension and have access to the input extension information from the ExecutionContext. But currently from what I can tell this is not the case currently.

Are there any plans to make this info available to the various extension lifecycle hook methods?

@patrick91
Copy link
Member

@mdgilene can you open an issue with an example use case? We'll try to make it happen 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support the extensions Request Parameter for the HTTP protocol
7 participants