Jump to content
clsource

Rest Helper For Processwire

Recommended Posts

Thanks for sharing!

Very interesting how you handle CRUD with this approach?

Share this post


Link to post
Share on other sites

Well basically when you follow the RESTful approach when creating systems, you use resources rather than actions.

you can know more here 

http://restcookbook.com/

http://restpatterns.org/

http://www.restapitutorial.com/

and this books

 https://leanpub.com/build-apis-you-wont-hate

 http://www.soa-in-practice.com/

Example if you want to make an admin for the users resource.

you can have this URL

http://api.example.com/users

In the traditional CRUD  aproach, the verb is inside the URL like

http://api.example.com/users/create

but in REST you must use only HTTP Verbs to interact,

so the same endpoint url makes different actions depending on the verb used to call it.

In our system that could be

http://api.example.com/users

GET - result in a list of users 

POST - creates a new user 

-------------------------------------

http://api.example.com/users/clsource

GET - result in the user data
PUT - updates the all the data of a specific user 

PATCH - updates a specific data field of a specific user
DELETE - deletes the user
 

Using the HTTP response codes and mime types you can notify the result of an operation, usually with a JSON or XML body for information.

The Web services Approach, specially REST web services, enables us to separate complex systems

in smaller ones, easier to mantain and test.

Basically you can have multiple backend systems that just are APIs and one frontend system that glue them all.

this add a layer of security and robustness, because you can separate your systems in different servers. A possible attack can not affect all the system, just small parts of it.

Edited by clsource
  • Like 12

Share this post


Link to post
Share on other sites

Wow! Thanks for the links and your post!

Always try to learn.

Kind Regards mr-fan

  • Like 1

Share this post


Link to post
Share on other sites

could something like this also handled by url segments?

just read:

http://processwire.com/docs/tutorials/how-to-use-url-segments/

segments for GET, PUT, PATCH, DELETE

and the logic within the template file??

so may you have some sort of data like

www.your-pw-site.com/products/

and use url segments for getting is

www.your-pw-site.com/products/get/

data service for external pages could be done via using methods from

http://modules.processwire.com/modules/service-pages/

and put, patch, delete via API in the template?

or did i miss something.

(I'm very new to this topic - but very interested since a friend ask me to setup a bridge between a local (mostly offline) MSSQL server and a mobile App so my ideas walking with a "man in the middle" as a website app that get JSON from the local PC (=sync) and host the data for the mobile App (=sync) ----> O0 )

so sorry for loud thinking here....

Share this post


Link to post
Share on other sites

I'm also quite new to the RESTful approach but i think the whole point is that a given endpoint responds to the various http request methods, so:

www.your-pw-site.com/products/ would respond to http GET by listing the products, and http POST would add a new product.

  • Like 1

Share this post


Link to post
Share on other sites

the basic question is.

Is it possible to put the logic in some helper classes and the/a template file without changing the core?

have to try - need more time----> URGEND need for a paypal "spend more time" account... ;)

Via inside the URL would be a traditional way not REST via http response...like clsource described...

the mainpoint for my hobby project is two-way sync (one direction for now):

1. local MSSQL DB to Webserver via .net send JSON Data to a web adress (->getting the data right is my point of work - i'll try with the import Json addon and some scripts)

2. get the data from the Webserver on a mobile app via JS and JSON (like with the PageWebservice Addon from Ryan) on a next step save it in local store and so on....i've a try with the g00gle APK builder...

so until now i'm sorting what base i will use - more focus on REST (in mind of huge data and different usecases) or get it less or more simple via PHP and GET/POST?

Kind regards mr-fan

Share this post


Link to post
Share on other sites

I'm also quite new to the RESTful approach but i think the whole point is that a given endpoint responds to the various http request methods, so:

www.your-pw-site.com/products/ would respond to http GET by listing the products, and http POST would add a new product.

Yes, The verb is on the Http Request and different responses are given depending on the way you call an endpoint.

could something like this also handled by url segments?

just read:

http://processwire.com/docs/tutorials/how-to-use-url-segments/

segments for GET, PUT, PATCH, DELETE

and the logic within the template file??

so may you have some sort of data like

www.your-pw-site.com/products/

and use url segments for getting is

www.your-pw-site.com/products/get/

data service for external pages could be done via using methods from

http://modules.processwire.com/modules/service-pages/

and put, patch, delete via API in the template?

or did i miss something.

(I'm very new to this topic - but very interested since a friend ask me to setup a bridge between a local (mostly offline) MSSQL server and a mobile App so my ideas walking with a "man in the middle" as a website app that get JSON from the local PC (=sync) and host the data for the mobile App (=sync) ----> O0 )

so sorry for loud thinking here....

If you got 

www.your-pw-site.com/products/

then you can have these methods

GET -> list of products
POST -> create a new product

then if you got this particular product "computer-1"

www.your-pw-site.com/products/computer-1

you can have these methods

GET-> info of computer 1
PUT -> replace all the info of computer 1
PATCH -> replace specific info like name or sku of computer 1
DELETE -> removes computer 1

Now taking that as an example, you can have this way to program and endpoint in Processwire

1.- Create a template named "products" (with a file products.php in templates folder)

2.- Create a page that use that template, and creates  the url www.your-pw-site.com/products/ (Enable UrlSegments)

3.- Now  products.php will be coded like this

Note that Product.php is just a helper class that just have some methods for easier output formatting

<?php
require_once './includes/Rest.php';
require_once './models/Product.php';

// Vars with the default output
$code = 200;
$output = null;
$header = Rest\Header::mimeType('json');

// First check if you have Url segment1
// this segment you can have the product id

if($input->urlSegment1) {
	
	$productId = $input->urlSegment1;
	
	$product = Product::find($productId);
	
	// Check if we found a product
	if(!($product instanceOf NullPage)) {
		
		// Convert the page object to our model
		$product = new Product($product);
		
		// Detects the Verb
		if(Rest\Request::is('get')) {
			
			// json encodeable array
			$output = $product->get();
			
		} else (Rest\Request::is('put')) {
			$params = Rest\Request::params();
			$output = $product->put($params);
			
			// Could be 202 if modification is made async
			// 200 if OK
			// $code = 202;

		} else (Rest\Request::is('patch')) {
			
			$params = Rest\Request::params();
			$sku = $params['sku'];
			
			$output = $product->patch('sku', $sku);
			
			// Could be 202 if modification is made async
			// 200 if OK
			// $code = 202;

		} else (Rest\Request::is('delete')) {
			$output = $product->delete();
		}
		
		// Product not found
	} else {
		$code = 404;
		$output = Product::notFound();
	}

} else {

	// Detects the Verb
	if(Rest\Request::is('get')) {
		$params = Rest\Request::params();
		
		$page = $params['page'];
		
		$output = Product::fetch($page);
		
	} else (Rest\Request::is('post')) {
		
		$params = Rest\Request::params();
		
		// You can get the params like
		// $params['name'], 
		// $params['sku']
		// and so on
		
		$newProduct = Product::create($params);
		
		// Returns and array that can be json encoded
		$output = $newProduct->get();

		// 201 Created
		$code = 201;
	}

} // End if

// Show the response and body
http_response_code($code);
header($header);
echo json_encode($output);
  • Like 3

Share this post


Link to post
Share on other sites

@clsource

Thank you for your REST helper. I'm using it for a project and it is working fine.

For my project I'm using basic HTTP Authetication. I added some code to the params method to fetch username and password and merge it into the $params array. The altered code is here: https://gist.github.com/gebeer/5d1447ff76e17931d944#file-rest-php-L265

For a PUT request I use $session->login() to verify username and password.

		$uId = $input->urlSegment1;

		$u = $users->get($uId);

		if ($session->login($u->name, $params["upass"])) {

			$session->logout();

                        //update user data
                }
 

In the response header of  that request I get some PW cookie data:

Set-Cookie: wire=ha6io723mkfc9v4scdib3oe8g7; path=/; HttpOnly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=1n8faeiva3vg7u13ijsrs24bt1; path=/; HttpOnly wire_challenge=YK0WRw0Wrd2ZAhKEUCLPOHd9iSySEPb91; expires=Tue, 07-Apr-2015 14:11:24 GMT; path=/; httponly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=u9m41s8b87d3ca1jp1jbl0r6k3; path=/; HttpOnly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=oidcbmht561qnvts2fjnq4b7p3; path=/; HttpOnly persist=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/ 

 Can I avoid that somehow other than not using session? In the PW cheatsheet I couldn't find anything related to cookies.

  • Like 2

Share this post


Link to post
Share on other sites

@clsource

Thank you for your REST helper. I'm using it for a project and it is working fine.

For my project I'm using basic HTTP Authetication. I added some code to the params method to fetch username and password and merge it into the $params array. The altered code is here: https://gist.github.com/gebeer/5d1447ff76e17931d944#file-rest-php-L265

For a PUT request I use $session->login() to verify username and password.

		$uId = $input->urlSegment1;

		$u = $users->get($uId);

		if ($session->login($u->name, $params["upass"])) {

			$session->logout();

                        //update user data
                }
 

In the response header of  that request I get some PW cookie data:

Set-Cookie: wire=ha6io723mkfc9v4scdib3oe8g7; path=/; HttpOnly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=1n8faeiva3vg7u13ijsrs24bt1; path=/; HttpOnly wire_challenge=YK0WRw0Wrd2ZAhKEUCLPOHd9iSySEPb91; expires=Tue, 07-Apr-2015 14:11:24 GMT; path=/; httponly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=u9m41s8b87d3ca1jp1jbl0r6k3; path=/; HttpOnly wire=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT wire=oidcbmht561qnvts2fjnq4b7p3; path=/; HttpOnly persist=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/ 

 Can I avoid that somehow other than not using session? In the PW cheatsheet I couldn't find anything related to cookies.

Wow thanks for using this code :D

and thanks for improving it.

Well A technique I use for avoid using sessions is a token and send that token with every request.

I previously created a "token" field inside the user page. So when the user logs in a token (normally sha1) is created

and saved to his token field.

So for example you made a login request and the backend responds with this data.

{
  "status" : "ok",
  "data" : {
     "id" : 142,
     "username" : "clsource",
     "name: "Camilo",
     "token": "abc123"
  }
}

And then you need to update its name

sending a PUT request to the corresponding endpoint

PUT {

   name :  Camilo C.

}

https://api.example.com/v1/users/{token}/profile/name

in this case {token} would be "abc123"

As the token is saved in the user page you can check if the user exists quering by the token

$usr = $users->get("token=$token");

As you may notice the token gives you access for seeing and modifying the user,

so its better to keep it safe. A rule of thumb is creating a token with a 1 hour valid time.

And when the token is invalid you should request a new one in background.

Hope it helps :D

  • Like 5

Share this post


Link to post
Share on other sites

Thank you clsource!

I would like to use PW built in functionality for authenticating my users rather than implementing my own. I am aware though, that the RESTful approach is supposed to work without server side session handling. That is why I only login the user to check if the correct password was sent and then logout of the session instantly.

If there is a way to avoid the Cookie info in the response header, that would be what I'm looking for. If there is none, I will have to rethink my approach and use a token along with the password in the Authentication header. 

Also I'm a bit confused about the cookie data in the response header. wire cookies expire 1970 and there are several of them?

So if anybody can think of a PW API method to suppress cookies, that would be great.

Share this post


Link to post
Share on other sites

Thanks again for your help.

I will give header_remove a try when I'm back at my office and report back here.

Cheers

Gerhard

Share this post


Link to post
Share on other sites
header_remove("Set-Cookie");

did the trick.

I guess this is not the cleanest way of doing it. I opened a new thread to find out how I can suppress cookies in the first place as this is somewhat beyond the scope of this thread here.

Share this post


Link to post
Share on other sites

Thank you!

I am now going with the token approach. That is much cleaner and more REST like.

Share this post


Link to post
Share on other sites

I tried to build something similar a few days ago, but fell over this line:

json_decode(@file_get_contents('php://input')

This does work for x-www-form-urlencoded encoded data, but it fails as soon as you want to send images, which needs the data to be encoded as multipart/form-data. So effectively you can't use PUT to update images in php, especially if you need to send additional data besides the file (authentication). Just wanted to note this here. 

Alternatively one can use the way that backbone.js goes. Just use GET/POST and differ not by http method, but by something like $_POST["_method"] when working with PHP as backend.

  • Like 1

Share this post


Link to post
Share on other sites

Wow!

Really awesome job there clsource.

It really should be in processwire core as RESTful services is gaining attraction lately.

What does ryan think about this?

  • Like 2

Share this post


Link to post
Share on other sites

Welcome to the forum, mosid!

Here is a discussion about RESTful API in PW where Ryan shares his thoughts about it.

And there is Ryan's module Pages Web Service.

I don't think it needs to be in the core. Thanks to PW's modular structure it is easy to implement.

  • Like 1

Share this post


Link to post
Share on other sites

Wow!

Really awesome job there clsource.

It really should be in processwire core as RESTful services is gaining attraction lately.

What does ryan think about this?

Welcome to the forum, mosid!

Here is a discussion about RESTful API in PW where Ryan shares his thoughts about it.

And there is Ryan's module Pages Web Service.

I don't think it needs to be in the core. Thanks to PW's modular structure it is easy to implement.

Thanks @mosid and @gebeer. Yes making a module should not be difficult. Anyway sometime ago I tried to including in the core.

here's a repo with the PW fork that have Rest included. (its outdated)

https://github.com/clsource/ProcessWire/tree/dev

  • Like 1

Share this post


Link to post
Share on other sites

It would be helpful to see some basic examples of how to use the code that clsource and gebeer have created: what a PW template would look like. Or is it already here and I'm being obtuse?

Share this post


Link to post
Share on other sites

It would be helpful to see some basic examples of how to use the code that clsource and gebeer have created: what a PW template would look like. Or is it already here and I'm being obtuse?

I created this helper nearly a year ago! (time passes very fast!).

In the way I learned new tricks and Processwire also have many new things that could improve the rest helper.

So that could be a really good idea.

  • Like 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By abdulqayyum
      Hy Processwire community,
      There are some problem in fileCompiler cache.
      when i change under the directory \site\templates\ it must change under the directory /site/assets/cache/FileCompiler/site/templates/
      but it does not update and functionality working with /site/assets/cache/FileCompiler/site/templates/ directory.
       
      In this case please suggest me how i clear fileCompiler cache?
      what i have to clear it manually?
      Thanks AbdulQayyum.
    • By abdulqayyum
      Hy everyone,
      i am using loginRegister module for front-end user login.
      In this module user can login with Email/username, i am showing with Email. done
      but not showing Email in Forgotton Password section. there still showing with username.

      i want to show Forgotton Password with Email instead username. and should reset with email.

      please help me in this section, how i can set it with Email.

      Thanks AbdulQayyum.
    • By abdulqayyum
      Markup-Google-Recaptcha is not working with LoginRegister module in Forgotton Password Form.
      Here is my code
      wire-> modules -> process -> ProcessForgotPassword.php
      protected function step1_renderForm() {
              $form = $this->modules->get("InputfieldForm");
              $form->attr('action', './?forgot=1');
              $form->attr('method', 'post');
          
              $field = $this->modules->get("InputfieldText");     
              $field->attr('id+name', 'username');
              $field->attr('class', 'redesign-field forgotPassFeild');
              $field->setAttribute('placeholder', 'Username');
              $field->required = true;
              $field->label = $this->_("Forgotton Password");
              $field->description = $this->_("If you cannot remember your password to access the affiliates portal. simply provide your username in the box below and we'll send you a reset link via email.");
              $form->add($field);
               
             // Calling MarkupGoogleRecaptcha Module.
              $captcha = $modules->get("MarkupGoogleRecaptcha");
             //  rendering form with recaptcha
              $captcha->render($form);
         
              $submit = $this->modules->get("InputfieldSubmit");
              $submit->attr('id+name', 'submit_forgot');
              $form->add($submit);
              $this->session->userResetStep = 1;
               
              // rendering form
               $out .= $form->render();
          
              // getting captcha script
              $out .= $captcha->getScript();
              return $out;
          }

      I am following this one example.

      please suggest me how i can show MarkupGoogleRecaptcha in forgotton password.
      Getting log error


      Thanks,
      Abdul Qayyum
    • By Mithlesh
      Hi there,
      My form is not getting submitted, it is showing:
      Unable to verify successful email delivery of this form submission.
      Attaching for your reference as well: 

      In the Backend, it is showing Connection timed out with smtp.gmail.com
      Pl guide me how to resolve that
    • By Sephiroth
      Hi guys, so since I moved to Processwire, it has been my default go-to CMF/CMS for my website and client applications, apparently my previous job took a toll on me, and made me have less time, but now finally had the chance to change my website to something I always had in mind.
      I decided to go with something minimal, as I tend to enjoy writing, so wanted a website to have more text than graphics and I think I whipped up something clean. Currently I still have more to do, but this is my current website, the main purpose to have a content driven website where I will be writing tutorials , articles more and hopefully  technical  notes.
      Please let me know your honest opinion.
      PS: I am more of a coder than a designer but i think this old dog still pulled it off
       
      https://okeowoaderemi.com/
       
       




×
×
  • Create New...