graceful package

graceful.fields module

class graceful.fields.BaseField(details, label=None, source=None, validators=None, many=False, read_only=False, write_only=False)

Base field class for subclassing.

To create new field type subclass BaseField and implement following methods:

  • from_representation(): converts representation (used in request/response body) to internal value.
  • to_representation(): converts internal value to representation that will be used in response body.
Parameters:
  • details (str) – human readable description of field (it will be used for describing resource on OPTIONS requests).

  • label (str) – human readable label of a field (it will be used for describing resource on OPTIONS requests).

    Note: it is recommended to use field names that are self-explanatory intead of relying on field labels.

  • source (str) – name of internal object key/attribute that will be passed to field on .to_representation() call. Special '*' value is allowed that will pass whole object to field when making representation. If not set then default source will be a field name used as a serializer’s attribute.

  • validators (list) – list of validator callables.

  • many (bool) – set to True if field is in fact a list of given type objects.

  • read_only (bool) – True if field is read-only and cannot be set/modified via POST, PUT, or PATCH requests.

  • write_only (bool) – True if field is write-only and cannot be retrieved via GET requests.

    New in version 0.5.0.

Example:

class BoolField(BaseField):
    def from_representation(self, data):
        if data in {'true', 'True', 'yes', '1', 'Y'}:
            return True:
        elif data in {'false', 'False', 'no', '0', 'N'}:
            return False:
        else:
            raise ValueError(
                "{data} is not valid boolean field".format(
                    data=data
                )
            )

    def to_representation(self, value):
        return ["True", "False"][value]
describe(**kwargs)

Describe this field instance for purpose of self-documentation.

Parameters:kwargs (dict) – dictionary of additional description items for extending default description
Returns:dict – dictionary of description items

Suggested way for overriding description fields or extending it with additional items is calling super class method with new/overriden fields passed as keyword arguments like following:

class DummyField(BaseField):
   def description(self, **kwargs):
       super().describe(is_dummy=True, **kwargs)
from_representation(data)

Convert representation value to internal value.

Note

This is method handler stub and should be redifined in the BaseField subclasses.

spec = None
to_representation(value)

Convert representation value to internal value.

Note

This is method handler stub and should be redifined in the BaseField subclasses.

type = None
validate(value)

Perform validation on value by running all field validators.

Single validator is a callable that accepts one positional argument and raises ValidationError when validation fails.

Error message included in exception will be included in http error response

Parameters:value – internal value to validate
Returns:None

Note

Concept of validation for fields is understood here as a process of checking if data of valid type (successfully parsed/processed by .from_representation handler) does meet some other constraints (lenght, bounds, uniqueness, etc). So this method is always called with result of .from_representation() passed as its argument.

class graceful.fields.BoolField(details, representations=None, **kwargs)

Represents boolean type of field.

By default accepts a wide range of incoming True/False representations:

  • False: ['False', 'false', 'FALSE', 'F', 'f', '0', 0, 0.0, False]
  • True: ['True', 'true', 'TRUE', 'T', 't', '1', 1, True]

By default, the outup representations of internal object’s value are Python’s False/True values that will be later serialized to form that is native for content-type of use.

This behavior can be changed using representations field argument. Note that when using representations parameter you need to make strict decision and there is no ability to accept multiple options for true/false representations. Anyway, it is reccomended approach to strictly define these values.

Parameters:representations (tuple) – two-tuple with representations for (False, True) values, that will be used instead of default values
from_representation(data)

Convert representation value to bool if it has expected form.

to_representation(value)

Convert internal boolean value to one of defined representations.

type = 'bool'
class graceful.fields.FloatField(details, max_value=None, min_value=None, **kwargs)

Represents float type of field.

Accepts both floats and strings as an incoming float number representation and always returns float as a representation of internal objects’s value that will be later serialized to form that is native for content-type of use.

This field accepts optional arguments that simply add new max and min value validation.

Parameters:
  • max_value (int) – optional max value for validation
  • min_value (int) – optional min value for validation
from_representation(data)

Convert representation value to float.

to_representation(value)

Convert internal value to float.

type = 'float'
class graceful.fields.IntField(details, max_value=None, min_value=None, **kwargs)

Represents integer type of field.

Field of this type accepts both integers and strings as an incoming integer representation and always returns int as a representation of internal objects’s value that will be later serialized to form that is native for content-type of use.

This field accepts optional arguments that simply add new max and min value validation.

Parameters:
  • max_value (int) – optional max value for validation
  • min_value (int) – optional min value for validation
from_representation(data)

Convert representation value to int.

to_representation(value)

Convert internal value to int.

type = 'int'
class graceful.fields.RawField(details, label=None, source=None, validators=None, many=False, read_only=False, write_only=False)

Represents raw field subtype.

Any value from resource object will be returned as is without any conversion and no control over serialized value type is provided. Can be used only with very simple data types like int, float, str etc. but can eventually cause problems if value provided in representation has type that is not accepted in application.

Effect of using this can differ between various content-types.

from_representation(data)

Return representation value as-is (note: content-type dependent).

to_representation(value)

Return internal value as-is (note: content-type dependent).

type = 'raw'
class graceful.fields.StringField(details, label=None, source=None, validators=None, many=False, read_only=False, write_only=False)

Represents string field subtype without any extensive validation.

from_representation(data)

Convert representation value to str.

to_representation(value)

Convert representation value to str.

type = 'string'

graceful.parameters module

class graceful.parameters.Base64EncodedParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes string parameter with value encoded using Base64 encoding.

spec = ('RFC-4648 Section 4', 'https://tools.ietf.org/html/rfc4648#section-4')
value(raw_value)

Decode param with Base64.

class graceful.parameters.BaseParam(details, label=None, required=False, default=None, many=False, validators=None)

Base parameter class for subclassing.

To create new parameter type subclass BaseParam and implement .value() method handler.

Parameters:
  • details (str) – verbose description of parameter. Should contain all information that may be important to your API user and will be used for describing resource on OPTIONS requests and .describe() call.

  • label (str) – human readable label for this parameter (it will be used for describing resource on OPTIONS requests).

    Note that it is recomended to use parameter names that are self-explanatory intead of relying on param labels.

  • required (bool) – if set to True then all GET, POST, PUT, PATCH and DELETE requests will return 400 Bad Request response if query param is not provided. Defaults to False.

  • default (str) – set default value for param if it is not provided in request as query parameter. This MUST be a raw string value that will be then parsed by .value() handler.

    If default is set and required is True it will raise ValueError as having required parameters with default value has no sense.

  • many (str) – set to True if multiple occurences of this parameter can be included in query string, as a result values for this parameter will be always included as a list in params dict. Defaults to False. Instead of list you can use any list-compatible data type by overriding the container class attribute. See: Custom containers.

    New in version 0.1.0.

  • validators (list) – list of validator callables.

    New in version 0.2.0.

Note

If many=False and client inlcudes multiple values for this parameter in query string then only one of those values will be returned, and it is undefined which one.

Example:

class BoolParam(BaseParam):
    def value(self, data):
        if data in {'true', 'True', 'yes', '1', 'Y'}:
            return True
        elif data in {'false', 'False', 'no', '0', 'N'}:
            return False
        else:
            raise ValueError(
                "{data} is not valid boolean field".format(
                    data=data
                )
            )
container

alias of list

describe(**kwargs)

Describe this parameter instance for purpose of self-documentation.

Parameters:kwargs (dict) – dictionary of additional description items for extending default description
Returns:dict – dictionary of description items

Suggested way for overriding description fields or extending it with additional items is calling super class method with new/overriden fields passed as keyword arguments like following:

class DummyParam(BaseParam):
    def description(self, **kwargs):
        super().describe(is_dummy=True, **kwargs)
spec = None
type = None
validated_value(raw_value)

Return parsed parameter value and run validation handlers.

Error message included in exception will be included in http error response

Parameters:value – raw parameter value to parse validate
Returns:None

Note

Concept of validation for params is understood here as a process of checking if data of valid type (successfully parsed/processed by .value() handler) does meet some other constraints (lenght, bounds, uniqueness, etc.). It will internally call its value() handler.

value(raw_value)

Raw value deserialization method handler.

Parameters:raw_value (str) – raw value from GET parameters
class graceful.parameters.BoolParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes parameter with value expressed as bool.

New in version 0.2.0.

Accepted string values for boolean parameters are as follows:

  • False: ['True', 'true', 'TRUE', 'T', 't', '1'}
  • True: ['False', 'false', 'FALSE', 'F', 'f', '0', '0.0']

In case raw parameter value does not match any of these strings the value() method will raise ValueError method.

type = 'bool'
value(raw_value)

Decode param as bool value.

class graceful.parameters.DecimalParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes parameter with value expressed as decimal number.

type = 'decimal'
value(raw_value)

Decode param as decimal value.

class graceful.parameters.FloatParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes parameter with value expressed as float number.

type = 'float'
value(raw_value)

Decode param as float value.

class graceful.parameters.IntParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes parameter with value expressed as integer number.

type = 'integer'
value(raw_value)

Decode param as integer value.

class graceful.parameters.StringParam(details, label=None, required=False, default=None, many=False, validators=None)

Describes parameter that will always be returned as-is (string).

Additional validation can be added to param instance using validators argument during initialization:

from graceful.parameters import StringParam
from graceful.validators import match_validator
from graceful.resources.generic import Resource

class ExampleResource(Resource):
    word = StringParam(
        'one "word" parameter',
        validators=[match_validator('\w+')],
    )
type = 'string'
value(raw_value)

Return param value as-is (str).

graceful.serializers module

class graceful.serializers.BaseSerializer

Base serializer class for describing internal object serialization.

Example:

from graceful.serializers import BaseSerializer
from graceful.fields import RawField, IntField, FloatField


class CatSerializer(BaseSerializer):
    species = RawField("non normalized cat species")
    age = IntField("cat age in years")
    height = FloatField("cat height in cm")
describe()

Describe all serialized fields.

It returns dictionary of all fields description defined for this serializer using their own describe() methods with respect to order in which they are defined as class attributes.

Returns:OrderedDict – serializer description
fields

Return dictionary of field definition objects of this serializer.

from_representation(representation)

Convert given representation dict into internal object.

Internal object is simply a dictionary of values with respect to field sources.

This does not check if all required fields exist or values are valid in terms of value validation (see: BaseField.validate()) but still requires all of passed representation values to be well formed representation (success call to field.from_representation).

In case of malformed representation it will run additional validation only to provide a full detailed exception about all that might be wrong with provided representation.

Parameters:representation (dict) – dictionary with field representation values
Raises:DeserializationError – when at least one representation field is not formed as expected by field object. Information about additional forbidden/missing/invalid fields is provided as well.
get_attribute(obj, attr)

Get attribute of given object instance.

Reason for existence of this method is the fact that ‘attribute’ can be also object’s key from if is a dict or any other kind of mapping.

Note: it will return None if attribute key does not exist

Parameters:obj (object) – internal object to retrieve data from
Returns:internal object’s key value or attribute
set_attribute(obj, attr, value)

Set value of attribute in given object instance.

Reason for existence of this method is the fact that ‘attribute’ can be also a object’s key if it is a dict or any other kind of mapping.

Parameters:
  • obj (object) – object instance to modify
  • attr (str) – attribute (or key) to change
  • value – value to set
to_representation(obj)

Convert given internal object instance into representation dict.

Representation dict may be later serialized to the content-type of choice in the resource HTTP method handler.

This loops over all fields and retrieves source keys/attributes as field values with respect to optional field sources and converts each one using field.to_representation() method.

Parameters:obj (object) – internal object that needs to be represented
Returns:dict – representation dictionary
validate(object_dict, partial=False)

Validate given internal object returned by to_representation().

Internal object is validated against missing/forbidden/invalid fields values using fields definitions defined in serializer.

Parameters:
  • object_dict (dict) – internal object dictionart to perform to validate
  • partial (bool) – if set to True then incomplete object_dict is accepter and will not raise any exceptions when one of fields is missing
Raises:

DeserializationError

class graceful.serializers.MetaSerializer

Metaclass for handling serialization with field objects.

static __new__(mcs, name, bases, namespace)

Create new class object instance and alter its namespace.

classmethod __prepare__(mcs, name, bases, **kwargs)

Prepare class namespace in a way that ensures order of attributes.

This needs to be an OrderedDict so _get_fields() method can construct fields storage that preserves the same order of fields as defined in code.

Note: this is python3 thing and support for ordering of params in descriptions will not be backported to python2 even if this framework will get python2 support.

graceful.authentication module

class graceful.authentication.Anonymous(user)

Dummy authentication middleware that authenticates every request.

It makes every every request authenticated with default value of anonymous user. This authentication middleware may be used in order to simplify custom authorization code since it will ensure that every request context will have the 'user' variable defined.

Note

This middleware will always add the default user to the request context if no other previous authentication middleware resolved. So if this middleware is used it makes no sense to:

Parameters:user – Default anonymous user object.

New in version 0.4.0.

challenge = None
identify(req, resp, resource, uri_kwargs)

Identify user with a dummy sentinel value.

only_with_storage = True
class graceful.authentication.BaseAuthenticationMiddleware(user_storage=None, name=None)

Base class for all authentication middleware classes.

Parameters:
  • user_storage (BaseUserStorage) – a storage object used to retrieve user object using their identifier lookup.
  • name (str) – custom name of the authentication middleware useful for handling custom user storage backends. Defaults to middleware class name.

New in version 0.4.0.

challenge = None
identify(req, resp, resource, uri_kwargs)

Identify the user that made the request.

Parameters:
  • req (falcon.Request) – request object
  • resp (falcon.Response) – response object
  • resource (object) – resource object matched by falcon router
  • uri_kwargs (dict) – additional keyword argument from uri template. For falcon<1.0.0 this is always None
Returns:

object – a user object (preferably a dictionary).

only_with_storage = False
process_resource(req, resp, resource, uri_kwargs=None)

Process resource after routing to it.

This is basic falcon middleware handler.

Parameters:
  • req (falcon.Request) – request object
  • resp (falcon.Response) – response object
  • resource (object) – resource object matched by falcon router
  • uri_kwargs (dict) – additional keyword argument from uri template. For falcon<1.0.0 this is always None
try_storage(identifier, req, resp, resource, uri_kwargs)

Try to find user in configured user storage object.

Parameters:identifier – User identifier.
Returns:user object.
class graceful.authentication.BaseUserStorage

Base user storage class that defines required API for user storages.

All built-in graceful authentication middleware classes expect user storage to have compatible API. Custom authentication middlewares do not need to use storages.

New in version 0.4.0.

classmethod __subclasshook__(klass)

Verify implicit class interface.

get_user(identified_with, identifier, req, resp, resource, uri_kwargs)

Get user from the storage.

Parameters:
  • identified_with (str) – instance of the authentication middleware that provided the identifier value.
  • identifier (str) – string that identifies the user (it is specific for every authentication middleware implementation).
  • req (falcon.Request) – the request object.
  • resp (falcon.Response) – the response object.
  • resource (object) – the resource object.
  • uri_kwargs (dict) – keyword arguments from the URI template.
Returns:

the deserialized user object. Preferably a dict but it is application-specific.

class graceful.authentication.Basic(user_storage=None, name=None, realm='api')

Authenticate user with Basic auth as specified by RFC 7617.

Token authentication takes form of Authorization header in the following form:

Authorization: Basic <credentials>

Whre <credentials> is base64 encoded username and password separated by single colon charactes (refer to official RFC). Usernames must not contain colon characters!

If client fails to authenticate on protected endpoint the response will include following challenge:

WWW-Authenticate: Basic realm="<realm>"

Where <realm> is the value of configured authentication realm.

This middleware must be configured with user_storage that provides access to database of client API keys and their identities. Additionally. the identifier received by user storage in the get_user() method is a decoded <username>:<password> string. If you need to apply any hash function before hitting database in your user storage handler, you should split it using followitg code:

username, _, password = identifier.partition(":")
Parameters:
  • realm (str) – name of the protected realm. This can be only alphanumeric string with spaces (see: the REALM_RE pattern).
  • user_storage (BaseUserStorage) – a storage object used to retrieve user object using their identifier lookup.
  • name (str) – custom name of the authentication middleware useful for handling custom user storage backends. Defaults to middleware class name.

New in version 0.4.0.

REALM_RE = re.compile('^[\\w ]+$')
identify(req, resp, resource, uri_kwargs)

Identify user using Authenticate header with Basic auth.

only_with_storage = True
class graceful.authentication.DummyUserStorage(user=None)

