aiohttp icon indicating copy to clipboard operation
aiohttp copied to clipboard

Allow URLs with paths as base_url in ClientSession

Open thewhaleking opened this issue 2 years ago • 10 comments

Is your feature request related to a problem?

Many sites have an API path in the URL. For example, Jira uses {jira_url}/rest/api/2/ as the base for its API requests. The current implementation of the ClientSession only allows absolute URLs without a path. Thus, to make a number of Jira requests, you would do something like:

async with aiohttp.ClientSession(base_url="https://jira.com") as client:
    baz = await client.get("/rest/api/2/issue/ISSUE-1")
    bom = await client.get("/rest/api/2/project/ISSUE")

instead of the simpler

async with aiohttp.ClientSession(base_url="https://jira.com/rest/api/2") as client:
    baz = await client.get("/issue/ISSUE-1")
    bom = await client.get("/project/ISSUE")

This somewhat defeats the purpose of having the base_url in the first place.

Describe the solution you'd like

Allow using paths in the base_url, similar to how Requests and HTTPX do.

Describe alternatives you've considered

Just continue typing in the path or using variables with f-strings.

Related component

Client

Additional context

No response

Code of Conduct

  • [X] I agree to follow the aio-libs Code of Conduct

thewhaleking avatar Mar 03 '22 15:03 thewhaleking

+1

I was also expecting base_url to allow for any base URL, not just absolute. Moreover, I just tried using a URL object for base_url, and while the assertion doesn't trigger, it silently ignores the path part.

For example, this snippet makes a request to http://service:8080/orders/1 (wrongly) without any errors:

import asyncio
from aiohttp import ClientSession
from yarl import URL

async def test():
    base_url = URL("http://service:8080/api/v2")
    async with ClientSession(base_url=base_url) as session:
        async with session.get("/orders/1") as response:
            body = await response.text()

asyncio.run(main())

hhromic avatar Apr 02 '22 14:04 hhromic

+1

This is the default behavior of urljoin from urllib.parse when the joined part starts with a slash, otherwise the url is joined as we want it, but path that does not start with slash is restricted by design here

https://github.com/aio-libs/aiohttp/blob/cc6dc0c49f5d002485f9a3cdf9bc3127a3ac1388/aiohttp/client.py#L355-L361

I think that a removal of second assert condition makes the deal, and it does not violate the RFC as stated in base_url feature PR discussion https://github.com/aio-libs/aiohttp/pull/6129#discussion_r739634394

buzanovn avatar Jun 09 '22 10:06 buzanovn

+1 that would be really usefull

bogdan-coman-uv avatar Oct 10 '22 10:10 bogdan-coman-uv

+1

andreaevooq avatar Apr 20 '23 12:04 andreaevooq

Why is this not possible till now?

AYMENJD avatar Apr 28 '23 04:04 AYMENJD

It would appear to be to get the feature merged in a timely manner without considering the extra edge cases:

We can improve the feature support in future https://github.com/aio-libs/aiohttp/pull/6129#issuecomment-955767200

https://github.com/aio-libs/aiohttp/pull/6129#discussion_r738566850

Dreamsorcerer avatar Apr 28 '23 15:04 Dreamsorcerer

I also need base_url to include paths. In the meantime, can we document current behavior better? Do you want me to attempt an PR for the documentation?

mokko avatar Jul 28 '23 12:07 mokko

Yep, that'd be great.

Dreamsorcerer avatar Jul 28 '23 12:07 Dreamsorcerer

Thanks for taking my PR to improve the documentation.

Although perhaps obvious, let me just say: the workaround is not to use ClientSession's base_url, but to construct your urls yourself. In my case that leads to somewhat ugly code, but is simple enough to do.

mokko avatar Aug 04 '23 12:08 mokko