Last modified by Ashterix on 2024/05/16 12:35

Show last authors
1 {{box cssClass="floatinginfobox" title="**Content**"}}
2 {{toc/}}
3 {{/box}}
4
5 You can easily add your own API methods to the RPC server.
6
7 To do this, you just need to create any class that will become an API Service anywhere in your application. This class must implement the interface {{code language="none"}}Ufo\JsonRpcBundle\ApiMethod\Interfaces\IRpcService{{/code}}. This interface does not impose any logic on the class; it is only necessary for Symfony to understand that it should treat it as a service available to the RPC server.
8
9 Implement any public method in your class, and it will automatically be available as an API Service.
10
11 (% id="cke_bm_318406S" style="display:none" %) (%%) After following the previous instructions, new methods will already be available in the API. By default, method names are composed of {{code language="none"}}<className>.<methodName>{{/code}}.
12
13 = Naming Classes =
14
15 If necessary, you can create several classes that will be available as API Services.
16 Considering their naming {{code language="none"}}<className>.<methodName>{{/code}}, I recommend treating the method name as a simple indication of what it does and the class name as the namespace of the API method.
17
18 (% class="box successmessage" %)
19 (((
20 == **Best Practices** ==
21
22 The class **//Messenger//** contains methods **//sendEmail()//**, **sendSms()**; the class **CartResolver** contains methods **//addProduct()//**, **getProducts()**, **calculateDiscount()**.
23
24 In the API, the following methods will be available:
25
26 * **CartResolver.addProduct**
27 * **CartResolver.getProducts**
28 * **CartResolver.calculateDiscount**
29 * **Messenger.sendEmail**
30 * **Messenger.sendSms**
31
32 Even just by looking at the method names, it is clear what your server can do.
33
34 This approach allows you to use the same method names in different classes:
35
36 * **ProductService.create**
37 * **ProductService.getName**
38 * **UserService.create**
39 * **UserService.getName**
40 )))
41
42 = Simple Start =
43
44 The following example should demonstrate the ease of adding your methods to the API.
45
46 (% class="row" %)
47 (((
48 (% class="col-xs-12 col-sm-6" %)
49 (((
50 {{code language="php" layout="LINENUMBERS" title="== Code =="}}
51 <?php
52 namespace App\Api\Procedures;
53
54 use Ufo\JsonRpcBundle\ApiMethod\Interfaces\IRpcService;
55
56 class ExampleApi implements IRpcService
57 {
58 public function __construct(
59 // connecting some dependencies to retrieve data
60 ) {}
61
62 public function getUserNameByUuid(
63 string $userId
64 ): string {
65 // some logic to get user info by id
66 return 'some result';
67 }
68
69 public function sendEmail(
70 string $email,
71 string $text,
72 string $subject = 'Message without subject'
73 ): bool {
74 // some logic to send email
75 return true;
76 }
77 }
78 {{/code}}
79
80 To the right, you see an example of the documentation that the server will generate for this class.
81
82 The main information about parameter names, their types, and optionality is obtained thanks to (% class="box code" %)ReflectionClass(%%), with the important points being the order of method arguments and their type hints.
83 )))
84
85 (% class="col-xs-12 col-sm-6" %)
86 (((
87 {{code language="json" layout="LINENUMBERS" title="== Documentation =="}}
88 {
89 "methods": {
90 "ExampleApi.getUserNameByUuid": {
91 "name": "ExampleApi.getUserNameByUuid",
92 "description": "",
93 "parameters": {
94 "userId": {
95 "type": "string",
96 "name": "userId",
97 "description": "",
98 "optional": false
99 }
100 },
101 "returns": "string",
102 "responseFormat": "string"
103 },
104 "ExampleApi.sendEmail": {
105 "name": "ExampleApi.sendEmail",
106 "description": "",
107 "parameters": {
108 "email": {
109 "type": "string",
110 "name": "email",
111 "description": "",
112 "optional": false
113 },
114 "text": {
115 "type": "string",
116 "name": "text",
117 "description": "",
118 "optional": false
119 },
120 "subject": {
121 "type": "string",
122 "name": "subject",
123 "description": "",
124 "optional": true,
125 "default": "Message without subject"
126 }
127 },
128 "returns": "boolean",
129 "responseFormat": "boolean"
130 }
131 }
132 }
133 {{/code}}
134 )))
135 )))
136
137 Now we can make POST requests to both new API methods and see the results.
138
139 == **POST Requests** ==
140
141 (% class="row" %)
142 (((
143 (% class="col-xs-12 col-sm-6" %)
144 (((
145 {{code language="json" layout="LINENUMBERS" title="Request"}}
146 {
147 "id": "example_request",
148 "method": "ExampleApi.getUserNameByUuid",
149 "params": {
150 "userId": "1111"
151 }
152 }
153 {{/code}}
154 )))
155
156 (% class="col-xs-12 col-sm-6" %)
157 (((
158 {{code language="json" layout="LINENUMBERS" title="Response"}}
159 {
160 "id": "example_request",
161 "result": "some result",
162 "jsonrpc": "2.0"
163 }
164 {{/code}}
165 )))
166 )))
167
168 (% class="row" %)
169 (((
170 (% class="col-xs-12 col-sm-6" %)
171 (((
172 {{code language="json" layout="LINENUMBERS" title="Request"}}
173 {
174 "id": "example_request",
175 "method": "ExampleApi.sendEmail",
176 "params": {
177 "email": "user@example.com",
178 "subject": "This is a test mail",
179 "text": "Hi! This is a test email sent by the API"
180 }
181 }
182 {{/code}}
183 )))
184
185 (% class="col-xs-12 col-sm-6" %)
186 (((
187 {{code language="json" layout="LINENUMBERS" title="Response"}}
188 {
189 "id": "example_request",
190 "result": true,
191 "jsonrpc": "2.0"
192 }
193 {{/code}}
194 )))
195 )))
196
197 (% class="box warningmessage" %)
198 (((
199 To simplify the documentation, all further examples will be provided using a single method (//**sendEmail**//).
200 )))
201
202 = Description of Methods and Parameters =
203
204 The documenter relies on all available data belonging to the method and its arguments (names, input and output data types, docblocks). Thus, the description of methods and parameters can be enriched using docblocks.
205
206 Let's add a description for the method and its parameters.
207
208 (% class="row" %)
209 (((
210 (% class="col-xs-12 col-sm-6" %)
211 (((
212 {{code language="php" layout="LINENUMBERS" title="== Code =="}}
213 <?php
214 // ...
215 /**
216 * A method for sending an email message
217 * @param string $email The email address
218 * @param string $text Message body
219 * @param string $subject Optional message subject parameter
220 * @return bool
221 */
222 public function sendEmail(
223 string $email,
224 string $text,
225 string $subject = 'Message without subject'
226 ): bool {
227 // some logic to send email
228 return true;
229 }
230 // ...
231 {{/code}}
232
233 Note the documentation now displays additional information about the method and its parameters.
234 )))
235
236 (% class="col-xs-12 col-sm-6" %)
237 (((
238 {{code language="json" layout="LINENUMBERS" title="== Documentation =="}}
239 {
240 "methods": {
241 "ExampleApi.sendEmail": {
242 "name": "ExampleApi.sendEmail",
243 "description": "A method for sending an email message",
244 "parameters": {
245 "email": {
246 "type": "string",
247 "name": "email",
248 "description": "The email address",
249 "optional": false
250 },
251 "text": {
252 "type": "string",
253 "name": "text",
254 "description": "Message body",
255 "optional": false
256 },
257 "subject": {
258 "type": "string",
259 "name": "subject",
260 "description": "Optional message subject parameter",
261 "optional": true,
262 "default": "Message without subject"
263 }
264 },
265 "returns": "boolean",
266 "responseFormat": "boolean"
267 }
268 }
269 }
270 {{/code}}
271 )))
272 )))
273
274 = RPC Attributes =
275
276 For more flexible customization of your API methods, JsonRpcBundle uses [[PHP attributes>>url:https://www.php.net/manual/en/language.attributes.overview.php]].
277
278 With the help of specialized attributes, you can:
279
280 * set aliases for methods;
281 * specify the response format for methods (if the response is in the form of an array, object, or collection of objects);
282 * configure input parameter validation;
283 * set up response caching.
284
285 Read more about these attributes:
286
287 {{children/}}