File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -133,6 +133,14 @@ Returns a QR code image encoding the short URL. Useful for sharing links in prin
133133PNG by default; pass ` fmt=svg ` for a crisp, scalable vector you can drop into print or the web.
134134` scale ` sets the pixel size of each module (1-40, default 10) and ` border ` the quiet zone width (0-20, default 4).
135135
136+ ### Delete
137+
138+ ``` http
139+ DELETE /api/links/{code} -> 204 No Content
140+ ```
141+
142+ Removes a short link by its code or custom alias. Returns 404 if nothing matches. The code lookup is case-insensitive, same as the other endpoints.
143+
136144### Redirect
137145
138146``` http
Original file line number Diff line number Diff line change @@ -168,6 +168,14 @@ async def get_qr_code(
168168 headers = {"Cache-Control" : "public, max-age=86400" }
169169 return StreamingResponse (buf , media_type = media_type , headers = headers )
170170
171+ @router .delete ("/api/links/{code}" , status_code = 204 )
172+ async def delete_link (code : str , session : AsyncSession = Depends (get_session )):
173+ link = await find_link (session , code )
174+ if not link :
175+ raise HTTPException (status_code = 404 , detail = "Link not found" )
176+ await session .delete (link )
177+ await session .commit ()
178+
171179@router .get ("/{code}" )
172180async def redirect_to_url (code : str , session : AsyncSession = Depends (get_session )):
173181 link = await find_link (session , code )
Original file line number Diff line number Diff line change @@ -662,3 +662,31 @@ async def test_stats_page_custom_alias_lookup_case_insensitive(client):
662662 assert res .status_code == 200
663663 assert "/Gh-Link" in res .text
664664
665+
666+
667+ @pytest .mark .asyncio
668+ async def test_delete_link (client ):
669+ res = await client .post ("/api/shorten" , json = {"url" : "https://example.com" })
670+ code = res .json ()["short_code" ]
671+
672+ res = await client .delete (f"/api/links/{ code } " )
673+ assert res .status_code == 204
674+
675+ res = await client .get (f"/{ code } " , follow_redirects = False )
676+ assert res .status_code == 404
677+
678+
679+ @pytest .mark .asyncio
680+ async def test_delete_link_case_insensitive (client ):
681+ with patch ("app.routers.api.generate_short_code" , return_value = "AbC123" ):
682+ res = await client .post ("/api/shorten" , json = {"url" : "https://example.com" })
683+ assert res .status_code == 201
684+
685+ res = await client .delete ("/api/links/abc123" )
686+ assert res .status_code == 204
687+
688+
689+ @pytest .mark .asyncio
690+ async def test_delete_link_not_found (client ):
691+ res = await client .delete ("/api/links/nope" )
692+ assert res .status_code == 404
You can’t perform that action at this time.
0 commit comments