home_site

Lab12 - Styl REST [ ver. TI.2025.12.17.004 ]

Zawartość strony

Styl REST

W ramach laboratorium zostanie opracowany serwis wykorzystujący API REST oraz wykorzystujący dokumentową bazę danych MonogoDB. Część serwerowa zostanie opracowana w języku php a cześć klienta z wykorzystaniem języka JavaScript i technologii AJAX.

Skrót REST oznacza Representational State Transfer, jest określeniem API charakteryzującym się następującymi cechami:
Odseparowanie części serwerowej od klienta
API typu REST służą do budowania wysoce skalowalnych, ale prostych aplikacji WWW. Odseparowanie klienta od API, a zarazem zachowanie ścisłej struktury API ułatwia aplikacjom klienta wysyłanie żądań o zasoby bez możliwości wywoływania baz danych ani uruchamiania logiki działającej po stronie serwera.
Aplikacja serwerowa jest bezstanowa
Zgodnie z projektem API typu REST przyjmują tylko dane wejściowe i zwracają dane wyjściowe. Nie mogą przechowywać żadnego stanu związanego z połączeniem z klientem. Nie oznacza to jednak, że API typu REST nie mogą służyć do uwierzytelniania i autoryzacji. Mechanizm autoryzacji powinien umożliwiać korzystanie z tokenów wysyłanych w każdym żądaniu.
Powinno umożliwiać zapisywanie w danych pamięci podręcznej
Aby odpowiednio skalować aplikacje internetowe, API typu REST muszą z łatwością oznaczać odpowiedzi jako możliwe/niemożliwe do zapisania w pamięci podręcznej. Ponieważ REST ściśle definiuje, jakie dane będą zwracane za pośrednictwem określonych punktów końcowych, mechanizm ten można z łatwością skonfigurować w przypadku poprawnie zaprojektowanych API typu REST. W idealnym rozwiązaniu pamięć podręczna powinna być zarządzana z poziomu oprogramowania, w taki sposób, aby uniemożliwiać przypadkowe przechwycenie uprzywilejowanych informacji przez innego użytkownika.
Punkt końcowy powinien definiować określony obiekt lub metodę
Zwykle są one definiowane hierarchicznie, np. /zasob/id/20210103. Dzięki temu w API typu REST można z łatwością korzystać z metod HTTP takich jak GET, POST, PUT i DELETE. W efekcie punkt końcowy obsługujący wiele metod HTTP nie wymaga dodatkowej dokumentacji.
Lab12_RestFull
Serwis RESTful.

Struktura katalogów uruchamianego serwisu znajduje się poniżej.

-|- vendor ->
 |- stud - | .htaccess
 |         | api.php
 |         | mongo.php
 |         | rest.php
 | client.html
 | rest.js
 | composer.json
 | test_mongo.php         

Baza danych MongoDB

W ramach zadania zostanie zrealizowany dostęp do bazy danych MongoDB z skryptu php. Poniżej znajdują się pliki umożliwiające zrealizowanie zadania.

  1. Przygotowanie środowiska do uruchomienia serwisu wymaga dodania do naszego katalogu biblioteki obsługującej bazę danych MongoDB. Zrealizujemy to poprzez wgranie biblioteki mongodb w katalogu "vendor". Archiwum katalogu znajduje się w pliku "vendor.tar.gz". Dodatkowo należy umieścić plik zawierający informację o dołączonej bibliotece - "composer.json".
    {
        "require": {
            "mongodb/mongodb": "^1.4"
        }
    }
    
  2. Plik mongo.php - realizacja operacji CRUD w bazie danych MongoDB z wykorzystaniem języka php.

    Plik mongo.php - ( [listing dokumentu] [link do dokumentu] )

       <?php
    
    //require 'vendor/autoload.php' ;
    
    class db {
        private $user = "user" ;
        private $pass = "pass";
        private $host = "172.20.44.30";
        private $base = "user";
        private $coll = "student";
        private $conn;
        private $dbase;
        private $collection;
    
    
    
        function __construct() {
          //$this->conn = new Mongo("mongodb://{$this->user}:{$this->pass}@{$this->host}/{$this->base}");
          $this->conn = new MongoDB\Client("mongodb://{$this->user}:{$this->pass}@{$this->host}/{$this->base}");    
          //$this->dbase = $this->conn->selectDB($this->base);
          //$this->collection = $this->dbase->selectCollection($this->coll);
          $this->collection = $this->conn->{$this->base}->{$this->coll};
        }
    
        function select() {
          $cursor = $this->collection->find();
          $table = iterator_to_array($cursor);
          return $table ;
        }
    
        function insert($user) {
          $ret = $this->collection->insertOne($user) ;
          return $ret;
        }
    
        function update($ident,$user,$flag) {
          if ( $flag ) {
             $rec = new MongoDB\BSON\ObjectId($ident);
             $filter = array ( '_id' => $rec );
          } else {
             $filter = array ( 'ident' => $ident );
          }
          $update = array ( '$set' => $user );
          //$option = array ( 'w' => 1 );
          //$ret = $this->collection->update($filter,$update,$option);
          $updresult = $this->collection->updateOne($filter,$update);
          //return $ret['nModified'];
          $ret = $updresult->getModifiedCount();
          return $ret;
        }
    
        function delete($ident,$flag) {
          if ( $flag ) {
             $rec = new MongoDB\BSON\ObjectId($ident);
             $filter = array ( '_id' => $rec );
          } else {
             $filter = array ( 'ident' => $ident );
          }
          //$option = array( 'justOne' => true, 'w' => 1 );
          //$ret = $this->collection->remove($filter,$option);
          $delresult = $this->collection->deleteOne($filter);
          $ret = $delresult->getDeletedCount(); 
          //return $ret['n'];
          return $ret;
        }
    }
      
  3. Plik test_mongo.php - testowanie funkcjonalności opracowanego interfejsu dostępu do bazy danych.

    Plik test_mongo.php - ( [listing dokumentu] [link do dokumentu] )

    <?php
    
    require 'vendor/autoload.php' ;
    include 'stud/mongo.php';
    $db = new db();
    
    print "<pre>" ;
    
    print "Polaczono z baza danych" ;
    
    // Test insert()
    print "Test insert() function <br/>" ;
    $record = array ( 'ident' => 1, 'fname' => 'mirek', 'lname' => 'kowalski', 'faculty' => 'wfiis', 'year' => '2015' ) ;
    $flag = $db->insert($record);
    //print "[ ".$flag." ]";
    print $flag?"OK":"not OK";
    print "<br/>";
    $record = array ( 'ident' => 2, 'fname' => 'adam', 'lname' => 'abacki', 'faculty' => 'wfiis', 'year' => '2015' ) ;
    $flag = $db->insert($record);
    //print "[ ".$flag." ]";
    print $flag?"OK":"not OK";
    print "<br/>";
    
    print "\n<br/>------------ <br/>\n" ;
    
    
    // Test select()
    print "Test select() function <br/>\n" ;
    $data = $db->select();
    print_r($data) ;
    print "\n<br/>------------ <br/>\n" ;
    
    // Test delete()
    print "Test delete() function <br/>\n" ;
    $id =  1  ;
    $flag = $db->delete($id,0) ;
    print "[ ".$flag." ]";
    
    print "\n<br/>----------- <br/>\n" ;
    
    // Test update() 
    print "Test update() function <br/>\n";
    $id =  2  ;
    $data = array ( 'year' => '2016' ) ;
    $flag = $db->update($id,$data,0) ;
    print "[ ".$flag." ]";
    
    print "\n<br/>----------- <br/>\n" ;
    print "</pre>" ;
    
    ?>
      

Serwis RESTful - serwer - język php

W ramach tego zadania zrealizujemy prosty serwis realizujący architekturę RESTful i implementujący funkcjonalność CRUD ( "create, read, update, delete"). Poniżej znajdują się wymagane pliki do realizacji postawionego zadania.

  1. Plik rest.php - interfejs dostępu do naszej aplikacji, klasa obsługująca żądania protokołu http.

    Plik rest.php - ( [listing dokumentu] [link do dokumentu] )

    <?php
    
    class REST {
    		
       public $_allow = array();
       public $_content_type = "application/json";
       public $_request = array();
    		
       private $_method = "";
       protected $_endpoint = "";
       protected $_verb = "";
       protected $_args = Array();
       private $_code = 200;
    		
       public function __construct(){
          $this->inputs();
       }
    		
       public function get_referer(){
          return $_SERVER['HTTP_REFERER'];
       }
    		
       public function response($data,$status){
          $this->_code = ($status)?$status:200;
          $this->set_headers();
          echo $data;
          exit;
       }
    		
       private function get_status_message(){
          $status = array(
    	100 => 'Continue',  
    	101 => 'Switching Protocols',  
    	200 => 'OK',
    	201 => 'Created',  
    	202 => 'Accepted',  
    	203 => 'Non-Authoritative Information',  
    	204 => 'No Content',  
    	205 => 'Reset Content',  
    	206 => 'Partial Content',  
    	300 => 'Multiple Choices',  
    	301 => 'Moved Permanently',  
    	302 => 'Found',  
    	303 => 'See Other',  
    	304 => 'Not Modified',  
    	305 => 'Use Proxy',  
    	306 => '(Unused)',  
    	307 => 'Temporary Redirect',  
    	400 => 'Bad Request',  
    	401 => 'Unauthorized',  
    	402 => 'Payment Required',  
    	403 => 'Forbidden',  
    	404 => 'Not Found',  
    	405 => 'Method Not Allowed',  
    	406 => 'Not Acceptable',  
    	407 => 'Proxy Authentication Required',  
    	408 => 'Request Timeout',  
    	409 => 'Conflict',  
    	410 => 'Gone',  
    	411 => 'Length Required',  
    	412 => 'Precondition Failed',  
    	413 => 'Request Entity Too Large',  
    	414 => 'Request-URI Too Long',  
    	415 => 'Unsupported Media Type',  
    	416 => 'Requested Range Not Satisfiable',  
    	417 => 'Expectation Failed',  
    	500 => 'Internal Server Error',  
    	501 => 'Not Implemented',  
    	502 => 'Bad Gateway',  
    	503 => 'Service Unavailable',  
    	504 => 'Gateway Timeout',  
    	505 => 'HTTP Version Not Supported');
    	return ($status[$this->_code])?$status[$this->_code]:$status[500];
       }
    		
       public function get_request_method(){
          return $_SERVER['REQUEST_METHOD'];
       }
    		
       private function inputs(){
          $this->_args = explode('/', rtrim($_REQUEST['rquest'], '/'));
          $this->_endpoint = array_shift($this->_args);
    
          switch($this->get_request_method()){
    	 case "POST":
    	    //	$this->_request = $this->cleanInputs($_POST);
    	    //	break;
                $this->_request = file_get_contents("php://input") ;
    	    $this->_request = $this->cleanInputs($this->_request);
    	    break;
    	 case "GET":
    	    $this->_request = $this->cleanInputs($_GET);
    	    break;
    	 case "DELETE":
    	    $this->_request = $this->cleanInputs($_GET);
                break;
    	 case "PUT":
                $this->_request = file_get_contents("php://input") ;
                $this->_request = $this->cleanInputs($this->_request);
                break;
    	 default:
    	    $this->response('',406);
    	    break;
          }
       }		
    		
       private function cleanInputs($data){
          $clean_input = array();
          if(is_array($data)){
    	 foreach($data as $k => $v){
    	    $clean_input[$k] = $this->cleanInputs($v);
    	 }
          } else {
    	 //if(get_magic_quotes_gpc()){
    	 //    $data = trim(stripslashes($data));
    	 //}
    	 $data = strip_tags($data);
    	 $clean_input = trim($data);
          }
          return $clean_input;
       }		
    		
       private function set_headers(){
          header("HTTP/1.1 ".$this->_code." ".$this->get_status_message());
          header("Content-Type:".$this->_content_type);
       }
    
    }	
    ?>
      
  2. Plik api.php - klasa implementująca funkcjonalność opracowanej aplikacji.

    Plik api.php - ( [listing dokumentu] [link do dokumentu] )

    <?php
        	
    require '../vendor/autoload.php' ;        
    require_once("rest.php");
    require_once("mongo.php");
    	
    class API extends REST {
    	
    	public $data = "";
    	
    	public function __construct(){
    		parent::__construct();		// Init parent contructor
                  $this->db = new db() ;             // Initiate Database
    	}
    			
    	public function processApi(){
    
    		$func = "_".$this->_endpoint ; 
    		if((int)method_exists($this,$func) > 0) {
    		    $this->$func();
                  }  else {
    		    $this->response('Page not found',404); }			
    	}
    		
    		
    	private function _save() {
    		if($this->get_request_method() != "POST") {
    			$this->response('',406);
    		}
    
    		if(!empty($this->_request) ){
    			try {
                       $json_array = json_decode($this->_request,true);
                       $res = $this->db->insert($json_array);
                       if ( $res ) {
    				   $result = array('return'=>'ok');
    				   $this->response($this->json($result), 200);
                         } else {
                            $result = array('return'=>'not added');
                            $this->response($this->json($result), 200);
                         }
    			} catch (Exception $e) {
    				$this->response('', 400) ;
    			}
    		} else {
    		  	$error = array('status' => "Failed", "msg" => "Invalid send data");
    			$this->response($this->json($error), 400);
    		}
    	}
    
    	private function _list(){	
    		if($this->get_request_method() != "GET"){
    			$this->response('',406);
    		}
            $result = $this->db->select() ;            
    		$this->response($this->json($result), 200); 
    	       //$this->response('',204);	// If no records "No Content" status
    	}
    
        private function _delete0() {
            $this->_delete(0);
        }
    
        private function _delete1() {
            $this->_delete(1);
        }
    	
    	private function _delete($flag){
    		if($this->get_request_method() != "DELETE"){
    			$this->response('',406);
    		}
    		$id = $this->_args[0];
    		if(!empty($id)){				
                         $res = $this->db->delete($id,$flag);
                         if ( $res ) {
    			    $success = array('status' => "Success", "msg" => "Successfully one record deleted. Record - ".$id);
    			    $this->response($this->json($success),200);
                         } else {
                             $failed = array('status' => "Failed", "msg" => "No records deleted" );
                             $this->response($this->json($failed),200);
                         }
    		}else {
    			 $failed = array('status' => "No content", "msg" => "No records deleted" );
                             $this->response($this->json($failed),204);    // If no records "No Content" status
                    }
    	}
           
        private function _update0() {
            $this->_update(0);
        }
    
        private function _update1() {
            $this->_update(1);
        }
    
    	private function _update($flag){
    		if($this->get_request_method() != "PUT"){
    			$this->response('',406);
    		}
    		$id = $this->_args[0];
                    $json_array = json_decode($this->_request,true);;
    		if(!empty($id)){
                         $res = $this->db->update($id,$json_array,$flag) ;				
                         if ( $res > 0 ) {
    			   $success = array('status' => "Success", "msg" => "Successfully one record updated.");
    			   $this->response($this->json($success),200);
                         } else {
    			   $failed = array('status' => "Failed", "msg" => "No records updated.");
    			   $this->response($this->json($failed),200);
                         }                        
    		}else
    			$this->response('',204);	// If no records "No Content" status		
    	}
    
    	private function json($data){
    		if(is_array($data)){
    			return json_encode($data);
    		}
    	}
    }
    		
    	$api = new API;
    	$api->processApi();
    
    ?>
      
  3. Plik .htaccess - plik rzutujący adresy URL żądań RESTful na odpowiednie żądania QUERY_STRING do serwisu w php.

    Plik .htaccess - ( [listing dokumentu] [link do dokumentu] )

    RewriteEngine On
    
    RewriteBase /~antek/TI_2024/lab12/stud/
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-s
    RewriteRule ^(.*)$ api.php?rquest=$1 [QSA,NC,L]
    
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^(.*)$ api.php [QSA,NC,L]
    
    RewriteCond %{REQUEST_FILENAME} -s
    RewriteRule ^(.*)$ api.php [QSA,NC,L]  
  4. Polecenia curl testujące opracowany serwer.
    curl -i -X GET http://pascal.fis.agh.edu.pl/ ... /list
    
    curl -i -d '{"ident":11,"fname":"marek","lname":"cabacki","faculty":"wfiis","year":"2014"}' -X POST http://pascal.fis.agh.edu.pl/ ... /save
    
    curl -i -d '{"year":"2017"}' -X PUT http://pascal.fis.agh.edu.pl/ ... /update0/1
    
    curl -i -X DELETE http://pascal.fis.agh.edu.pl/ ... /delete0/11
    

Serwis RESTful - klient w JavaScript

Ostatnim punktem będzie realizacja klienta dostępu do opracowanego serwisu z wykorzysaniem aplikacji opracowanej w języku JavaScript wykorzystującej technologię AJAX. Poniżej znajdują się pliki do potrzebne do realizacji zadania.

  1. Plik client.html - intefejs graficzny użytkownika aplikacji klienta.

    Plik client.html - ( [listing dokumentu] [link do dokumentu] )

    <!DOCTYPE html>
    <html>
       <head>
          <meta charset="utf-8">
          <title>Ajax: Serwis RESTful</title>
          <script src="rest.js" type="text/javascript"></script>
       </head>
       <body>
         <div style="text-align:center" >
           <table border="1" bgcolor="gray">
             <tr><th><big>Baza danych MongoDB. Operacje CRUD.</big></th></tr>
           </table>
           <br />
           <form action="#">
              <table><tr>
              <td><input type="button" value="Pobranie danych z bazy" onclick="_list()"/></td>
              <td><input type="button" value="Dodanie rekordu do bazy" onclick="_ins_form()"/></td>
              <td><input type="button" value="Usuniecie rekordu z bazy" onclick="_del_list()"/></td>
              <td><input type="button" value="Poprawa rekordu w bazie" onclick="_upd_list()"/></td>
              </tr></table>
           </form>
         </div>
         <div id="data"></div>
         <div id="result"></div>
        </body>
    </html>  
  2. Plik rest.js - funkcje realizujące dostęp do opracowanego serwera REST.

    Plik rest.js - ( [listing dokumentu] [link do dokumentu] )

    var request;
    var objJSON;
    var id_mongo;
    const xhr = new XMLHttpRequest();
    const url = "http://pascal.fis.agh.edu.pl/~antek/TI_2025/lab12/stud/"
    
    
    // Lista rekordow w bazie
    function _list() {    
       xhr.open("GET", url + "list", true);   
       xhr.responseType = 'json';
       xhr.addEventListener("load", e => {
          if (xhr.status == 200)    {
             //objJSON = JSON.parse(request.response);
    		 objJSON = xhr.response ;
             var txt = "";
             for ( var id in objJSON )  {
                 txt +=  id+": {" ;
                 for ( var prop in objJSON[id] ) {             
                     if ( prop !== '_id')
                       { txt += prop+":"+objJSON[id][prop]+",";  }
                     else
                       { txt += "id:" + objJSON[id][prop]['$oid']+"," ; } 
                 }
                 txt +="}<br/>";
             }
    		 document.getElementById('data').innerHTML = '';
             document.getElementById('result').innerHTML = txt;
          }
       })
       xhr.send(null);
    }
    
    // Wstawianie rekordow do bazy
    function _ins_form() {
       var form1 = "<form name='add'><table>" ;
       form1    += "<tr><td>ident</td><td><input type='text' name='ident' value='ident' ></input></td></tr>";
       form1    += "<tr><td>fname</td><td><input type='text' name='fname' value='fname' ></input></td></tr>";
       form1    += "<tr><td>lname</td><td><input type='text' name='lname' value='lname' ></input></td></tr>";  
       form1    += "<tr><td>faculty</td><td><input type='text' name='faculty' value='faculty' ></input></td></tr>";
       form1    += "<tr><td>year</td><td><input type='text' name='year' value='year' ></input></td></tr>";
       form1    += "<tr><td></td><td><input type='button' value='wyslij' onclick='_insert(this.form)' ></input></td></tr>";
       form1    += "</table></form>";
       document.getElementById('data').innerHTML = form1;
       document.getElementById('result').innerHTML = ''; 
    }
    
    function _insert(form)  {
        var user = {};
        user.ident = form.ident.value;
        user.fname = form.fname.value;
        user.lname = form.lname.value;
        user.faculty = form.faculty.value;
        user.year = form.year.value;
        txt = JSON.stringify(user);
        xhr.open("POST", url + "save", true);
    	xhr.setRequestHeader('Content-Type', 'application/json')
    	xhr.addEventListener("load", e => {
           if ( xhr.status == 200 )    {
    		  document.getElementById('data').innerHTML = ''; 
              document.getElementById('result').innerHTML = JSON.stringify(xhr.response);
           }
        })   
        xhr.send(txt);
    }
    
    // Usuwanie rekordow z bazy danych
    function _del_list() { 
        xhr.open("GET", url+ "list", true);	
        xhr.responseType = 'json';	
        xhr.addEventListener("load", e => {
           if ( xhr.status == 200 ) { 
              // objJSON = JSON.parse(request.response);
    		  objJSON = xhr.response ;
              var txt = "<form name='data'><select name='del' size='10'>";
              for ( var id in objJSON ) {
                  txt +=  "<option value="+id+" >"+id+": {" ;
                  for ( var prop in objJSON[id] ) {             
                     if ( prop !== '_id')
                       { txt += prop+":"+objJSON[id][prop]+",";  }
                     else
                       { txt += "id:"+ objJSON[id][prop]['$oid']+"," ;  }
                  }     
                  txt +="}</option>";
              }
              txt += "</select><br/><input type='button' value='usun' onclick='_delete(this.form)'/></form>";
              document.getElementById('data').innerHTML = txt;
    		  document.getElementById('result').innerHTML = ''; 
           }
        })
        xhr.send(null);
    }
    
    function _delete(form) {
        var rec = form.del.selectedIndex;
        var id = document.getElementsByTagName('option')[rec].value;
        var id_mongo = objJSON[id]['_id']['$oid'];     
        xhr.open("DELETE", url + "delete1/"+id_mongo, true);
        xhr.addEventListener( "load", e => {
           if (xhr.status  == 200 )    {
    		   document.getElementById('data').innerHTML = '';
               document.getElementById('result').innerHTML = JSON.stringify(xhr.response);
           }
        }) 
        xhr.send(null);
    }
    
    // Poprawa rekordow w bazie danych
    function _upd_list() { 
           xhr.open("GET", url + "list", true);
           xhr.responseType = 'json';		   
           xhr.addEventListener("load", e => {
             if ( xhr.status == 200 )    { 
               //objJSON = JSON.parse(request.response);
    		   objJSON = xhr.response ;
               var txt = "<form name='data'><select name='del' size='10'>";
               for ( var id in objJSON )  {
                  txt +=  "<option value="+id+" >"+id+": {" ;
                  for ( var prop in objJSON[id] ) {             
                     if ( prop !== '_id')
                       { txt += prop+":"+objJSON[id][prop]+",";  }
                     else
                       { txt += "oid:" + objJSON[id][prop]['$oid']+"," ;  }
                  }    
                  txt +="}</option>";
               }
               txt += "</select><br/><input type='button' value='popraw' onclick='_upd_form(this.form)'/></form>";
               document.getElementById('data').innerHTML = txt;
    		   document.getElementById('result').innerHTML = ''; 
              }
           })
    
           xhr.send(null);
      }
    
    function _upd_form(form) {
        var rec = form.del.selectedIndex;
        id_rec = document.getElementsByTagName('option')[rec].value;
        id_mongo = objJSON[id_rec]['_id']['$oid'];
        console.log(id_mongo); 
        var form1 = "<form name='add'><table>" ;
        form1    += "<tr><td>ident</td><td><input type='text' name='ident' value='"+objJSON[id_rec]['ident']+"' ></input></td></tr>";
        form1    += "<tr><td>fname</td><td><input type='text' name='fname' value='"+objJSON[id_rec]['fname']+"' ></input></td></tr>";
        form1    += "<tr><td>lname</td><td><input type='text' name='lname' value='"+objJSON[id_rec]['lname']+"' ></input></td></tr>";  
        form1    += "<tr><td>faculty</td><td><input type='text' name='faculty' value='"+objJSON[id_rec]['faculty']+"' ></input></td></tr>";
        form1    += "<tr><td>year</td><td><input type='text' name='year' value='"+objJSON[id_rec]['year']+"' ></input></td></tr>";
        form1    += "<tr><td></td><td><input type='button' value='wyslij' onclick='_update(this.form)' ></input></td></tr>";
        form1    += "</table></form>";
        document.getElementById('data').innerHTML = form1;
        document.getElementById('result').innerHTML = ''; 
    }
    
    function _update(form) {
        var user = {};
        user.ident = form.ident.value;
        user.fname = form.fname.value;
        user.lname = form.lname.value;
        user.faculty = form.faculty.value;
        user.year = form.year.value;
        txt = JSON.stringify(user);
        xhr.open("PUT", url + "update1/"+id_mongo, true);
    	xhr.setRequestHeader('Content-Type', 'application/json')	
        xhr.addEventListener("load", e => {
             if ( xhr.status == 200 )    {
    			document.getElementById('data').innerHTML = ''; 
                document.getElementById('result').innerHTML = JSON.stringify(xhr.response);
              }
        })
        xhr.send(txt);
    }
      

Serwis RESTful - node.js, Express

Do realizacji projektu wymagane jest zainstalowanie dwóch pakietów - mongodb i body-parser.

npm install body-parser
npm install mongodb@2.2.33
  1. Na początek utworzymy plik serwera server.js

    Plik server.js ( [listing dokumentu] link do dokumentu )

    const express = require('express');
    const bodyParser= require('body-parser')
    var cors = require('cors')
    const mongodb = require('mongodb')
    var db
    const dbname = 'user';
    const url = 'mongodb://user:pass@172.20.44.25/user';
     
    const app = express();
    app.use(cors({origin:{dotAll:true}}))
    app.use('/client', express.static('public'))
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({extended: true}))
    
     
    mongodb.MongoClient.connect(url, function(err, client) {
      if (err) return console.log(err)
      db = client.db(dbname);
      console.log('Connect OK');
    })
     
    app.listen(<port>,function() {
       console.log('listening on <port>')
    })
     
    app.get('/', function(req,res) {
      res.send('Aplikacja CRUD - node.js')
    })
     
    app.post('/stud', function( req,res ) {
       console.log(JSON.stringify(req.body))
       db.collection('student').insertOne(req.body,function(err,result) {
          if (err) return console.log(err)
          console.log('Rekord dodany do bazy')
          res.end('{"inserted record":"'+result.insertedCount+'"}')
       })
    })
     
    app.get('/stud', function(req, res) {
      var cursor = db.collection('student').find().toArray(function(err, results) {
         if (err) return console.log(err)
         res.end(JSON.stringify(results))
         console.log(results) 
      })
    })
     
    app.get('/stud/:id', function(req,res) {
       console.log(req.params.id)   	
       console.log(req.query)
       if ( req.query.flag && req.query.flag == 1 ) {
         db.collection('student').findOne({ident: req.params.id },function(err,result) {
           if (err) return console.log(err)
           res.end(JSON.stringify(result))
           console.log(result)
         })	 	
       } else {	
         db.collection('student').findOne({_id: new mongodb.ObjectId(req.params.id)},function(err,result) {
           if (err) return console.log(err)
           res.end(JSON.stringify(result))
           console.log(result)
         })	   
       } 
    })
    
    app.delete('/stud/:id',function(req, res) {
       console.log(req.params.id)
       console.log(req.query)
       if ( req.query.flag && req.query.flag == 1 ) {
         db.collection('student').findOne({ident: req.params.id },function(err,result) {
           if (err) return console.log(err)
           res.end(JSON.stringify(result))
           console.log(result)
         })	 	
       } else {	   
         db.collection('student').deleteOne({_id: new mongodb.ObjectId(req.params.id)},function(err,result) {
           if (err) return console.log(err)
           console.log('Rekord usuniety z bazy - '+req.params.id)
           res.end('{"Documents deleted ":"1"}')
         })
       }	 
    })
    
    app.put('/stud/:id',function(req,res) {
       console.log(req.params.id)
       console.log(req.query)
       console.log(req.body)	
       data = req.body
       if ( req.query.flag && req.query.flag == 1 ) {
         db.collection('student').findOne({ident: req.params.id },function(err,result) {
           if (err) return console.log(err)
           res.end(JSON.stringify(result))
           console.log(result)
         })	 	
       } else {	    
         db.collection('student').updateOne({_id: new mongodb.ObjectId(req.params.id)},{ $set: data}, function(err,result) {
           if (err) return console.log(err)
           console.log('rekord poprawiony - '+req.params.id)
           console.log( result.modifiedCount )
           console.log( result.matchedCount )
           res.end('{"Document updated ":"'+result.modifiedCount+'"}')
         })
       }	 
    })
    
      
  2. Poprawność działania serwera sprawdzimy wykorzystując klinta serwisu REST opracowanego w poprzednim punkcie. Wymagana jest tylko modyfikacja punktów końcowych w ramach klienta.

Serwis RESTful - python, Flask

Realizacja projektu jest zrealizowana w środowisku Python Virtual Environment. W tym celu należy utworzyć odpowiedni katalog, przygotować środowisko i pobrać odpowiednie pakiety do realizacji zadania. Poniżej przykładowa realizacja PVE wraz z poleceniami przygotowującymi środowisko uruchomieniowe dla serwera.

mkdir python-lab12
cd python-lab12
python3 -m venv lab12projekt
source lab12project/bin/activate
pip install flask-pymongo
pip install flask-cors
  1. Plik serwera server.py

    Plik server.py ( [listing dokumentu] link do dokumentu )

    from flask import Flask, jsonify, request, Response
    from flask_pymongo import PyMongo
    import json
    from typing import Any
    from bson.json_util import dumps
    from bson import ObjectId
    from flask_cors import CORS
    
    class MongoJSONEncoder(json.JSONEncoder):
        def default(self, o: Any) -> Any:
            if isinstance(o, ObjectId):
                return str(o)
            if isinstance(o, datetime):
                return str(o)
            return json.JSONEncoder.default(self, o)
    
    app = Flask(__name__, static_url_path='/client')
    CORS(app)
    app.config["MONGO_URI"] = "mongodb://user:pass2022@172.20.44.25:27017/user"
    mongo = PyMongo(app)
    
    
    @app.route('/stud', methods=['GET'])
    def get_stud():
        output = []
        cursor = mongo.db.student.find()
        data_json = MongoJSONEncoder().encode(list(cursor))
        return data_json
    	
    @app.route('/stud', methods=['POST'])
    def add_stud():
        data = request.json
        mongo.db.student.insert_one(data)
        return {'result': 'ok'}, 200
    		
    		
    @app.route('/stud/<id>', methods=['PUT'])
    def update_stud(id):
        objId = ObjectId(id)
        data = request.json
        query = { "_id" : objId }
        value = { "$set" : data }
        mongo.db.student.update_one(query, value)
        return {'result':'OK'}, 200		
    	
    @app.route('/stud/<id>', methods=['DELETE'])
    def delete_stud(id):
        objId = ObjectId(id)
        query = { "_id" : objId }
        mongo.db.student.delete_one(query)
        return {'result':'OK'}, 200	
    	
    if __name__ == '__main__':
        app.run(host='149.156.109.180', port=<port>)
      
  2. Poprawność działania serwera sprawdzimy wykorzystując klinta serwisu REST opracowanego w poprzednich punktach. Wymagana jest tylko modyfikacja punktów końcowych w ramach klienta.

Linki do uruchomionych przykładów na serwerze Pascal

Linki dostępne z sieci wydziałowej.