joop 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
joop/tests/test_web.py ADDED
@@ -0,0 +1,75 @@
1
+ """Unit tests for joop web components.
2
+
3
+ We're testing both components, their templates, and the rendering here.
4
+ """
5
+
6
+ from joop.web import HTMLComponent
7
+ import unittest
8
+ from dataclasses import is_dataclass, dataclass, asdict
9
+ from joop.tests.test_templater import environment
10
+ from joop.web.examples.hello import (
11
+ HelloWorld, HelloName, HelloSuperComponent
12
+ )
13
+
14
+ # Create our classes for the test and
15
+ # specify the environment via multiple inheritance:
16
+
17
+ class BaseTestHTMLComponent(HTMLComponent):
18
+ _jinja_env = environment
19
+
20
+ class MyHello(HelloWorld,
21
+ BaseTestHTMLComponent): pass
22
+
23
+ class MyHelloName(HelloName,
24
+ BaseTestHTMLComponent): pass
25
+
26
+ class MyHelloSuper(HelloSuperComponent,
27
+ BaseTestHTMLComponent): pass
28
+
29
+ class TestHTMLComponent(unittest.TestCase):
30
+
31
+ def _setup_hello(self):
32
+ self.hello = MyHello()
33
+ self.hello.inputs = MyHello.Inputs()
34
+ self.hello.subs = MyHello.SubComponents()
35
+
36
+ def _setup_name(self):
37
+ self.hello_name = MyHelloName()
38
+ self.hello_name.inputs = MyHelloName.Inputs(first_name = "Justin",
39
+ last_name = "Rushin")
40
+ self.hello_name.subs = MyHelloName.SubComponents()
41
+
42
+ def _setup_super(self):
43
+ self.hello_super = MyHelloSuper()
44
+ self.hello_super.inputs = MyHelloSuper.Inputs()
45
+
46
+ def setUp(self):
47
+ # Configure the Jinja2 environment with a FileSystemLoader
48
+ self._setup_hello()
49
+ self._setup_name()
50
+ self._setup_super()
51
+
52
+ def test_000_type_check(self):
53
+ # here, we are verifying that our custom abstract code works
54
+ assert is_dataclass(self.hello.inputs)
55
+
56
+ def test_001_hello_world(self):
57
+ hello_html = self.hello.render()
58
+ assert hello_html == "<p>Hello, World!</p>"
59
+
60
+ def test_002_hello_name(self):
61
+ hello_name_html = self.hello_name.render()
62
+ _tgt_html = """<p>Hello, Justin Rushin!</p>"""
63
+ assert hello_name_html == _tgt_html
64
+
65
+ def test_003_hello_subcomponent(self):
66
+ _hello = MyHello(parent=self.hello_super)
67
+ _hello.inputs = MyHello.Inputs()
68
+ _hello.subs = MyHello.SubComponents()
69
+ self.hello_super.subs = MyHelloSuper.SubComponents(
70
+ my_hello = _hello
71
+ )
72
+ assert is_dataclass(self.hello_super.subs)
73
+ hello_super_html = self.hello_super.render()
74
+ _tgt_html = """<p>I'm a supercomponent! And I say:</p>\n<p>Hello, World!</p>"""
75
+ assert hello_super_html == _tgt_html
joop/web/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ """Web module.
2
+
3
+ All functionality related to web-backends, HTML templating, etc. lives here.
4
+
5
+ Modules:
6
+ component: Define web UI or API components.
7
+ html: Where components get rendered to HTML.
8
+ view: Register components to webservers, set up views routes, etc.
9
+
10
+ """
11
+
12
+ from joop.web.component import Component #, JSONComponent
13
+ from joop.web.html import HTML, HTMLComponent
14
+ from joop.web.view import View
joop/web/component.py ADDED
@@ -0,0 +1,163 @@
1
+ """
2
+
3
+ Components are programmatic representations of data or UI elements, designed to be rendered dynamically,
4
+ in the context of a web server.
5
+ A highly abstract class, the purpose of it is to provide a standard way to define inputs, outputs,
6
+ and the transformations needed to render them. Components are the backbone of joop.web.
7
+
8
+ Classes:
9
+ Component:
10
+ The base class for all components, providing a structure for inputs, data, and subcomponents.
11
+
12
+ JSONComponent:
13
+ A specialized component for handling JSON data. Implementation pending.
14
+
15
+ """
16
+
17
+ from typing import Optional
18
+ from dataclasses import dataclass, fields
19
+ from abc import ABCMeta
20
+
21
+ from joop.abstract import AbstractMethod
22
+
23
+ class Component(metaclass=ABCMeta):
24
+ '''
25
+ Base class for programmatically rendering data or UI elements.
26
+
27
+ This class provides a structure for defining inputs, data, and subcomponents,
28
+ and includes methods for processing inputs and rendering components.
29
+
30
+ Attributes:
31
+ inputs (Inputs): The input data for the component.
32
+ data (Data): The processed data for the component.
33
+ subs (SubComponents): The subcomponents of the component.
34
+
35
+ Methods:
36
+ _process_inputs():
37
+ Processes the inputs to generate the component's data.
38
+
39
+ render() -> str:
40
+ Abstract method to render the component as a string.
41
+ '''
42
+
43
+ class Inputs(metaclass=ABCMeta):
44
+ """Abstract base class for defining the input data structure of a component."""
45
+ pass
46
+
47
+ Inputs = dataclass(Inputs)
48
+
49
+ class _Data(metaclass=ABCMeta):
50
+ """Abstract base class for defining the internal data structure of a component."""
51
+ pass
52
+
53
+ _Data = dataclass(_Data)
54
+
55
+ class Data(_Data):
56
+ """
57
+ Class for defining the processed data of a component.
58
+
59
+ Methods:
60
+ _from_inputs(inputs: Component.Inputs) -> Component.Data:
61
+ Creates a Data instance from the given Inputs.
62
+
63
+ from_inputs(inputs: Component.Inputs) -> Component.Data:
64
+ Abstract method to create a Data instance from the given Inputs.
65
+ """
66
+
67
+ @classmethod
68
+ def _from_inputs(cls, inputs: 'Component.Inputs') -> 'Component.Data':
69
+ """
70
+ Create a Data instance from the given Inputs.
71
+
72
+ Args:
73
+ inputs (Component.Inputs): The input data for the component.
74
+
75
+ Returns:
76
+ Component.Data: A new Data instance.
77
+ """
78
+ return cls()
79
+
80
+ @classmethod
81
+ def from_inputs(cls, inputs: 'Component.Inputs') -> 'Component.Data':
82
+ """
83
+ Abstract method to create a Data instance from the given Inputs.
84
+
85
+ Args:
86
+ inputs (Component.Inputs): The input data for the component.
87
+
88
+ Returns:
89
+ Component.Data: A new Data instance.
90
+ """
91
+ return Component.Data() # pragma: no cover
92
+
93
+ from_inputs = AbstractMethod(from_inputs)
94
+
95
+ class SubComponents(metaclass=ABCMeta):
96
+ """Abstract base class for defining the subcomponents of a component."""
97
+ pass
98
+
99
+ SubComponents = dataclass(SubComponents)
100
+
101
+ inputs: Inputs
102
+ data: Data
103
+ subs: SubComponents
104
+
105
+ def __init__(self, parent: Optional['Component'] = None, *args, **kwargs):
106
+ """
107
+ Initialize a Component instance.
108
+
109
+ Args:
110
+ parent (Optional[Component]): The parent component, if any.
111
+ *args: Additional positional arguments.
112
+ **kwargs: Additional keyword arguments.
113
+ """
114
+ super().__init__(*args, **kwargs) # Pass additional arguments to the next class in the MRO
115
+ if parent is not None:
116
+ self._parent = parent
117
+
118
+ def _process_inputs(self):
119
+ """
120
+ Process the inputs to generate the component's data.
121
+
122
+ This method uses the `from_inputs` method of the Data class to create a
123
+ Data instance from the component's inputs.
124
+ """
125
+ self.data = self.Data.from_inputs(self.inputs)
126
+
127
+ def render(self) -> str:
128
+ """
129
+ Abstract method to render the component as a string.
130
+
131
+ This method processes the inputs and generates the component's data before
132
+ rendering it as a string. Subclasses must implement this method.
133
+
134
+ Returns:
135
+ str: The rendered component as a string.
136
+ """
137
+ self._process_inputs()
138
+
139
+ render.__isabstractmethod__ = True
140
+
141
+ def __init_subclass__(cls, **kwargs):
142
+ """
143
+ Initialize a subclass of Component.
144
+
145
+ This method ensures that the Data, Inputs, and SubComponents classes of the
146
+ subclass are decorated as dataclasses.
147
+
148
+ Args:
149
+ **kwargs: Additional keyword arguments.
150
+ """
151
+ super().__init_subclass__(**kwargs)
152
+ cls.Data = dataclass(cls.Data)
153
+ cls.Inputs = dataclass(cls.Inputs)
154
+ cls.SubComponents = dataclass(cls.SubComponents)
155
+
156
+ class JSONComponent(Component):
157
+ """
158
+ A specialized component for handling JSON data.
159
+
160
+ Inherits:
161
+ Component: The base Component class.
162
+ """
163
+ pass
joop/web/components.py ADDED
@@ -0,0 +1,116 @@
1
+ """
2
+ Useful components for web development.
3
+ It includes a base class `AlpineTableComponent` for generating AlpineJS-powered
4
+ tables based on Pydantic or SQLModel models.
5
+ The module also defines data access object (DAO) classes for handling row data.
6
+ """
7
+
8
+ from joop.web.html import HTMLComponent
9
+ from joop.dao import DAO
10
+ import typing
11
+
12
+ class MetaRowDAO(DAO):
13
+ """
14
+ Implementation pending.
15
+ A base Data Access Object (DAO) class for handling row data.
16
+ This class can be extended to implement specific data access logic.
17
+ """
18
+ pass
19
+
20
+ class RowDAO(MetaRowDAO):
21
+ """
22
+ Implementation pending.
23
+ A concrete implementation of `MetaRowDAO` for handling generic row data.
24
+ """
25
+ pass
26
+
27
+ class SQLRowDAO(MetaRowDAO):
28
+ """
29
+ Implementation pending.
30
+ A concrete implementation of `MetaRowDAO` for handling SQL-based row data.
31
+ """
32
+ pass
33
+
34
+ '''
35
+ A common base component to allow for ready-made,
36
+ AlpineJS powered
37
+ tables based on Pydantic or SQLModel models.
38
+ '''
39
+ class AlpineTableComponent(HTMLComponent):
40
+ """
41
+ A reusable component for rendering tables using Alpine.js and HTML templates.
42
+
43
+ Attributes:
44
+ _template_location (str): Path to the HTML template for the table.
45
+ _use_prefix_template (bool): Determines whether to use a prefixed template directory.
46
+ _row_type (typing.Type[MetaRowDAO]): Specifies the type of row data to be used in the table.
47
+ """
48
+ _template_location = "table/alp_table.html"
49
+ _use_prefix_template = False
50
+ _row_type: typing.Type[MetaRowDAO]
51
+
52
+ class Inputs(HTMLComponent.Inputs):
53
+ """
54
+ Represents the input data structure for the `AlpineTableComponent`.
55
+ Extend this class to define specific input fields for the table.
56
+ """
57
+ pass
58
+
59
+ class Data(HTMLComponent.Data):
60
+ """
61
+ Represents the data structure for the `AlpineTableComponent`.
62
+
63
+ Attributes:
64
+ rows (typing.Iterable[MetaRowDAO]): The rows of data to be displayed in the table.
65
+ table_headers (typing.Any): The headers of the table, derived from the row type.
66
+ _row_type: The type of row data used in the table.
67
+ """
68
+ rows : typing.Iterable[MetaRowDAO]
69
+ table_headers: typing.Any
70
+ _row_type = None
71
+
72
+ @classmethod
73
+ def _get_table_headers(cls):
74
+ """
75
+ Retrieve the table headers based on the fields of the row type's model.
76
+
77
+ Returns:
78
+ list: A list of field names for the table headers.
79
+ """
80
+ return cls._row_type.get_model_fields()
81
+
82
+ @classmethod
83
+ def from_inputs(cls,
84
+ inputs : 'AlpineTableComponent.Inputs',
85
+ ) -> 'AlpineTableComponent.Data':
86
+ """
87
+ Create a `Data` instance from the provided inputs.
88
+
89
+ Args:
90
+ inputs (AlpineTableComponent.Inputs): The input data for the table.
91
+
92
+ Returns:
93
+ AlpineTableComponent.Data: An instance of the Data class with initialized values.
94
+ """
95
+ return cls(rows = [],
96
+ table_headers = cls._get_table_headers())
97
+
98
+ def _process_inputs(self, **kwargs):
99
+ """
100
+ Process the input data and set the row type for the table.
101
+
102
+ Args:
103
+ **kwargs: Additional keyword arguments for processing inputs.
104
+
105
+ Returns:
106
+ Any: The processed input data.
107
+ """
108
+ self.Data._row_type = self._row_type
109
+ return super()._process_inputs(**kwargs)
110
+
111
+ class SubComponents(HTMLComponent.SubComponents):
112
+ """
113
+ Represents subcomponents of the `AlpineTableComponent`.
114
+ Extend this class to define specific subcomponents.
115
+ """
116
+ pass
@@ -0,0 +1,148 @@
1
+ """
2
+
3
+ This file contains examples for learning, development, and testing of joop.web components.
4
+ Included is examples of how to define and implement web components of the most basic kind.
5
+
6
+ """
7
+
8
+ from joop.web import HTMLComponent
9
+
10
+ class HelloWorld(HTMLComponent):
11
+
12
+ # Every HTMLComponent has a template location.
13
+ _template_location = "hello.html"
14
+
15
+ # A definition of an inner input class is required.
16
+ class Inputs(HTMLComponent.Inputs):
17
+ # Even if it's empty.
18
+ pass
19
+
20
+ # For the inner classes, inherit from the parent class:
21
+ class Data(HTMLComponent.Data):
22
+ pass
23
+
24
+ # `from_inputs` must be defined as well.
25
+ @classmethod # Yes, you still have to specify classmethod.
26
+ # Also, it is good to be specific with type hints:
27
+ def from_inputs(cls, inputs : 'HelloWorld.Inputs') -> 'HelloWorld.Data':
28
+ # If you've got a no-op class like this, use:
29
+ return super()._from_inputs(inputs)
30
+
31
+ # Copy-pasting the above ^^^ to a new component is safe
32
+
33
+ # Same as inputs, just make an empty class if there are no
34
+ # child/sub components.
35
+ class SubComponents(HTMLComponent.SubComponents):
36
+ pass
37
+
38
+ '''
39
+ To then render the hello world component:
40
+ ```
41
+ component = HelloWorld()
42
+ component.inputs = component.Inputs()
43
+ # You don't need to do data because of the `from_inputs`.
44
+ component.subs = component.SubComponents()
45
+ return component.render()
46
+ ```
47
+ That's it. But why complicate a "hello world" by
48
+ requiring empty classes, functions etc.?
49
+ A few reasons:
50
+ 1. We don't optimize for "hello world" because real
51
+ components are unlikely to be this simple, but
52
+ compromise on succintness for the sake of simplicity
53
+ and consistency.
54
+ 2. joop is a declarative paradigm, and accordingly,
55
+ explicitly declared symbols show the class inheritance.
56
+ 3. Explicitly declared stubs show you that nothing is there.
57
+ 4. It facilitates the derivation of more complex components
58
+ from more simple ones (and possibly, vice-versa).
59
+ 5. A place for everything, and everything in its place.
60
+ '''
61
+
62
+ # Now for a component with dynamic data rendering.
63
+
64
+ class HelloName(HTMLComponent):
65
+ _template_location = "hello_name.html" # Adjusted for simplicity
66
+
67
+ # Inputs and data are dataclasses via inheritance (there's a bit of trickery).
68
+ class Inputs(HTMLComponent.Inputs):
69
+ first_name: str
70
+ last_name : str
71
+
72
+ # Inputs is what it sounds like.
73
+ # Data goes to the template to be rendered.
74
+ class Data(HTMLComponent.Data):
75
+ # The name of the data fields will be used in the template.
76
+ full_name : str
77
+
78
+ @classmethod
79
+ def from_inputs(cls, inputs: "HelloName.Inputs") -> "HelloName.Data":
80
+ res = f"{inputs.first_name} {inputs.last_name}"
81
+ return cls(full_name = res)
82
+
83
+ class SubComponents(HTMLComponent.SubComponents):
84
+ pass
85
+ '''
86
+ To then render the hello name component:
87
+ ```
88
+ component = HelloName()
89
+ component.inputs = component.Inputs(
90
+ first_name = "Justin",
91
+ last_name = "Rushin")
92
+ component.subs = res.SubComponents()
93
+ return component.render()
94
+ ```
95
+ '''
96
+
97
+ # Now for an example with subcomponents aka:
98
+ # child components, or nested components.
99
+
100
+ class HelloSuperComponent(HTMLComponent):
101
+ # Of course, this is our/outer's template. Inner
102
+ # template isn't specified. It's in the subcomponent.
103
+ _template_location = "hello_supercomponent.html"
104
+
105
+ # Empty inputs and data classes follow:
106
+ class Inputs(HTMLComponent.Inputs):
107
+ pass
108
+
109
+ class Data(HTMLComponent.Data):
110
+
111
+ @classmethod
112
+ def from_inputs(cls, inputs):
113
+ return super()._from_inputs(inputs)
114
+
115
+ class SubComponents(HTMLComponent.SubComponents):
116
+ # No need to specify a default factory.
117
+ # We use some trickery. Just specify the class
118
+ # of the child component.
119
+ my_hello: HelloWorld
120
+
121
+ def render(self) -> str:
122
+ return super().render()
123
+
124
+ '''
125
+ To render this component with nesting:
126
+ ```
127
+ component = HelloSuperComponent()
128
+ component.inputs = component.Inputs() # empty inputs
129
+ subcomponent = HelloWorld(parent = component)
130
+ subcomponent.inputs = subcomponent.Inputs()
131
+ component.subs = component.SubComponents(
132
+ my_hello = subcomponent
133
+ )
134
+ component.render()
135
+ ```
136
+ `render` will include subcomponents recursively.
137
+ '''
138
+
139
+ '''
140
+ To summarize, a component is made by:
141
+ 1. Deriving the outer class from the correct class.
142
+ 2. Defining the fields/properties of the innner classes.
143
+ 3. Implementing the `from_inputs` function to transform
144
+ input to output.
145
+ 4. Carrying out any other special implementation necessary.
146
+
147
+ Of course, this ignores what's done on the template side.
148
+ '''
@@ -0,0 +1,148 @@
1
+ """
2
+ This module provides an example implementation of a table component and its integration into a web page.
3
+ It demonstrates the usage of the `AlpineTableComponent` for rendering tables and the `View` class for creating web pages.
4
+ """
5
+
6
+ from joop.web.components import AlpineTableComponent
7
+ from joop.web.view import View
8
+ from joop.web.html import HTMLComponent
9
+ from joop.http.methods import HttpMethod
10
+ from joop.web.examples.view import HELLO_DESIG, HELLO_ROOT
11
+ from joop.dao import DAO
12
+ from pydantic import BaseModel
13
+
14
+ class Hello_DAO(DAO):
15
+ """
16
+ A Data Access Object (DAO) for handling data related to the `Hello_Model`.
17
+
18
+ Attributes:
19
+ Hello_Model (BaseModel): A Pydantic model representing the data structure.
20
+ """
21
+
22
+ class Hello_Model(BaseModel):
23
+ """
24
+ A Pydantic model representing a simple data structure with a single field `Desig`.
25
+
26
+ Attributes:
27
+ Desig (str): A string field representing a designation.
28
+ """
29
+ Desig : str
30
+
31
+ _modeltype = Hello_Model
32
+
33
+ class MyTableComponent(AlpineTableComponent):
34
+ """
35
+ A custom table component that extends the `AlpineTableComponent`.
36
+
37
+ Attributes:
38
+ _row_type (type): Specifies the type of row data to be used in the table.
39
+ """
40
+ _row_type = Hello_DAO
41
+
42
+ class Inputs(AlpineTableComponent.Inputs):
43
+ """
44
+ Represents the input data structure for the `MyTableComponent`.
45
+ Extend this class to define specific input fields for the table.
46
+ """
47
+ pass
48
+
49
+ class Data(AlpineTableComponent.Data):
50
+ """
51
+ Represents the data structure for the `MyTableComponent`.
52
+
53
+ Attributes:
54
+ definition_name (str): The name of the table definition.
55
+ """
56
+ definition_name : str = "myTable"
57
+
58
+ @classmethod
59
+ def from_inputs(cls, inputs : 'MyTableComponent.Inputs') -> AlpineTableComponent.Data:
60
+ """
61
+ Create a `Data` instance from the provided inputs.
62
+
63
+ Args:
64
+ inputs (MyTableComponent.Inputs): The input data for the table.
65
+
66
+ Returns:
67
+ AlpineTableComponent.Data: An instance of the Data class with initialized values.
68
+ """
69
+ return cls(
70
+ rows = [
71
+ Hello_DAO.from_model(Hello_DAO.Hello_Model(Desig = "Hello")),
72
+ Hello_DAO.from_model(Hello_DAO.Hello_Model(Desig = "World"))
73
+ ],
74
+ table_headers = cls._get_table_headers()
75
+ )
76
+
77
+ class SubComponents(AlpineTableComponent.SubComponents):
78
+ """
79
+ Represents subcomponents of the `MyTableComponent`.
80
+ Extend this class to define specific subcomponents.
81
+ """
82
+ pass
83
+
84
+ class MyTablePage(HTMLComponent):
85
+ """
86
+ A web page component that includes the `MyTableComponent`.
87
+
88
+ Attributes:
89
+ _template_location (str): Path to the HTML template for the page.
90
+ """
91
+ _template_location = "table/page.html"
92
+
93
+ class Inputs(HTMLComponent.Inputs):
94
+ """
95
+ Represents the input data structure for the `MyTablePage`.
96
+ Extend this class to define specific input fields for the page.
97
+ """
98
+ pass
99
+
100
+ class Data(HTMLComponent.Data):
101
+ """
102
+ Represents the data structure for the `MyTablePage`.
103
+ """
104
+
105
+ @classmethod
106
+ def from_inputs(cls, inputs : 'MyTablePage.Inputs'):
107
+ """
108
+ Create a `Data` instance from the provided inputs.
109
+
110
+ Args:
111
+ inputs (MyTablePage.Inputs): The input data for the page.
112
+
113
+ Returns:
114
+ MyTablePage.Data: An instance of the Data class with initialized values.
115
+ """
116
+ return cls()
117
+
118
+ class SubComponents(HTMLComponent.SubComponents):
119
+ """
120
+ Represents subcomponents of the `MyTablePage`.
121
+
122
+ Attributes:
123
+ my_t (MyTableComponent): An instance of the `MyTableComponent`.
124
+ """
125
+ my_t = MyTableComponent
126
+ table : my_t = my_t()
127
+
128
+ class MyTableWholePage(View):
129
+ """
130
+ A web view that renders the `MyTablePage` component.
131
+
132
+ Attributes:
133
+ _component_type (type): Specifies the type of the main component for the view.
134
+ """
135
+ _component_type = MyTablePage
136
+
137
+ class Endpoint():
138
+ """
139
+ Defines the endpoint for the `MyTableWholePage` view.
140
+
141
+ Attributes:
142
+ _url (str): The URL path for the endpoint.
143
+ _name (str): The name of the endpoint.
144
+ _methods (list): The HTTP methods supported by the endpoint.
145
+ """
146
+ _url = HELLO_ROOT + "/table"
147
+ _name = HELLO_DESIG + "_table"
148
+ _methods = [HttpMethod.GET.value]
@@ -0,0 +1,30 @@
1
+ """
2
+
3
+ This is an example of how to define Views from components.
4
+
5
+ """
6
+
7
+ from joop.http.methods import HttpMethod
8
+ from joop.web.examples.hello import HelloWorld, HelloName
9
+ from joop.web.view import View
10
+
11
+ HELLO_ROOT = "/hello"
12
+ HELLO_DESIG = "hello"
13
+
14
+ class HelloView(View):
15
+
16
+ _component_type = HelloWorld
17
+
18
+ class Endpoint():
19
+ _url = HELLO_ROOT
20
+ _name = HELLO_DESIG
21
+ _methods = [HttpMethod.GET.value]
22
+
23
+ class NameView(View):
24
+
25
+ _component_type = HelloName
26
+
27
+ class Endpoint():
28
+ _url = HELLO_ROOT + "/<string:first_name>/<string:last_name>"
29
+ _name = HELLO_DESIG + "_name"
30
+ _methods = [HttpMethod.GET.value]