From 6a8744ba99b0f9b230963230e54124593c18394a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Horvat?= Date: Mon, 30 Sep 2024 16:18:26 +0200 Subject: [PATCH] Add trailing slash to the graphql URLs (#3389) --- pontoon/api/README.md | 14 +++++++------- pontoon/api/tests/test_schema.py | 16 ++++++++-------- pontoon/api/tests/test_urls.py | 16 ++++++++-------- pontoon/api/urls.py | 9 +++++---- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/pontoon/api/README.md b/pontoon/api/README.md index a6ac443306..254236d708 100644 --- a/pontoon/api/README.md +++ b/pontoon/api/README.md @@ -1,7 +1,7 @@ # GraphQL API Pontoon exposes some of its data via a public API endpoint. The API is -[GraphQL](http://graphql.org/)-based and available at `/graphql`. +[GraphQL](http://graphql.org/)-based and available at `/graphql/`. ## Production Deployments @@ -12,13 +12,13 @@ the query must be escaped. An example GET requests may look like this: ```bash -$ curl --globoff https://example.com/graphql?query={projects{name}} +$ curl --globoff "https://example.com/graphql/?query={projects{name}}" ``` An example POST requests may look like this: ```bash -$ curl -X POST -d "query={ projects { name } }" https://example.com/graphql +$ curl -X POST -d "query={ projects { name } }" https://example.com/graphql/ ``` ## Local Development @@ -33,23 +33,23 @@ a production one, returning JSON responses. The following query in the CLI will return a JSON response: ```bash -$ curl --globoff http://localhost:8000/graphql?query={projects{name}} +$ curl --globoff "http://localhost:8000/graphql/?query={projects{name}}" ``` If however a request is sent with `Accept: text/html` such as is the case when accessing the endpoint in a browser, a GUI query editor and explorer, [GraphiQL](https://github.com/graphql/graphiql), will be served:: - http://localhost:8000/graphql?query={projects{name}} + http://localhost:8000/graphql/?query={projects{name}} To preview the JSON response in the browser, pass in the `raw` query argument:: - http://localhost:8000/graphql?query={projects{name}}&raw + http://localhost:8000/graphql/?query={projects{name}}&raw ## Query IDE The [GraphiQL](https://github.com/graphql/graphiql) query IDE is available at -`http://localhost:8000/graphql` when running Pontoon locally and the URL is +`http://localhost:8000/graphql/` when running Pontoon locally and the URL is accessed with the `Accept: text/html` header, e.g. using a browser. It offers a query editor with: diff --git a/pontoon/api/tests/test_schema.py b/pontoon/api/tests/test_schema.py index b664a38177..b8403b2937 100644 --- a/pontoon/api/tests/test_schema.py +++ b/pontoon/api/tests/test_schema.py @@ -34,7 +34,7 @@ def test_projects(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") ProjectFactory.create(visibility=Project.Visibility.PRIVATE) assert response.status_code == 200 @@ -111,7 +111,7 @@ def test_project_filters( } if is_admin: client.force_login(admin) - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert response.json() == { @@ -143,7 +143,7 @@ def test_project_localizations(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert response.json() == { @@ -205,7 +205,7 @@ def test_localization_filters( if is_admin: client.force_login(admin) - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert response.json() == { @@ -246,7 +246,7 @@ def test_projects_localizations_cyclic(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert b"Cyclic queries are forbidden" in response.content @@ -268,7 +268,7 @@ def test_project_localizations_cyclic(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert b"Cyclic queries are forbidden" in response.content @@ -290,7 +290,7 @@ def test_locales_localizations_cyclic(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert b"Cyclic queries are forbidden" in response.content @@ -312,7 +312,7 @@ def test_locale_localizations_cyclic(client): }""" } - response = client.get("/graphql", body, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", body, HTTP_ACCEPT="application/json") assert response.status_code == 200 assert b"Cyclic queries are forbidden" in response.content diff --git a/pontoon/api/tests/test_urls.py b/pontoon/api/tests/test_urls.py index d931fb3d62..c4dcad2b8a 100644 --- a/pontoon/api/tests/test_urls.py +++ b/pontoon/api/tests/test_urls.py @@ -21,7 +21,7 @@ def projects_query(): def test_graphql_dev_get(settings, projects_query, client): settings.DEV = True - response = client.get("/graphql", projects_query, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", projects_query, HTTP_ACCEPT="application/json") assert response.status_code == 200 @@ -29,7 +29,7 @@ def test_graphql_dev_get(settings, projects_query, client): def test_graphql_dev_post(settings, projects_query, client): settings.DEV = True - response = client.post("/graphql", projects_query, HTTP_ACCEPT="application/json") + response = client.post("/graphql/", projects_query, HTTP_ACCEPT="application/json") assert response.status_code == 200 @@ -38,7 +38,7 @@ def test_graphql_dev_post(settings, projects_query, client): def test_graphql_prod_get(settings, projects_query, client): settings.DEV = True - response = client.get("/graphql", projects_query, HTTP_ACCEPT="application/json") + response = client.get("/graphql/", projects_query, HTTP_ACCEPT="application/json") assert response.status_code == 200 @@ -47,7 +47,7 @@ def test_graphql_prod_get(settings, projects_query, client): def test_graphql_prod_post(settings, projects_query, client): settings.DEV = False - response = client.post("/graphql", projects_query, HTTP_ACCEPT="appication/json") + response = client.post("/graphql/", projects_query, HTTP_ACCEPT="application/json") assert response.status_code == 200 @@ -55,14 +55,14 @@ def test_graphql_prod_post(settings, projects_query, client): def test_graphiql_dev_get(settings, projects_query, client): settings.DEV = True - response = client.get("/graphql", projects_query, HTTP_ACCEPT="text/html") + response = client.get("/graphql/", projects_query, HTTP_ACCEPT="text/html") assert response.status_code == 200 @pytest.mark.django_db def test_graphiql_dev_post(settings, projects_query, client): settings.DEV = True - response = client.post("/graphql", projects_query, HTTP_ACCEPT="text/html") + response = client.post("/graphql/", projects_query, HTTP_ACCEPT="text/html") assert response.status_code == 200 @@ -71,7 +71,7 @@ def test_graphiql_dev_post(settings, projects_query, client): def test_graphiql_prod_get(settings, projects_query, client): settings.DEV = False reload_urls(settings) - response = client.get("/graphql", projects_query, HTTP_ACCEPT="text/html") + response = client.get("/graphql/", projects_query, HTTP_ACCEPT="text/html") assert response.status_code == 400 @@ -80,5 +80,5 @@ def test_graphiql_prod_get(settings, projects_query, client): def test_graphiql_prod_post(projects_query, client, settings): settings.DEV = False reload_urls(settings) - response = client.post("/graphql", projects_query, HTTP_ACCEPT="text/html") + response = client.post("/graphql/", projects_query, HTTP_ACCEPT="text/html") assert response.status_code == 400 diff --git a/pontoon/api/urls.py b/pontoon/api/urls.py index bf48f67689..e4b85a57c0 100644 --- a/pontoon/api/urls.py +++ b/pontoon/api/urls.py @@ -1,15 +1,16 @@ from graphene_django.views import GraphQLView -from django.urls import path +from django.urls import re_path from pontoon.api.schema import schema from pontoon.settings import DEV urlpatterns = [ - # GraphQL endpoint. In DEV mode it serves the GraphiQL IDE if accessed with Accept: text/html - path( - "graphql", + # GraphQL endpoint. In DEV mode it serves the GraphiQL IDE if accessed with Accept: text/html. + # Explicitly support URLs with or without trailing slash in order to support curl requests. + re_path( + r"^graphql/?$", GraphQLView.as_view(schema=schema, graphiql=DEV), ), ]