i am creating a web application in cakephp 2.9. it has two use,
To provide API access to android and Ios devices
To serve Web pages(Normal web applicaiton)
currently i am developing the api part , i create a webserviceController.php file and write all the Api , Now i feel like the controller is too fatty,
i dont know which is the best practice to manage API's. now my webservice controllerhave more than 2000 lines of code..
now iam planning to seperate the each api's in different controller
can anyone suggest me a good practice for writing apis in cakephp
currently my code look like
class WebServicesController extends Controller
{
public $uses = null;
public $components = array('RequestHandler', 'Verification', 'AppContstant','PushNotification');
public function users()
{
//code to get users
//
$this->set(array(
'result' => $result,
'_serialize' => 'result'
));
}
and in my route.php
Router::mapResources('WebServices');
Router::parseExtensions();
Router::resourceMap(array(
array('action' => 'users', 'method' => 'GET', 'id' => false),
i have more around 43 api's in webserviceController,
How to manage API's cakephp
What is the best practice?
_serialize vs json_encode() which is fast?
How to versioning my API url ?
The simplest way of making an API in cakephp is print the a JSON directly from the controller and stop the rendering by die().
Official document suggests you to have an API view for the output, which is a standard MVC way and is a good practice. You can check out more here: https://book.cakephp.org/2.0/en/views/json-and-xml-views.html
Maybe you can reference how Croogo implemented it, this is a Cakephp based CMS.
They make API as a component to manage version and methods: https://github.com/croogo/croogo/blob/master/Croogo/Controller/Component/BaseApiComponent.php
This is an example of its URL routing in format /$version/$model/$method.$format/?$parameters
http://www.example.com/croogo-2.2.2/api/v1.0/nodes/lookup.json?type=page&title=how
Sibin Francis, You can use rest api class and include in you api controller
add following line at top
App::import('Vendor', 'REST', array('file' => 'Rest.inc.php'));
Public function yourFunctionName() {
if ($this->request->is("post")) { // Use your method name put/post/get/etc
$rest = new REST();
// Your logic here
return $rest->response(json_encode($data), response_code);
}
}
Its very easy and simple. Only you need to call vendor Rest Api class.
Related
I am new to CodeIgniter and Rest API. I am trying to implement REST API in CodeIgniter and have used Phil Sturgeon's rest-client and rest-server. I have watched few tutorials and have successfully implemented the Rest-Server part (checking with Chrome's Rest Client APP). But, to implement the Rest-Client, I am having few troubles.
Do I need to have cURL and CodeIgniter's cUrl Library?
If yes, how should I set it up?
I watched this tutorial too by Phil Sturgeon but in this tutorial, he has only used the Rest-Client function to call the Server. But not defined where to put it. Here's the code
function rest_client($id){
$this->load->library('rest', array(
'server' => 'http://localhost/rest/index.php/restgetcontroller/',
));
$user = $this->rest->get('user', array('id' => $id), 'json');
echo $user->name;
}
I am sorry if it is too simple.
Thank You
Edit: I made a Client controller and put there a method to call it. But when I load the page, I get this error.
Call to undefined method CI_Loader::spark()
You can use wherever you need to retrieve a value from your API.
$user will have a value you can use for your purpose.
Basically, you would use the API where you used to use a Model, because now the interaction with the database is made with the API, not from your Controllers directly.
To call RESTful APIs you'll require CURL, there's a library called Guzzlehttp to use CURL more efficiently.
You can use composer to install the library or simply download the zip and require it in your controller.
Example Usage:
try {
$guzzleHttp = new GuzzleHttp\Client([
'verify' => false
]);
$http_response = $guzzleHttp->request('GET', 'http://localhost/rest/index.php/restgetcontroller/');
$response = json_decode($http_response->getBody()->getContents());
return $data;
} catch (Exception $e) {
log_message('error', $e->getMessage());
return false;
}
I'm used to have model and form validation together, in another framework. But I'm migrating to Laravel and trying to understand its mindset.
What's the best approach for data validation? I've seen some classes that help out on creating forms and validating requests, but isn't it unsafe to have models saving data without validating it before?
How could I integrate form (frontend), request (backend) and model validation so they all play nicely together? Or this is not done in the Laravel world at all?
As a starter in Laravel myself, I can tell a mind of a learner.
The first thing to understand is that Laravel is very very very very very abstract. It offers you thousands of solutions for a single problem. Since you're just starting out, I'm going to assume you're using Laravel 5 (5.1 to be more specific).
The $this->validate() from Controllers
You can use $this->validate() in your controllers.
class SomeController extends Controller {
public function store(Request $request){
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// This passed validation.
}
}
The Validation Facade
Inside the config/app.php you will find a aliases field that defines the Validator Facade as 'Validator' => Illuminate\Support\Facades\Validator::class. You can make validators from basically anywhere.
public function store(Request $request) {
$validator = Validator::make($request->all(), [
'email' => 'required|unique:emails|email',
]);
if ($validator->fails()) {
// Error logic
}
// Store the blog post...
}
Form Requests
Personally, I like Form Requests. They allow you to reuse validation logic defined once in any controller you feel like it. You can run in your project
php artisan make:request MyCustomRequest
That will generate a new request inside app/Http/Requests where you can write your rules inside the rules method. And then, when you want to use it, just type-hint your controller method.
Here is how to use it:
public function store(CompanyRequest $request){
// This code will only be executed if the rules inside CompanyRequest
// Are true.
}
Here is the file defining CompanyRequest.
class CompanyRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
return [
'name' => 'required|max:255',
'domain' => 'required|max:40'
];
}
}
Conclusion
There are probably a few more ways to do it. You can, for instance, use Validator::make facade from within your Eloquent models. Laravel offers multiple ways of handling basic problems. You just have to find what is best for you and major in it.
I'm not sure this is the best method or not.
But I'm using this concept and its most popular way of validating forms in most popular CMS.
As usual the form action should point to a controller method. Inside controller method you can init a validator class like below.
$validation = \Validator::make(\Input::all(), with(new UserValidation)->getRules());
if ($validation->fails()) {
return redirect()->route('your route path ')->withErrors($validation)->withInput();
}
Then in your controller use the namespace like .
use VendorName\PackageName\validations\UserValidation;
Here I put the validations in a separate folder called validations. Also notice that I'm using Package development concept in Laravel 5.x you can read more about that here.
Then in that UserValidation class you can put all the validation rules.
class UserValidation {
public function getRules() {
return [
'name' => 'required|max:200|unique:client',
'address'=>'required',
'status' => 'required',
];
}
}
This has several advantage the controller looks much neat and validation customization will be entirely separate file.
Also you can split up the route to a separate folder too.
Hope it make sense..
In the end, the best way I found to solve this matter was stitching together two Laravel extensions: Ardent, an Eloquent extension that includes validation, and a fork of Laravalid, that extends the Form with jQuery basic validation: that fork includes Ardent integration.
I'm upgrading a custom solution where I can dynamically register and unregister Web Api controllers to use the new attribute routing mechanism. However, it seems to recent update to RTM break my solution.
My solution exposes a couple of Web Api controllers for administration purposes. These are registered using the new HttpConfigurationExtensions.MapHttpAttributeRoutes method call.
The solution also allows Web Api controllers to be hosted in third-party assemblies and registered dynamically. At this stage, calling HttpConfigurationExtensions.MapHttAttributeRoutes a second time once the third-party controller is loaded would raise an exception. Therefore, my solution uses reflection to inspect the RoutePrefix and Route attributes and register corresponding routes on the HttpConfiguration object.
Unfortunately, calling the Web Api results in the following error:
"No HTTP resource was found that matches the request URI".
Here is a simple controller that I want to use:
[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
[HttpGet]
[Route("one")]
public string GetOne()
{
return "One";
}
[HttpGet]
[Route("two")]
public string GetTwo()
{
return "Two";
}
[HttpPost]
[Route("one")]
public string SetOne(string value)
{
return String.Empty;
}
}
Here is the first solution I tried:
configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");
Here is the second solution I tried:
var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
if (routeAttribute != null)
{
string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
}
}
I also have tried a third solution, whereby I create custom classes that implement IHttpRoute and trying to register them with the configuration to no avail.
Is it possible to use legacy-style route mapping based upon the information contained in the new routing attributes ?
Update
I have installed my controller in a Web Application in order to troubleshoot the routing selection process with the Web Api Route Debugger. Here is the result of the screenshot:
As you can see, the correct action seems to be selected, but I still get a 404 error.
Update2
After further analysis, and per Kiran Challa's comment below, it seems that the design of Web Api prevents mixing attribute routing and conventional routing, and that what I want to do is not possible using this approach.
I have created a custom attribute [RouteEx] that serves the same purpose of the Web Api [Route] attribute, and now my code works perfectly.
I guess, since this is not possible using the conventional attribute routing, none of the answers on this question could legitimately be consisered valid. So I'm not nominating an answer just yet.
You shouldn't be required to use reflection and inspect the attribute-routing based attributes yourself. Attribute routing uses existing Web API features to get list of controllers to scan through.
Question: Before the switch to attribute routing, how were you loading these assemblies having the
controllers?
If you were doing this by IAssembliesResolver service, then this solution should work even with attribute routing and you should not be needing to do anything extra.
Regarding your Update: are you calling MapHttpAttributeRoutes?
I'm developing a RESTful application on Zend Framework 2 basis. Just implemented the get(...) method of the controller:
class SeminarsController extends RestfulController
{
/**
* #var Zend\Db\TableGateway\TableGateway
*/
private $seminarTable;
...
public function get($id)
{
$seminarDetails = $this->getSeminarsTable()->findOnceByID($id)->current();
return new JsonModel(array('data' => array(
'id' => $seminarDetails->id,
'title' => $seminarDetails->title,
'details' => $seminarDetails->details
)));
}
...
}
Works fine. But now it's bound to a hard defined output format -- JSON. How can/should I make it more flexible, in order to enable the user/client to get the output in different formats?
EDIT
What I want to know is, what structure/architecture solution for such case(-s). I'm sure, there are best practices / standard solutions for this problem.
You are looking for a custom view strategy (you can create a custom view strategy to render any kind of response).
There is a great webinar on this by Matthew Weier O'Phinney that you can watch on the Zend website.
If the link doens't work, go to the recorded webinars page and look for "Build RESTful ZF2 Applications".
The webinar contains all information you need including code samples.
I'm trying to create a custom http method in RESTful API. I was reading the documentation and it is said that you can do it buy adding a simple action in controller and then for example conifg your route with child routes with action => action_name but in the code I have spotted addHttpMethodHandler() method in Zend\Mvc\Controller\AbstractRestfulController.php so in controller construct method I have added:
$add = function () {
return new JsonModel(array(
'id' => 2222,
));
};
$this->addHttpMethodHandler('someAction', $add);
var_dump($this->customHttpMethodsMap);
With the var_dump I can see that this new function is added but I just wonder how can I call it or maybe I'm missing the point.
Regards,
I actually wrote a blog post on this because I had so much trouble too.
The problem is that in addition to calling addHttpMethodHandler within the abstract restful controller, you also need to make sure that the Zend Request class knows that your http method exists.
Here is a link to a better explanation: http://richardbrock1.wordpress.com/2013/03/23/custom-http-methods-in-zf2/