summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-api/opendc/util/rest.py
blob: 63d063b3e542425628e81edc02d2e12515f749cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import importlib
import json

from opendc.util import exceptions, parameter_checker
from opendc.util.exceptions import ClientError
from opendc.util.auth import current_user


class Request:
    """WebSocket message to REST request mapping."""
    def __init__(self, message=None):
        """"Initialize a Request from a socket message."""

        # Get the Request parameters from the message

        if message is None:
            return

        try:
            self.message = message

            self.id = message['id']

            self.path = message['path']
            self.method = message['method']

            self.params_body = message['parameters']['body']
            self.params_path = message['parameters']['path']
            self.params_query = message['parameters']['query']

            self.token = message['token']

        except KeyError as exception:
            raise exceptions.MissingRequestParameterError(exception)

        # Parse the path and import the appropriate module

        try:
            self.path = message['path'].strip('/')

            module_base = 'opendc.api.{}.endpoint'
            module_path = self.path.replace('{', '').replace('}', '').replace('/', '.')

            self.module = importlib.import_module(module_base.format(module_path))
        except ImportError as e:
            print(e)
            raise exceptions.UnimplementedEndpointError('Unimplemented endpoint: {}.'.format(self.path))

        # Check the method

        if self.method not in ['POST', 'GET', 'PUT', 'PATCH', 'DELETE']:
            raise exceptions.UnsupportedMethodError('Non-rest method: {}'.format(self.method))

        if not hasattr(self.module, self.method):
            raise exceptions.UnsupportedMethodError('Unimplemented method at endpoint {}: {}'.format(
                self.path, self.method))

        self.current_user = current_user

    def check_required_parameters(self, **kwargs):
        """Raise an error if a parameter is missing or of the wrong type."""

        try:
            parameter_checker.check(self, **kwargs)
        except exceptions.ParameterError as e:
            raise ClientError(Response(400, str(e)))

    def process(self):
        """Process the Request and return a Response."""

        method = getattr(self.module, self.method)

        try:
            response = method(self)
        except ClientError as e:
            e.response.id = self.id
            return e.response

        response.id = self.id

        return response

    def to_JSON(self):
        """Return a JSON representation of this Request"""

        self.message['id'] = 0
        self.message['token'] = None

        return json.dumps(self.message)


class Response:
    """Response to websocket mapping"""
    def __init__(self, status_code, status_description, content=None):
        """Initialize a new Response."""

        self.id = 0
        self.status = {'code': status_code, 'description': status_description}
        self.content = content

    def to_JSON(self):
        """"Return a JSON representation of this Response"""

        data = {'id': self.id, 'status': self.status}

        if self.content is not None:
            data['content'] = self.content

        return json.dumps(data, default=str)