Ideas

Note

Remember that config is in Python, resources are collected by Python, so when you need to define something more than once, just use for loop.

Config

Config file is python file. That is passed to CodernityREST by setting CFG environment variable. Config is then collected and available via crest_cfg python module.

It is strongly recommended to import it as it is, and to get variables in following way:

import crest_cfg as cfg

cfg.get("SETTING", "value_when_not_set")

The get method behaves like stdlib python dict.get, so setting no default value will raise exception when setting is not defined.

Note

Normal python crest_cfg.SETTING will also work, but it’s not recommended.

Local / test config

try:
    from local_config import *  # NOQA
except ImportError:
    pass


# add test_config.py file to override above settings

try:
    from test_config import *  # NOQA
except ImportError:
    pass

It will allow you to have local specific config.

Overriding via env variables

You can override any setting by setting environment variable prefixed with CREST_. So if you want to setup environment = 'development' you can set CREST_environment="development".

Values for env variables should be json encoded. Or you can give it a prefix for simple types like CREST_environment=str:development.

Resource Router

It’s used to define what python function should be called on given PATH and what METHOD (regex works too).

You should define as many ResourceRouters as you wish, finally all are compacted/reduced into one router like thing just before CodernityREST is fully functioning. For performance it doesn’t matter if you have one ResourceRouter with 100 methods, or 100 ResourceRouters with one method.

r_sys = ResourceRouter('/', groups=('sys',))
r_sys.add_str('GET', '/kill_me', stop_server)
r = ResourceRouter('/')
r.add_str('GET', '/ping2', ping)

Use ResourceRouter as a container for your functions/methods with similar properties.

Exception maps

That’s one of core features in CodernityREST. By defining ExceptionMap you map a python exception to HTTP response code. It will work with any exception you want. No more problems with 3rd party exceptions and 500 Response codes.

They are evaluated from current PATH to / unless you specify single=True. When inherit_msg is set, it means that original exception message should be used.

ex_map = ExceptionMap()
ex_map.add(CustomException, 409, 'custom exception')
ex_map.add(CustomExceptionWithMsg, 409, inherit_msg=True)

r_exc.set_ex_map(ex_map)

Exceptions

To make coding and debugging easier in addition to Exception maps and Req dumper CodernityREST adds X-Error-Id header to failing responses with unique error identifier so you can refer to it later.

**opts

As you have probably seen, both ResourceRouter and single route accept **opts as arguments.

Everything you pass there will be available via req.opts inside your method. They are passed as they are, no copy or other modifications are made (except special ones)

What’s important, opts given on single route are merged with those from ResourceRouter.

Use cases

  • database connections (can be ResourceRouter specific or even single route). No problem at all with multiple databases, database connections or even engines.
  • in fact any object that you need inside your function.

Note

Do not miss Special opts

Special opts

There are some special opts, they are treated separately, and they are removed from final opts: - validator, it will validate request data / arguments with given validator. Error response is returned automatically. When validator passes, the flow continues. - dec, it decorates your method by given functions.

Both dec and validator can have priority. Wrapping starts from lowest one to highest one, so the highest priority will be called at first when calling this method.

r.add_str('GET', '/dec', decorated, dec=((9, dec_2), (8, dec_1)))
r_prios.add_str('GET', '/y', techo, validator=(3, DecOrders()),
                dec=((4, techo_dec1), (2, techo_dec2)))

Validator by default is nothing more or less than colander object. In fact it’s trivial to implement other validation method.

Use cases

  • Authorization (basic/digest, database)
  • Preconditions check (is the function/method valid in given time)
  • Validation (yes, validation is using this mechanism)
  • Customization, parameters modification
  • Anything you wish (almost)

Remember that with priorities you can first authorize, then validate, and finally check some precondition. Or... any other order of those 3 given functions.

Groups

Sometimes you might need to enable / disable some methods or resources without code modifications.

For that CodernityREST has groups. Any ResourceRouter can be in many groups, then in config file you can define route_groups, every resource with non matching group will be ignored (not registered).

r_sys = ResourceRouter('/', groups=('sys',))

Use cases

  • Separate internal / external endpoints in single code base (same urls different group)
  • Define other opts on different groups (you can define as much ResourceRouters as you wish)

Best practices

  • Do not decorate functions “manually” use dec in **opts - It will allow you to use all CodernityREST features and benefit from it. - You will be able to easily change api behaviour.
  • Use ResourceRouter as many times as you wish and need.
  • Keep logic separated.
  • Try avoid one big ResourceRouter. As mentioned before, CodernityREST will work perfectly with one big ResourceRouter, but believe us, you really want to create more than one ResourceRouter to easily control your logic (decorators, opts, groups etc).
  • Use validators.

Note

Most of features are tested in tests, you can check them, and ask for more info if needed.