-
Notifications
You must be signed in to change notification settings - Fork 185
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
Setting cookies in AIOHttpTransport doesn't work #197
Comments
What does the authenticate method returns? What is the type of I made two tests to test the cookies for RequestsHTTPTransport and the AIOHTTPTransport and both seems to works the same way with a simple dict: @pytest.mark.asyncio
async def test_aiohttp_cookies(event_loop, aiohttp_server):
from aiohttp import web
from gql.transport.aiohttp import AIOHTTPTransport
async def handler(request):
assert "COOKIE" in request.headers
assert "cookie1=val1" == request.headers["COOKIE"]
return web.Response(text=query1_server_answer, content_type="application/json")
app = web.Application()
app.router.add_route("POST", "/", handler)
server = await aiohttp_server(app)
url = server.make_url("/")
sample_transport = AIOHTTPTransport(url=url, cookies={"cookie1": "val1"})
async with Client(transport=sample_transport,) as session:
query = gql(query1_str)
# Execute query asynchronously
result = await session.execute(query)
continents = result["continents"]
africa = continents[0]
assert africa["code"] == "AF"
@pytest.mark.aiohttp
@pytest.mark.asyncio
async def test_requests_cookies(event_loop, aiohttp_server, run_sync_test):
from aiohttp import web
from gql.transport.requests import RequestsHTTPTransport
async def handler(request):
assert "COOKIE" in request.headers
assert "cookie1=val1" == request.headers["COOKIE"]
return web.Response(text=query1_server_answer, content_type="application/json")
app = web.Application()
app.router.add_route("POST", "/", handler)
server = await aiohttp_server(app)
url = server.make_url("/")
def test_code():
sample_transport = RequestsHTTPTransport(url=url, cookies={"cookie1": "val1"})
with Client(transport=sample_transport,) as session:
query = gql(query1_str)
# Execute query synchronously
result = session.execute(query)
continents = result["continents"]
africa = continents[0]
assert africa["code"] == "AF"
await run_sync_test(event_loop, server, test_code) But the behavior may change if the type of the cookies param is not a dict.
|
I can also confirm this behavior. gql version 3.0.0a5 I have method, that return me cookie dict. RequestsHTTPTransport (works fine)import requests
from gql import Client, gql
from gql.transport.requests import RequestsHTTPTransport
class SomeApi:
def __init__(self, graphql_url="https://devroooms.ru/admin-api"):
self.graphql_url = graphql_url
self.transport = RequestsHTTPTransport(url=graphql_url)
self.client = Client(transport=self.transport, fetch_schema_from_transport=True)
self.cookies = self.cookie_login()
self.transport.cookies = self.cookies
def cookie_login(self):
query = """
mutation AttemptLogin(
$username: String!
$password: String!
$rememberMe: Boolean!
) {
login(username: $username, password: $password, rememberMe: $rememberMe) {
...CurrentUser
...ErrorResult
__typename
}
}fragment CurrentUser on CurrentUser {
id
identifier
channels {
id
code
token
permissions
__typename
}
__typename
}
fragment ErrorResult on ErrorResult {
errorCode
message
__typename
}
"""
variable_values = {'username': '[email protected]', 'password': '[email protected]', 'rememberMe': True}
s = requests.session()
p = s.post(self.graphql_url, json={"query": query, "variables": variable_values})
if p.status_code == 200:
return s.cookies.get_dict()
else:
raise Exception
return None
def get_all_facets(self):
query = gql("""
query Query {
facets {
items {
isPrivate
id
createdAt
updatedAt
languageCode
name
code
values {
id
createdAt
updatedAt
languageCode
name
code
customFields
}
customFields
}
totalItems
}
}
""")
result = self.client.execute(query, variable_values={})
if result:
if result.get('facets'):
if result['facets'].get('items'):
return result['facets']['items']
return None
if __name__ == "__main__":
api = SomeApi()
api.get_all_facets() AIOHTTPTransportIf i change |
Cookies are working fine on AIOHTTPTransport as can be seen in the tests above. I suspect there are some other shenanigans here with maybe a redirect from the backend which works with requests but not with aiohttp. Could you reproduce your problem in a test which fails using aiohttp and succeeds with requests ? Or at least provide a backend which can be tested publicly ? |
And tried plain aiohttp, works fine import asyncio
import aiohttp
import json
async def main():
graphql_url = "https://devroooms.ru/admin-api"
session = aiohttp.ClientSession()
variable_values = {'username': '[email protected]', 'password': '[email protected]', 'rememberMe': True}
query = """
mutation AttemptLogin(
$username: String!
$password: String!
$rememberMe: Boolean!
) {
login(username: $username, password: $password, rememberMe: $rememberMe) {
...CurrentUser
...ErrorResult
__typename
}
}fragment CurrentUser on CurrentUser {
id
identifier
channels {
id
code
token
permissions
__typename
}
__typename
}
fragment ErrorResult on ErrorResult {
errorCode
message
__typename
}
"""
async with session.post(graphql_url, data={"query": query, "variables": json.dumps(variable_values)}) as resp:
print(await resp.text())
query = """
query Query {
facets {
items {
isPrivate
id
createdAt
updatedAt
languageCode
name
code
values {
id
createdAt
updatedAt
languageCode
name
code
customFields
}
customFields
}
totalItems
}
}
"""
async with session.post(graphql_url, data={"query": query}) as resp:
print(await resp.text())
await session.close()
loop = asyncio.get_event_loop()
loop.run_until_complete(main()) |
I don't see any cookies in your previous message ?? |
Updated my comments with live example with login and pass to test.
Yes, because aiohttp.ClientSession stores cookies from first response to second request. |
I understand your problem. This should work: import asyncio
import aiohttp
from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
class SomeApi:
def __init__(self, graphql_url="https://devroooms.ru/admin-api"):
self.graphql_url = graphql_url
jar = aiohttp.CookieJar()
self.transport = AIOHTTPTransport(url=graphql_url, client_session_args={'cookie_jar': jar})
self.client = Client(transport=self.transport, fetch_schema_from_transport=True)
async def cookie_login(self):
query = """
mutation AttemptLogin(
$username: String!
$password: String!
$rememberMe: Boolean!
) {
login(username: $username, password: $password, rememberMe: $rememberMe) {
...CurrentUser
...ErrorResult
__typename
}
}fragment CurrentUser on CurrentUser {
id
identifier
channels {
id
code
token
permissions
__typename
}
__typename
}
fragment ErrorResult on ErrorResult {
errorCode
message
__typename
}
"""
variable_values = {'username': '[email protected]', 'password': '[email protected]', 'rememberMe': True}
async with self.client as session:
answer = await session.execute(gql(query), variable_values=variable_values)
async def get_all_facets(self):
query = gql("""
query Query {
facets {
items {
isPrivate
id
createdAt
updatedAt
languageCode
name
code
values {
id
createdAt
updatedAt
languageCode
name
code
customFields
}
customFields
}
totalItems
}
}
""")
async with self.client as session:
result = await session.execute(query, variable_values={})
if result:
if result.get('facets'):
if result['facets'].get('items'):
return result['facets']['items']
return None
async def main():
api = SomeApi()
await api.cookie_login()
print ("login done")
answer = await api.get_all_facets()
print (f"result = {answer}")
asyncio.run(main()) |
Ok, i can reproduce this error in clean aiohttp import asyncio
import json
import aiohttp
async def main():
graphql_url = "https://devroooms.ru/admin-api"
session = aiohttp.ClientSession()
variable_values = {'username': '[email protected]', 'password': '[email protected]', 'rememberMe': True}
query = """
mutation AttemptLogin(
$username: String!
$password: String!
$rememberMe: Boolean!
) {
login(username: $username, password: $password, rememberMe: $rememberMe) {
...CurrentUser
...ErrorResult
__typename
}
}fragment CurrentUser on CurrentUser {
id
identifier
channels {
id
code
token
permissions
__typename
}
__typename
}
fragment ErrorResult on ErrorResult {
errorCode
message
__typename
}
"""
cookies = None
async with session.post(graphql_url, data={"query": query, "variables": json.dumps(variable_values)}) as resp:
await resp.json()
cookies = {key: value.value for key,value in resp.cookies.items()}
# print(cookies)
query = """
query Query {
facets {
items {
isPrivate
id
createdAt
updatedAt
languageCode
name
code
values {
id
createdAt
updatedAt
languageCode
name
code
customFields
}
customFields
}
totalItems
}
}
"""
async with session.post(graphql_url, data={"query": query},cookies=cookies) as resp:
print(await resp.json())
await session.close()
loop = asyncio.get_event_loop()
loop.run_until_complete(main()) |
@Izayda did you see my comment about setting a cookie jar ? |
Sorry, posted previous message without page reload. Thank you very much, you save my day,, thats works perfect! As i can see, there are some unexpected features in aiohttp with SimpleCookie, because sometimes cookies are enclosed with quotes e.t.c. |
I added some documentation about this in PR #202 |
I'm trying to set cookies in the transport to execute a query.
This works when I use
RequestsHTTPTransport
but not when I useAIOHTTPTransport
.The cookie needs to be present in the POST request. In case it's not present, the client gets redirected to the login page.
So if I'm using
requests
library directly, it should look like this:This works:
This redirects me to the login page.
I need to send the same cookies for uploading a file via graphQL which is why I need to use
AIOHttpTransport
. How do I send cookies the same way as in requests?Note: Tried sending via
extra_args
but that didn't work.The text was updated successfully, but these errors were encountered: