-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
strict_slashes is not respected from the application level #1591
Comments
I'm working on a new router idea that would, among other things, address this. So unless anyone else wants to address this separately, I'll have a fix for this in my proposed router. |
Cool, expecting your awesome work. |
@chenjr0719.... the pressure is on 😱 |
@ahopkins Oops, Please don't feel any pressure. If there are any help I can provide, please let me know. 😉 |
@chenjr0719 ;-) Was just joking. When I am done with the POC for it (probably not till next week at the earliest), I will definitely be looking for as much feedback and thoughts as possible since it will potentially be a big change (I am trying to make sure there will not be any API changes though). |
@chenjr0719 @ahopkins I think we might have to think a bit more on this specific issue. I managed to fix this with minor code changes. But this can be a breaking change in some cases. app = Sanic()
@app.get("/test", strict_slashes=True)
def test(request):
return text("OK")
assert app.test_client.get("/test")[1].status == 200 This was a valid behavior previously. But considering that there is a Also, what order do we take into account while overriding the app = Sanic(strict_slashes=True)
@app.get("/test")
def test(request):
return text("Test")
bp = Blueprint("bp")
@bp.get("/one", strict_slashes=False)
def one(request):
return text("one")
@bp.get("/second")
def second(request):
return text("second")
app.blueprint(bp)
print(app.router.route_all)
bp2 = Blueprint("bp2", strict_slashes=False)
@bp2.get("/third")
def third(request):
return text("third") What is the expected behavior in the above case? |
@harshanarayana I agree, which is sort of why I am not sure we tackle it separate from any other router changes we want to make. I think it would be best to make them all at once. |
@ahopkins Works for me. However, I just opened a new PR with WIP tag to address this + the other dependency issue. Take a look when you can and let me know your feedback. It's pending few documentation changes |
What I think is like this hierarchy structure.
So, in the Python world, it would be: # route
if route.strict_slashes is None:
route.strict_slashes = app.strict_slashes
# blueprint route
if bp_route.strict_slashes is None:
if bp.strict_slashes is None:
bp_route.strict_slashes = app.strict_slashes
else:
bp_route.strict_slashes = bp.strict_slashes
Now, back to your cases: from sanic import Sanic, Blueprint
from sanic.response import text
app = Sanic(strict_slashes=True)
@app.get("/test")
def test(request):
return text("Test")
# this should follow app level
assert app.test_client.get("/test")[1].status == 200
assert app.test_client.get("/test/")[1].status == 404
bp = Blueprint("bp")
@bp.get("/one", strict_slashes=False)
def one(request):
return text("one")
# this should follow bp route level
assert app.test_client.get("/one")[1].status == 200
assert app.test_client.get("/one/")[1].status == 200
@bp.get("/second")
def second(request):
return text("second")
# this should follow bp level, but the bp level is None, so follow app level
assert app.test_client.get("/second")[1].status == 200
assert app.test_client.get("/second/")[1].status == 404
app.blueprint(bp)
bp2 = Blueprint("bp2", strict_slashes=False)
@bp2.get("/third")
def third(request):
return text("third")
# this should follow bp level
assert app.test_client.get("/third")[1].status == 200
assert app.test_client.get("/third/")[1].status == 404 What do you think? |
@chenjr0719 Let me get back to you on this by EOD today. I am caught in the middle of a training session and haven't been able to look at it. |
@chenjr0719 That looks awesome. I agree with the results of each. Without having the test cases in front of me, there are a few permutations that are still not accounted for in your layout. We should make sure to test them all for consistency. |
In most of the places, the default argument is None but we override them to route level
|___ Blueprint level
|__ App Level When deciding the behavior for the def _check_if_strict_slash_should_be_enforced(slash_options):
for op_type in ["route", "bp", "app"]:
if slash_options.get(op_type) is not None:
return slash_options.get(op_type)
else:
return False Case 1app = Sanic(strict_slashes=True)
@app.get("/test")
def test(request):
return text("Test")
assert app.test_client.get("/test")[1].status == 200 # I think this behavior should be 404
assert app.test_client.get("/test/")[1].status == 404 # I think this behavior should be 200 In above, I think the Case 2app = Sanic(strict_slashes=True)
bp = Blueprint("bp")
@bp.get("/one", strict_slashes=False)
def one(request):
return text("one")
# this should follow bp route level
assert app.test_client.get("/one")[1].status == 200
assert app.test_client.get("/one/")[1].status == 200 Agree on this. The Case 3app = Sanic(strict_slashes=True)
bp2 = Blueprint("bp2", strict_slashes=False)
@bp2.get("/third")
def third(request):
return text("third")
app.blueprint(bp2)
# this should follow bp level
assert app.test_client.get("/third")[1].status == 200
assert app.test_client.get("/third/")[1].status == 404 # I think this should return 200 as well. In above case the General Items
|
Totally agree both.
I don't think this is When the app = Sanic(strict_slashes=False)
@app.get("/test")
def test(request):
return text("Test")
assert app.test_client.get("/test")[1].status == 200
assert app.test_client.get("/test/")[1].status == 200 When the app = Sanic(strict_slashes=True)
@app.get("/test")
def test(request):
return text("Test")
assert app.test_client.get("/test")[1].status == 200
assert app.test_client.get("/test/")[1].status == 404 In the other hand, when the app = Sanic(strict_slashes=True)
@app.get("/test/")
def test(request):
return text("Test")
assert app.test_client.get("/test")[1].status == 404
assert app.test_client.get("/test/")[1].status == 200 I like your idea about when I suggest to separate current discussion to two parts, one is about the override mechanism, another is how
|
Yes, it would be a change in behavior. Which leads to hesitancy and reluctance to make a change. However, it also seems a bit counter intuitive.Besides the consistency aspect, if there is to be a change in behavior, we should do a survey of other frameworks. Being intuitive is also important. |
@chenjr0719 @ahopkins Agreed. I am changing the original PR to only include the changes required for addressing the As for the change of default behavior implemented currently, let me move that discussion to the thread in community and see what comes out of it. |
Closing this. Any further discussion, let's move to forums. |
Describe the bug
This issue is porting from sanic-org/sanic-openapi#102. When using
Sanic(strict_slashes=True)
, it won't be apply to any blueprint.Code snippet
Output:
Expected behavior
The
strict_slashes
in app level should be respected until user override it by settingBlueprint(..., strict_slashes=True)
or in blueprint's route level.Environment (please complete the following information):
Additional context
None
The text was updated successfully, but these errors were encountered: