Yii 1.1: bogo-yii-json-service

JSON-capable controllers
10 followers

This extension extends the CController and gives it JSON capabilities for fast development of JSON web services and their documentation.

Requirements

This has been tested on Yii 1.1.10+

Features

Action Input parameters

You define your input parameters as objects, which are actually the JSON-decoded payload of your caller's request. Decoding and validation takes place transparently, as long as your input object is a subclass of CBJsonModel.

Action Return values

You return your action's response with return instead of render. It's highly suggested that your return objects are subtypes of CBJsonModel or arrays of such objects. Still, this is a suggestion, of course you can return anything that json_encode() accepts, as long as you trust what you're exposing to your caller.

PHPdoc for your json services

The above allow for automatic documentation of your services, e.g. using apigen. The produced documentation can be then published and let your clients/callers know exactly what they should pass as input and what to expect as output.

Consistent error and exception handling

Error handling is done automatically, i.e. whenever an exception or PHP error is thrown, a standard-format JSON is returned which your caller may then parse and handle.

Installation

Download and extract the code into /protected/extensions/bogo-yii-json-service/ folder.

Add the following lines in the import array of your /protected/config/main.php to make the extensions classes visible to your code and enable CBHttpRequest functionality in place of Yii's standard CHttpRequest class:

return array(
    // [..]
 
    // autoloading model and component classes
    'import'=>array(
        // [..]
        'ext.bogo-yii-json-service.components.*',
        // [..]
    ),
 
    // application components
    'components'=>array(
        // [..]
 
        // Use json-capable http request
        'request'=>array(
            'class'=>'CBHttpRequest',
        ),
 
        // [..]
    ),
    // [..]
);

Demonstration

Quick sample

Below a sample code which highlights the usage of JSON capabilities. Things you should keep are:

  1. The controller extends the CBJsonController component
  2. The method accepts a ProductQueryJson object instead of looking into $_GET/$_POST
  3. The method returns an array of ProductJson objects instead of calling $this->render()
class ProductController extends CBJsonController
{
    /**
     * Find products.
     *
     * @param ProductQueryJson $queryJson Query criteria
     * @return ProductJson[] Matching products
     */
    public function actionFindProduct(ProductQueryJson $queryJson)
    {
        $foundProducts = Product::model()->scopeApplyQuery($queryJson)->findAll();
 
        return ProductJson::createFromMany($foundProducts);
    }
}

More detailed usage

For more details and examples, see the the demo page

Your API's public documentation

Here's the demo controller documentation you get by using this extension in conjunction with proper phpdoc comments and apigen.

Resources

Similar Extensions

  • JApi, short for JSON API, is an action handler for Yii.

Total 10 comments

#16117 report it
Alexis Araya at 2014/01/21 09:52am
QueryJson

Thanks, it worked.

Now I have another question

in the ProductQueryJson class there are 3 properties

$filterMinPrice,$resultsLimit,$resultsOrderBy

ProductController 
  /**
         * Find products.
         *
         * @param ProductQueryJson $queryJson Query criteria
         * @return ProductJson[] Matching products
         */
        public function actionFindProduct(ProductQueryJson $queryJson)
        {
              $foundProducts = Product::model()->scopes($queryJson)->findAll()

                return ProductJson::createFromMany($foundProducts);
        }

I'm trying that you use in the query

http://localhost/MovilServices/index.php?r=Product/FindProduct&jsin={"filterMinPrice":"10","resultsLimit":"10","resultsOrderBy":"title"}

but not found :|

Fatal error: Call to a member function findAll() on a non-object

#16114 report it
Konstantinos Filios at 2014/01/21 07:52am
No argument passed for mandatory parameter

Hi Alexis,

yes, this happens because you have not passed any json body in your request. Supposing your json input would look like this: {"somefield":"somevalue"} you have three options here:

a. You are just trying out stuff, so you can pass your json object as a get parameter, in a simple GET request using the special "jsin" GET parameter:

http://localhost/MovilServices/index.php?r=Product/FindProduct&jsin={"somefield":"somevalue"}

b. You can pass your json as the body of a POST request, but you must also include the Content-Type: application/json header in your request

c. You can make the input object optional, by doing this in your action:

class ProductController
{
    actionFindProduct(JsonClassType $queryJson = null)
 
    {
    }
}

I understand a few of the above details should be documented but I'm currently re-organizing a few things to make the extension more flexible. I'm hoping I'll have more soon enough :)

#16102 report it
Alexis Araya at 2014/01/20 12:36pm
How to use?

Hello,

I tried the following url

http://localhost/MovilServices/index.php?r=Product/FindProduct

but not found, return error

"message":"ProductController::actionFindProduct: No argument passed for mandatory parameter \"queryJson\"", "code":0, "type":"CHttpException",

some idea of ​​the error?

thanks.

#13175 report it
xmvyii at 2013/05/10 03:30pm
restful

My project team co-workers are telling me, i should choose a RESTful service. Although i am a newbie to "modern" web development, and need to ask them, "why" they think that's important. As you've said, yours is not RESTful, and as i understand, the extension was created basically to provide a simple, non-restful JSON request-reply system (service), along with your preferred "style of documentation". Correct me if i'm wrong!

If my team insists or restful, i will probably look into the "How to create a REST api" (on yii) wiki: http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api/

#13170 report it
Konstantinos Filios at 2013/05/10 06:38am
Added demo documentation output

FYI, I split the example in a separate demo link to make the intro page shorter and added a sample api documentation output.

#13166 report it
Konstantinos Filios at 2013/05/10 05:09am
@xmvyii

Hi xmvyii,

thanks for trying the extension. Here are some answers to your questions:

  • The inspiration was on a "requirements" basis, rather than implementation. Where I work we usually consume .NET services which provide a /help page, documenting two things:
    1. The API method signatures, i.e. which methods exist, what types of parameters they accept and what types of objects they return
    2. The documentation about the objects themselves, so whoever consumes a method doesn't have to discover the structure/fields of objects through trial'n'error or direct communication with the method developers

So the implementation guidelines were the following: Provide a mechanism which requires the least extra effort from the JSON API developer and least "modifications" to the standard CController behaviour of Yii (which people are used to) and provides documentation to the API consumers using existing tools (apigen, phpdoc, etc.) without inferior quality, when compared to other languages and platforms.

  • The word "bogo" doesn't really mean anything. Long before Yii appeared, our team used to maintain a php library (arbitrarily) called "bogolib" which provided features similar to Yii's. After recognizing that Yii is a good solution, we replaced bogolib, and any features missing from yii have ever since become "bogo-*-extensions". Those ones which seem to provide generic functionality (not specific to our projects) are progressively contributed to the community wishing it will benefit as we did from it :)

  • About CRUD: We've called this a "JSON-capable" instead of "RESTful" extension, because it's actually not RESTful. It "overloads" the HTTP POST method and helps documenting and exchanging data using the JSON format.

CRUD operations work as you know them, with two major exceptions: 1. Instead of rendering results at the end of your controller, you just return an object. 2. Instead of looking into the $_GET/$_POST variables in your controller (e.g. in your actionCreate or your actionUpdate) you define an input object as a parameter in your action, and work on it as you would.

You made a good point though: I'll try to create an example with simple CRUD operations and add it either in this page or the github wiki. Then I'll take a look at the possible benefits of introducing a scaffolding template for gii.

  • About testing: Actually what you're suggesting makes a lot of sense. The only reason this (ugly in my opinion) testing feature/workaround is simple: Many people are too lazy to open a restclient.

Taking into consideration that GET imposes a limit on the length of the request URL, it's always best to use POST and a rest-client.

  • About supporting: We've based quite a lot of projects on this mechanism, so unless yii2 makes a huge step towards json services (it already has done a very good job for SOAP services), we'll keep supporting it. Just for the record we don't have internal versions of the extensions for ourselves. We use the one we've published as direct git submodules :)

br, kf

#13161 report it
xmvyii at 2013/05/09 04:25pm
general questions about bogo yii json service

Thank you to K.F. for this extension.

i'm somewhat of a newbie. can anyone help with these few questions?

-is bogo yii json service extension, "inspired" on any previous open source code (libraries, etc), or did you create it from scratch expressly for within yii? what is "bogo"? just a random name?

-how can CRUD operations get done, using bogo yii json service?

-by the way, my recommendation for you might be, don't spend time working on the "development/testing" work-around of using $_GET variables, ($_GET['jsin'] etc) instead, recommend a way to send "test" requests, i am thinking: such as: chrome://restclient/content/restclient.html .. it seems a better way, to test, than with $_GET work-around?

-by the way, do you (or anyone) plan on supporting in the future?

Thanks!

#12896 report it
thiswayup at 2013/04/18 04:40pm
It worked!

Looks like that did it!

Thanks!

#12889 report it
Konstantinos Filios at 2013/04/18 04:07am
Fixed ugly reference to $_GET['r']

Hi thiswayup,

thanks for your input, it turns out you were right. It was the debug/logging part which assumed the called controller action is in $_GET['r']. I've uploaded a patch in the latest commit of the master branch.

If you have the chance to verify it works for you, too, please let me know so I upload a revision here, too.

Btw, the documentation I've provided is quite draft, so if you think any addition from my side would help, please let me know.

#12883 report it
thiswayup at 2013/04/17 07:29pm
some help?

Hi

I've just tried to use this as I'm looking at a few rest/json implementations. I'm just basically just return a basic array via the controller at the moment but I seem to be getting the json but also an error message below: https://github.com/thiswayup/yiiRestTest/blob/master/errorOutput.txt

I've also put all the files onto git in the same repo. I wonder if you can give some tips?

Leave a comment

Please to leave your comment.

Create extension