3. Your API methods

Last modified by Ashterix on 2024/05/10 11:08

You can easily add your own API methods to the RPC server.

To do this, simply create any class in your application that is to become an API Service; this class must implement the interface Ufo\JsonRpcBundle\ApiMethod\Interfaces\IRpcService. This interface does not impose any logic on the class; it is only necessary for Symfony to understand that it should be treated as a service available to the RPC server.

Implement any public method in your class and it will automatically be available as an API Service.

 After following the previous instructions, you will have new methods available in the API. By default, method names consist of <className>.<methodName>.

Naming Classes

If needed, you can create multiple classes that will be available as API Services.
Considering their naming <className>.<methodName>, I recommend approaching the choice of method name as a simple indication of what it does, and the class name as the namespace of the API method.

Best Practice

The Messenger class contains methods sendEmail(), sendSms(); the CartResolver class contains methods addProduct(), getProducts(), calculateDiscount().

In the API, the following methods will be available:

  • CartResolver.addProduct
  • CartResolver.getProducts
  • CartResolver.calculateDiscount
  • Messenger.sendEmail
  • Messenger.sendSms

Just by looking at the method names, it's clear what your server can do.

This approach allows for the use of identical method names in different classes:

  • ProductService.create
  • ProductService.getName
  • UserService.create
  • UserService.getName

Getting Started

The following example demonstrates how easy it is to add your methods to the API.

Code

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
<?php
namespace App\Api\Procedures;

use Ufo\JsonRpcBundle\ApiMethod\Interfaces\IRpcService;

class ExampleApi implements IRpcService
{
   public function __construct(
       // connecting some dependencies to retrieve data
   ) {}
   
   public function getUserNameByUuid(
        string $userId
    ): string
    {
       // some logic get user info by id
       return 'some result';
    }
   
   public function sendEmail(
        string $email,
        string $text,
        string $subject = 'Message without subject'
    ): bool
    {
       // some logic send email
       return true;
    }
}

To the right is an example of the documentation that the server will generate for this class.

Basic information regarding parameter names, their types, and optionality is obtained thanks to ReflectionClass, with the order of method arguments, their typehints being crucial.

Documentation

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
{
   "methods": {
       "ExampleApi.getUserNameByUuid": {
           "name": "ExampleApi.getUserNameByUuid",
           "description": "",
           "parameters": {
               "userId": {
                   "type": "string",
                   "name": "userId",
                   "description": "",
                   "optional": false
                }
            },
           "returns": "string",
           "responseFormat": "string"
        },
       "ExampleApi.sendEmail": {
           "name": "ExampleApi.sendEmail",
           "description": "",
           "parameters": {
               "email": {
                   "type": "string",
                   "name": "email",
                   "description": "",
                   "optional": false
                },
               "text": {
                   "type": "string",
                   "name": "text",
                   "description": "",
                   "optional": false
                },
               "subject": {
                   "type": "string",
                   "name": "subject",
                   "description": "",
                   "optional": true,
                   "default": "Message without subject"
                }
            },
           "returns": "boolean",
           "responseFormat": "boolean"
        }
    }
}

Now we can make POST requests to both new API methods and see the results.

POST Requests

Request
1
2
3
4
5
6
7
{
   "id": "example_request",
   "method": "ExampleApi.getUserNameByUuid",
   "params": {
       "userId": "1111"
    }
}
Response
1
2
3
4
5
{
   "id": "example_request",
   "result": "some result",
   "jsonrpc": "2.0"
}
Request
1
2
3
4
5
6
7
8
9
{
   "id": "example_request",
   "method": "ExampleApi.sendEmail",
   "params": {
       "email": "user@example.com",
       "subject": "This is test mail",
       "text": "Hi! This is test send mail by API"
    }
}
Response
1
2
3
4
5
{
   "id": "example_request",
   "result": true,
   "jsonrpc": "2.0"
}

To simplify the understanding of the documentation, all subsequent examples will be provided using a single method (sendEmail).

Method and Parameter Descriptions

The documenter relies on all available data related to the method and its arguments (names, types of input and output data, docblocks). Thus, the descriptions of methods and parameters can be enriched through docblocks.

Let's add a description of the method and parameters.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// ...

   /**
     * A method for sending an email message
     * @param string $email The email address
     * @param string $text Message body
     * @param string $subject Optional message subject parameter
     * @return bool
     */

   public function sendEmail(
        string $email,
        string $text,
        string $subject = 'Message without subject'
    ): bool
    {
       // some logic send email
       return true;
    }

// ...

Note the documentation now displays additional information about the method and its parameters.

 

Documentation

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
{
   "methods": {
       "ExampleApi.sendEmail": {
           "name": "ExampleApi.sendEmail",
           "description": "A method for sending an email message",
           "parameters": {
               "email": {
                   "type": "string",
                   "name": "email",
                   "description": "The email address",
                   "optional": false
                },
               "text": {
                   "type": "string",
                   "name": "text",
                   "description": "Message body",
                   "optional": false
                },
               "subject": {
                   "type": "string",
                   "name": "subject",
                   "description": "Optional message subject parameter",
                   "optional": true,
                   "default": "Message without subject"
                }
            },
           "returns": "boolean",
           "responseFormat": "boolean"
        }
    }
}

RPC attributes

For more flexible configuration of your API methods, JsonRpcBundle uses such a tool as php attributes.

With specialized attributes, you can:

  • Set aliases for methods;
  • Specify the response format for methods (if the response is in the form of an array, an object, or a collection of objects);
  • Set up validation of input parameters;
  • Configure caching of responses.

Learn more about these attributes: