Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions cloud_registry/api/20201108.e0358db.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,32 @@ paths:
operationId: getServices
tags:
- services
parameters:
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
example: 1
- name: page_size
in: query
required: false
schema:
type: integer
minimum: 1
example: 10
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
responses:
'200':
description: 'List of services'
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ExternalService'
oneOf:
- type: array
items:
$ref: '#/components/schemas/ExternalService'
- $ref: '#/components/schemas/PaginatedExternalService'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
Expand Down Expand Up @@ -80,9 +97,11 @@ paths:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ServiceType'
oneOf:
- type: array
items:
$ref: '#/components/schemas/ServiceType'
- $ref: '#/components/schemas/PaginatedServiceType'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
Expand Down Expand Up @@ -198,3 +217,46 @@ components:
required:
- status
- title
PaginationMetadata:
description: 'Pagination Metadata'
type: object
required:
- page
- page_size
- total_count
- total_pages
properties:
page:
type: integer
description: "Current page of the response"
example: 1
page_size:
type: integer
description: "Number of entries in a page"
example: 10
total_count:
type: integer
description: "Total number of entries for the query"
example: 30
total_pages:
type: integer
description: "Total number of entries for the query"
example: 30
PaginatedExternalService:
type: object
properties:
results:
type: array
items:
$ref: '#/components/schemas/ExternalService'
pagination:
$ref: '#/components/schemas/PaginationMetadata'
PaginatedServiceType:
type: object
properties:
results:
type: array
items:
$ref: '#/components/schemas/ServiceType'
pagination:
$ref: '#/components/schemas/PaginationMetadata'
104 changes: 91 additions & 13 deletions cloud_registry/ga4gh/registry/server.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,72 @@
"""Controllers for service endpoints."""

import logging
from typing import Dict, List, Tuple
from math import ceil
from typing import Dict, List, Tuple, Union

from cloud_registry.exceptions import BadRequest, NotFound
from cloud_registry.ga4gh.registry.service import RegisterService
from cloud_registry.ga4gh.registry.service_info import RegisterServiceInfo
from flask import current_app, request
from foca.utils.logging import log_traffic
from cloud_registry.exceptions import NotFound, BadRequest
from cloud_registry.ga4gh.registry.service_info import RegisterServiceInfo
from cloud_registry.ga4gh.registry.service import RegisterService

logger = logging.getLogger(__name__)


# GET /services
@log_traffic
def getServices(**kwargs) -> List:
def getServices(**kwargs) -> Union[List, Dict]:
"""List all services.

Returns:
List of services.
List of services or Paginated list of services.
"""

# Get pagination data
page = request.args.get("page", type=int)
page_size = request.args.get("page_size", type=int)

foca_conf = current_app.config.foca # type: ignore[attr-defined]
db_collection_service = (
foca_conf.db.dbs["serviceStore"].collections["services"].client
)
records = db_collection_service.find(
filter={},
projection={"_id": False},

# return list if no pagination query found
if page is None and page_size is None:
records = db_collection_service.find(
filter={},
projection={"_id": False},
)
return list(records)

# Return paginated response
page = page or 1
page_size = page_size or 10
total_count = db_collection_service.count_documents({})
total_pages = ceil(total_count / page_size)

if page < 1 or (total_count > 0 and page > total_pages):
raise BadRequest

skip_items = (page - 1) * page_size
records = (
db_collection_service.find(
filter={},
projection={"_id": False},
)
.skip(skip_items)
.limit(page_size)
)
return list(records)

return {
"results": list(records),
"pagination": {
"page": page,
"page_size": page_size,
"total_count": total_count,
"total_pages": total_pages,
},
}


# GET /services/{serviceId}
Expand All @@ -55,17 +93,57 @@ def getServiceById(serviceId: str, **kwargs) -> Dict:

# GET /services/types
@log_traffic
def getServiceTypes(**kwargs) -> List:
def getServiceTypes(**kwargs) -> Union[List, Dict]:
"""List types of services.

Returns:
List of distinct service types.
"""
services = getServices.__wrapped__()

# Get pagination data
page = request.args.get("page", type=int)
page_size = request.args.get("page_size", type=int)

# get all the services
foca_conf = current_app.config.foca # type: ignore[attr-defined]
db_collection_service = (
foca_conf.db.dbs["serviceStore"].collections["services"].client
)
services = list(
db_collection_service.find(
filter={},
projection={"_id": False},
)
)
types = [s["type"] for s in services]
uniq_types = [dict(t) for t in {tuple(sorted(d.items())) for d in types}]

return uniq_types
# return list if no pagination query found
if page is None and page_size is None:
return uniq_types

# return paginated response
page = page or 1
page_size = page_size or 10
total_count = len(uniq_types)
total_pages = ceil(total_count / page_size)

if page < 1 or (total_count > 0 and page > total_pages):
raise BadRequest

skip_items = (page - 1) * page_size
end = skip_items + page_size
paginated_types = uniq_types[skip_items:end]

return {
"results": paginated_types,
"pagination": {
"page": page,
"page_size": page_size,
"total_count": total_count,
"total_pages": total_pages,
},
}


# GET /service-info
Expand Down
14 changes: 11 additions & 3 deletions tests/ga4gh/registry/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@ def test_getServices():
data.append(mock_resp)

# check whether getServices returns the same list
with app.app_context():
with app.test_request_context("services"):
res = getServices.__wrapped__()
# For paginated response extract the data present in result field
if "results" in res:
res = res["results"]
assert res == data


Expand Down Expand Up @@ -111,8 +114,10 @@ def test_getServiceTypes_duplicates():
"services"
].client.insert_one(mock_resp)

with app.app_context():
with app.test_request_context("services"):
res = getServiceTypes.__wrapped__()
if "results" in res:
res = res["results"]
# All written services have same type, we expect list of length 1
assert res == [MOCK_TYPE]

Expand All @@ -139,8 +144,11 @@ def test_getServiceTypes_distinct():
"services"
].client.insert_one(mock_resp)

with app.app_context():
with app.test_request_context("services"):
res = getServiceTypes.__wrapped__()
# For paginated response extract the data present in result field
if "results" in res:
res = res["results"]
# All written services have distinct types, we expect a list of the
# same length as there are entries in the database collection
assert len(res) == len(services)
Expand Down
Loading