A dummy storage that never returns users or returns specified default.

This storage is part of Anonymous authentication middleware. It may also be useful for testing purposes or to disable specific authentication middlewares through app configuration.

Parameters:
  • user – User object to return. Defaults to None (will never
  • authenticate).

New in version 0.4.0.

get_user(identified_with, identifier, req, resp, resource, uri_kwargs)

Return default user object.

class graceful.authentication.IPRangeWhitelistStorage(ip_range, user)

Simple storage dedicated for XForwardedFor authentication.

This storage expects that authentication middleware return client address from its identify() method. For example usage see XForwardedFor. Because it is IP range whitelist this storage it cannot distinguish different users’ IP and always returns default user object. If you want to identify different users by their IP see KeyValueUserStorage.

Parameters:
  • ip_range – Any object that supports in operator (i.e. implements the __cointains__ method). The __contains__ method should return True if identifier falls into specified whitelist. Tip: use iptools.
  • user – Default user object to return on successful authentication.

New in version 0.4.0.

get_user(identified_with, identifier, req, resp, resource, uri_kwargs)

Return default user object.

Note

This implementation expects that identifier is an user address.

class graceful.authentication.KeyValueUserStorage(kv_store, key_prefix='users', serialization=None)

Basic user storage using any key-value store as authentication backend.

Client identities are stored as string under keys matching following template:

<key_prefix>:<identified_with>:<identifier>

Where:

  • <key_prefix> is the configured key prefix (same as the initialization argument),
  • <identified_with> is the name of authentication middleware that provided user identifier,
  • <identifier> is the identifier object that identifies the user.

Note that this key scheme will work only for middlewares that return identifiers as single string objects. Also the <identifier> part of key template is a plain text value of without any hashing algorithm applied. It may not be secure enough to store user secrets that way.

If you want to use this storage with middleware that uses more complex identifier format/objects (e.g. the Basic class) you will have to register own identifier format in the hash_identifier method. For details see the hash_identifier method docstring or the practical example section of the documentation.

Parameters:
  • kv_store – Key-value store client instance (e.g. Redis client object). The kv_store must provide at least two methods: get(key) and set(key, value). The arguments and return values of these methods must be strings.
  • key_prefix – key prefix used to store client identities.
  • serialization – serialization object/module that uses the dumps()/loads() protocol. Defaults to json.

New in version 0.4.0.

get_user(identified_with, identifier, req, resp, resource, uri_kwargs)

Get user object for given identifier.

Parameters:
  • identified_with (object) – authentication middleware used to identify the user.
  • identifier – middleware specifix user identifier (string or tuple in case of all built in authentication middleware classes).
Returns:

dict – user object stored in Redis if it exists, otherwise None

static hash_identifier(identified_with, identifier)

Create hash from identifier to be used as a part of user lookup.

This method is a singledispatch function. It allows to register new implementations for specific authentication middleware classes:

from hashlib import sha1

from graceful.authentication import KeyValueUserStorage, Basic

@KeyValueUserStorage.hash_identifier.register(Basic)
def _(identified_with, identifier):
    return ":".join((
        identifier[0],
        sha1(identifier[1].encode()).hexdigest(),
    ))
Parameters:
  • identified_with (str) – name of the authentication middleware used to identify the user.
  • identifier (str) – user identifier string
Returns:

str – hashed identifier string

register(identified_with, identifier, user)

Register new key for given client identifier.

This is only a helper method that allows to register new user objects for client identities (keys, tokens, addresses etc.).

Parameters:
  • identified_with (object) – authentication middleware used to identify the user.
  • identifier (str) – user identifier.
  • user (str) – user object to be stored in the backend.
class graceful.authentication.Token(user_storage=None, name=None)

Authenticate user using Token authentication.

Token authentication takes form of Authorization header:

Authorization: Token <token_value>

Where <token_value> is a secret string known to both client and server. Example of valid header:

Authorization: Token 6fa459ea-ee8a-3ca4-894e-db77e160355e

If client fails to authenticate on protected endpoint the response will include following challenge:

WWW-Authenticate: Token

This middleware must be configured with user_storage that provides access to database of client tokens and their identities.

New in version 0.4.0.

challenge = 'Token'
identify(req, resp, resource, uri_kwargs)

