diff --git a/CHANGELOG.md b/CHANGELOG.md index d3af665a968..693d4b255d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ count ( - server: extend support for the `min`/`max` aggregates to all comparable types in BigQuery - server: fix support for joins in aggregates nodes in BigQuery - server: fix for passing input objects in query variables to remote schemas with type name customization (#7977) +- server: fix REST endpoints with path segments not showing correctly in the OpenAPI spec - console: action/event trigger transforms are now called REST connectors - console: fix list of tables (and schemas) being unsorted when creating a new trigger event (fix #6391) - cli: migrate and seed subcommands has an option in prompt to choose and apply operation on all available databases diff --git a/server/src-lib/Hasura/Server/OpenAPI.hs b/server/src-lib/Hasura/Server/OpenAPI.hs index ad96682ff72..785719ef389 100644 --- a/server/src-lib/Hasura/Server/OpenAPI.hs +++ b/server/src-lib/Hasura/Server/OpenAPI.hs @@ -425,15 +425,11 @@ getComment d = comment getURL :: EndpointMetadata GQLQueryWithText -> Text getURL d = - "/api/rest/" - -- The url will be of the format /:/: ... always, so we can - -- split and take the first element (it should never fail) - <> fst (T.breakOn "/" (unNonEmptyText . unEndpointUrl . _ceUrl $ d)) - <> foldl - ( \b a -> b <> "/{" <> a <> "}" - ) - "" - (map T.tail $ lefts $ splitPath Left Right (_ceUrl d)) + "/api/rest/" <> T.intercalate "/" pathComponents + where + pathComponents = splitPath formatVariable id . _ceUrl $ d + formatVariable variable = "{" <> dropColonPrefix variable <> "}" + dropColonPrefix = T.drop 1 extractEndpointInfo :: Maybe RemoteSchemaIntrospection -> EndpointMethod -> EndpointMetadata GQLQueryWithText -> Declare (Definitions Schema) EndpointData extractEndpointInfo sd method d = do diff --git a/server/tests-py/queries/openapi/openapi_multiple_endpoints_with_path_segments.yaml b/server/tests-py/queries/openapi/openapi_multiple_endpoints_with_path_segments.yaml new file mode 100644 index 00000000000..46685de4690 --- /dev/null +++ b/server/tests-py/queries/openapi/openapi_multiple_endpoints_with_path_segments.yaml @@ -0,0 +1,156 @@ +- description: Try to add a GET rest endpoint with no argument with path segments in it + url: /v1/query + status: 200 + response: + message: success + query: + type: create_rest_endpoint + args: + url: simple/with/segments + name: simple_with_segments + methods: + - GET + definition: + query: + collection_name: test_collection + query_name: simple_query + +- description: Try to add a POST rest endpoint with arguments in URL and with path segments in it + url: /v1/query + status: 200 + response: + message: success + query: + type: create_rest_endpoint + args: + url: simple/with/segments/:first_name/:last_name/trailing + name: with_args_and_segments_url + methods: + - POST + definition: + query: + collection_name: test_collection + query_name: query_with_args + +- description: Call openapi json endpoint + url: /api/swagger/json + method: GET + status: 200 + query: + response: + openapi: 3.0.0 + info: + version: '' + title: Rest Endpoints + description: This OpenAPI specification is automatically generated by Hasura. + paths: + /api/rest/simple/with/segments: + get: + summary: simple_with_segments + description: "***\nThe GraphQl query for this endpoint is:\n``` graphql\n\ + query { test_table { first_name last_name } }\n```" + parameters: + - schema: + type: string + in: header + name: x-hasura-admin-secret + description: Your x-hasura-admin-secret will be used for authentication + of the API request. + responses: + '200': + content: + application/json: + schema: + properties: + test_table: + items: + type: object + properties: + first_name: + title: String + type: string + last_name: + title: String + type: string + type: array + nullable: false + description: Responses for GET /api/rest/simple/with/segments + /api/rest/simple/with/segments/{first_name}/{last_name}/trailing: + post: + summary: with_args_and_segments_url + description: "***\nThe GraphQl query for this endpoint is:\n``` graphql\n\ + query ($first_name: String!, $last_name:String!) { test_table(where: {first_name:\ + \ { _eq: $first_name } last_name: { _eq: $last_name }}) { first_name last_name\ + \ } }\n```" + parameters: + - schema: + type: string + in: header + name: x-hasura-admin-secret + description: Your x-hasura-admin-secret will be used for authentication + of the API request. + - schema: + type: string + in: path + name: first_name + description: _"first_name" is required (enter it either in parameters or request body)_ + - schema: + type: string + in: path + name: last_name + description: _"last_name" is required (enter it either in parameters or request body)_ + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + first_name: + type: string + nullable: false + last_name: + type: string + nullable: false + description: Query parameters can also be provided in the request body + as a JSON object + responses: + '200': + content: + application/json: + schema: + properties: + test_table: + items: + type: object + properties: + first_name: + title: String + type: string + last_name: + title: String + type: string + type: array + nullable: false + description: Responses for POST /api/rest/simple/with/segments/{first_name}/{last_name}/trailing + components: {} + +- description: Try to remove the endpoint + url: /v1/query + status: 200 + response: + message: success + query: + type: drop_rest_endpoint + args: + name: simple_with_segments + +- description: Try to remove the endpoint + url: /v1/query + status: 200 + response: + message: success + query: + type: drop_rest_endpoint + args: + name: with_args_and_segments_url diff --git a/server/tests-py/test_openapi.py b/server/tests-py/test_openapi.py index e49d3ad839f..bb3b8a1b98e 100644 --- a/server/tests-py/test_openapi.py +++ b/server/tests-py/test_openapi.py @@ -35,6 +35,9 @@ class TestOpenAPISpec: def test_multiple_endpoints_same_path(self, hge_ctx, transport): check_query_f(hge_ctx, self.dir() + '/openapi_multiple_endpoints_same_path.yaml', transport) + def test_multiple_endpoints_with_path_segments(self, hge_ctx, transport): + check_query_f(hge_ctx, self.dir() + '/openapi_multiple_endpoints_with_path_segments.yaml', transport) + def test_endpoint_with_complex_arg(self, hge_ctx, transport): check_query_f(hge_ctx, self.dir() + '/openapi_get_endpoint_test_complex_arg.yaml', transport)