Cornices/cornice

Cornice API with optional path parameter

Opened this issue · 1 comments

Hi,

I'm trying to build a Cornice service which should accept an optional path parameter, so I followed Pyramid guidelines and set path as "/api/rest/doc/{doc_id}{version:.*}".

But then:

  • when defined, request.matchdict['version'] is set to "/1" (for example), instead of just "1", as described in Pyramid documentation;
  • when using Swagger extension, I only see a single parameter called "doc_id}{version"!

So is this syntax supported by Cornice, or should I handle it in another way?

Best regards,

Thierry

Hi Thierry,

To be honest with you I never used these optional path parameters.
Based on your feedback, it looks like Cornice does not support them well.
It doesn't mean it couldn't, if you want to track this down, the view registering code is this:

# 1. register route
route_args = {}
if hasattr(service, 'factory'):
route_args['factory'] = service.factory
routes = config.get_predlist('route')
for predicate in routes.sorter.names:
# Do not let the custom predicates handle validation of Header Accept,
# which will pass it through to pyramid. It is handled by
# _fallback_view(), because it allows callable.
if predicate == 'accept':
continue
if hasattr(service, predicate):
route_args[predicate] = getattr(service, predicate)
# register route when not using exiting pyramid routes
if not existing_route:
config.add_route(route_name, service.path, **route_args)
# 2. register view(s)
for method, view, args in service.definitions:
args = copy.copy(args) # make a copy of the dict to not modify it
# Deepcopy only the params we're possibly passing on to pyramid
# (Some of those in cornice_parameters, e.g. ``schema``, may contain
# unpickleable values.)
for item in args:
if item not in cornice_parameters:
args[item] = copy.deepcopy(args[item])
args['request_method'] = method
if service.cors_enabled:
args['validators'].insert(0, cors_validator)
decorated_view = decorate_view(view, dict(args), method, route_args)
for item in cornice_parameters:
if item in args:
del args[item]
# filter predicates defined on Resource
route_predicates = config.get_predlist('route').sorter.names
view_predicates = config.get_predlist('view').sorter.names
for pred in set(route_predicates).difference(view_predicates):
if pred in args:
args.pop(pred)
# pop and compute predicates which get passed through to Pyramid 1:1
predicate_definitions = _pop_complex_predicates(args)
if predicate_definitions:
empty_contenttype = [({'kind': 'content_type', 'value': ''},)]
for predicate_list in predicate_definitions + empty_contenttype:
args = dict(args) # make a copy of the dict to not modify it
# prepare view args by evaluating complex predicates
_mungle_view_args(args, predicate_list)
# We register the same view multiple times with different
# accept / content_type / custom_predicates arguments
config.add_view(view=decorated_view, route_name=route_name,
**args)
else:
# it is a simple view, we don't need to loop on the definitions
# and just add it one time.
config.add_view(view=decorated_view, route_name=route_name,
**args)

Alternatively, you can register several routes in the right order to obtain the same result