Identify user using Authenticate header with Token auth.

only_with_storage = True
class graceful.authentication.XAPIKey(user_storage=None, name=None)

Authenticate user with X-Api-Key header.

The X-Api-Key authentication takes a form of X-Api-Key header in the following form:

X-Api-Key: <key_value>

Where <key_value> is a secret string known to both client and server. Example of valid header:

X-Api-Key: 6fa459ea-ee8a-3ca4-894e-db77e160355e

If client fails to authenticate on protected endpoint the response will include following challenge:

WWW-Authenticate: X-Api-Key

Note

This method functionally equivalent to Token and is included only to ease migration of old applications that could use such authentication method in past. If you’re building new API and require only simple token-based authentication you should prefere Token middleware.

This middleware must be configured with user_storage that provides access to database of client API keys and their identities.

New in version 0.4.0.

challenge = 'X-Api-Key'
identify(req, resp, resource, uri_kwargs)

Initialize X-Api-Key authentication middleware.

only_with_storage = True
class graceful.authentication.XForwardedFor(user_storage=None, name=None, remote_address_fallback=False)

Authenticate user with X-Forwarded-For header or remote address.

Parameters:remote_address_fallback (bool) – Use fallback to REMOTE_ADDR value from WSGI environment dictionary if X-Forwarded-For header is not available. Defaults to False.

This authentication middleware is usually used with the IPRangeWhitelistStorage e.g:

from iptools import IPRangeList
import falcon

from graceful import authentication

IP_WHITELIST = IpRangeList(
    '127.0.0.1',
    # ...
)

auth_middleware = authentication.XForwardedFor(
    user_storage=authentication.IPWRangehitelistStorage(
        IP_WHITELIST, user={"username": "internal"}
    )
)

api = application = falcon.API(middleware=[auth_middleware])

Note

Using this middleware class is highly unrecommended if you are not able to ensure that contents of X-Forwarded-For header can be trusted. This requires proper reverse proxy and network configuration. It is also recommended to at least use the static IPRangeWhitelistStorage as the user storage.

New in version 0.4.0.

challenge = None
identify(req, resp, resource, uri_kwargs)

Identify client using his address.

only_with_storage = False

graceful.authorization module

graceful.authorization.authentication_required(req, resp, resource, uri_kwargs)

Ensure that user is authenticated otherwise return 401 Unauthorized.

If request fails to authenticate this authorization hook will also include list of WWW-Athenticate challenges.

Parameters:
  • req (falcon.Request) – the request object.
  • resp (falcon.Response) – the response object.
  • resource (object) – the resource object.
  • uri_kwargs (dict) – keyword arguments from the URI template.

New in version 0.4.0.

graceful.validators module

graceful.validators.min_validator(min_value)

Return validator function that ensures lower bound of a number.

Result validation function will validate the internal value of resource instance field with the value >= min_value check

Parameters:min_value – minimal value for new validator
graceful.validators.max_validator(max_value)

Return validator function that ensures upper bound of a number.

Result validation function will validate the internal value of resource instance field with the value >= min_value check.

Parameters:max_value – maximum value for new validator
graceful.validators.choices_validator(choices)

Return validator function that will check if value in choices.

Parameters:max_value (list, set, tuple) – allowed choices for new validator
graceful.validators.match_validator(expression)

Return validator function that will check if matches given expression.

Parameters:match – if string then this will be converted to regular expression using re.compile. Can be also any object that has match() method like already compiled regular regular expression or custom matching object/class.

graceful.errors module

exception graceful.errors.DeserializationError(missing=None, forbidden=None, invalid=None, failed=None)

Raised when error happened during deserialization of representation.

as_bad_request()

Translate this error to falcon’s HTTP specific error exception.

exception graceful.errors.ValidationError

Raised when validation error occured.

as_bad_request()

Translate this error to falcon’s HTTP specific error exception.

Note

Exceptions returned by this method should be used to inform about resource validation failures. In case of param validation failures the as_invalid_param() method should be used.

as_invalid_param(param_name)

Translate this error to falcon’s HTTP specific error exception.

Note

Exceptions returned by this method should be used to inform about param validation failures. In case of resource validation failures the as_bad_request() method should be used.

Parameters:param_name (str) – HTTP query string parameter name