bug: `{{base_url}}` doubles the base_url — the README's own example produces a malformed URL
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Start with build_request_parts in git_api/cli.py and compare its URL handling with replay around line 427. Add a regression test alongside the URL/interpolation coverage in tests/test_cli.py for the README example, then run the relevant tests. Done means the example resolves to https://api.example.com/users without doubling the base URL.
Written by the indexing model from the issue text.
Description
Summary
resolve_url() runs before _interpolate(), so the base_url prefix is glued on before the {{base_url}} placeholder is expanded. The result is a doubled URL — and this is exactly the example the README presents as the headline demo of the tool.
Steps to reproduce
mkdir /tmp/gapi-demo && cd /tmp/gapi-demo
git init -q
git-api
Inside the REPL — this is the README's own example, verbatim from README.md:38-43:
var base_url=https://api.example.com
GET {{base_url}}/users
No network access is needed; the URL is fully constructed before the socket opens.
Actual output
README line : GET {{base_url}}/users
README claims: -> GET https://api.example.com/users
ACTUAL url : https://api.example.com/https://api.example.com/users
MATCH? : False
End-to-end through the real REPL binary against a local echo server, with base_url pointing at it:
========== REPL stdout (verbatim) ==========
🌿 Git-API REPL 0.1.0
Type 'help' for commands, 'quit' to exit.
default> Set base_url = http://127.0.0.1:35107
default> Set token = secret123
default>
→ GET http://127.0.0.1:35107/http://127.0.0.1:35107/users
← 200
{
"ok": true
}
(use 'save get-{{base_url}}-users' to save)
default>
💾 Saved to .git-api/requests/tmpl.json
default> curl \
-X \
GET \
http://127.0.0.1:35107/http://127.0.0.1:35107/users
default>
↻ GET http://127.0.0.1:35107/http://127.0.0.1:35107/users
← 200
{
"ok": true
}
default> Bye.
========== SERVER RECEIVED ==========
[
{
"method": "GET",
"path": "/http://127.0.0.1:35107/users",
"body": ""
},
{
"method": "GET",
"path": "/http://127.0.0.1:35107/users",
"body": ""
}
]
The server received the path /http://127.0.0.1:35107/users. Note the REPL prints ← 200 and the save/curl/replay round-trip all "work" — the corruption is completely silent, because a doubled path is a perfectly valid URL that a catch-all route happily answers.
Expected output
→ GET http://127.0.0.1:35107/users
matching README.md:42.
The substitution must happen first, so that resolve_url sees either a full http(s):// URL (returned as-is) or a path to join onto the base:
_interpolate first -> 'https://api.example.com/users' -> returned unchanged
Root cause
git_api/cli.py:139-143 — order of operations inside build_request_parts:
url = resolve_url(parts[1], env) # line 139: prefixes base_url, leaving "{{base_url}}/users"
...
url = _interpolate(url, env) # line 143: expands the placeholder *inside* the already-prefixed URL
resolve_url (cli.py:79-89) does not know about {{...}}, so it treats {{base_url}}/users as a relative path and produces base + "/{{base_url}}/users". _interpolate then expands the placeholder to the full base URL, giving base + "/" + base + "/users".
This affects build_request_parts only. replay (cli.py:427) does it in the correct order:
url = resolve_url(_interpolate(req["url"], env), env) # interpolate, then resolve
so replay resolves {{base_url}}/users correctly while the live path does not. That asymmetry is the clearest confirmation that the ordering in build_request_parts is the bug and not an intentional design choice.
The test suite does not catch this because no test asserts the resolved URL for a {{base_url}}-prefixed input. tests/test_interpolation.py tests _interpolate in isolation, and tests/test_cli.py:377 uses a URL where substitution and joining do not overlap.
Suggested fix
--- a/git_api/cli.py
+++ b/git_api/cli.py
@@ def build_request_parts(parts: list[str], env: dict):
- url = resolve_url(parts[1], env)
+ # Substitute before joining: resolve_url must see either a full
+ # http(s):// URL or a bare path, never an unexpanded {{base_url}}.
+ url = resolve_url(_interpolate(parts[1], env), env)
raw_body = parts[2] if len(parts) > 2 else None
body = _interpolate(raw_body, env) if raw_body is not None else None
headers = _interpolate_headers(env.get("headers", {}), env)
- url = _interpolate(url, env)
This makes the live path match the already-correct replay path and makes the README example true.
Worth adding a regression test that asserts the README example resolves to https://api.example.com/users, so the documented example stays covered.
Related
- Same function as the multi-token body truncation defect (
parts[2]only, atcli.py:140). CHANGELOG.mdrecords that{{variable}}substitution was extended to headers in 0.1.0; the ordering fix belongs with it.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- Avg merge
- 37m
- Merged PRs (30d)
- 9
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from yunaremaia/git-api
-
bug good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
yunaremaia/git-api#60 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
yunaremaia/git-api#59 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
yunaremaia/git-api#58 ·
Maintainers usually reply within 1 day
-
bug: a request name containing `-f` silently arms `--force` and overwrites an existing saved requestOpenbug
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
yunaremaia/git-api#52 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
yunaremaia/git-api#49 ·
Maintainers usually reply within 1 day
All issues in yunaremaia/git-api
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
enhancement good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
iceboundrock/AutoForge#304 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
fossasia/visdom-dev#77 ·
Maintainers usually reply within 4 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
aws-cloudformation/cfn-lint#4890 ·
Maintainers usually reply within 2 days