{
"name": "Alexandru PΔvΔloi",
"nickname": "PΔvΔ",
"age": 26,
"labPage": "iampava.com/web-technologies",
"slides": "iampava.com/slides/web-technologies-2021",
"email": "pava@iampava.com"
}
{ about you }
β HTML
β CSS
β JavaScript
π₯ will have acquired confidence to start basic Web projects on your own
π will have worked on a personal project which showcases your skills
π will have worked with multiple colleagues and thus grow your team-work skills
π will have learned the fundamentals of the Web
π you'll have to do a lot of learning outside lab hours
β ask questions whenever something is unclear
π¨βπ» you'll have to do a lot of coding -> that's why we have the "homework" exercises
β Projects will be published soon on https://iampava.com/web-technologies β‘ teams of 2 or 3
β If you don't like any of them, feel free to submit one yourselves
β Read more about the projects & evaluation here: https://profs.info.uaic.ro/~busaco/teach/courses/web/
VS Code
Firefox
glitch.com
codepen.io
Every week I'll post in-advance exercises for the next lab!
OK, let's do this!
β JavaScript
β PhP
β C#
...
usually a browser, but not always!
built in pretty much any language we can think of
This
is
<img src="...">
<p> Lorem ipsum...</p>
Self-closing
Needs a closing tag!
<img src="/bob.png">
<p>
Hi!
<img src="bob.png">
</p>
Elements can have attributes
Or contain other elements
<button
data-speed="1"
type="button"
>
1x
</button>
... or custom attributes!
<!DOCTYPE html>
<html>
<head>
<!-- ... -->
</head>
<body>
<!-- ... -->
</body>
</html>
Elements that describe our website or links to other resources.
<title> FrontEnd.ro </title>
<meta
name="description"
content="ΓnvaΘΔ FrontEnd"
/>
<meta property="og:image" content="https://frontend.ro/main-seo-image.jpg" />
<meta property="og:image:type" content="image/jpeg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<link rel="stylsheet" href="/style.css" />
and others...
Elements that are part of the page and with which the user can interact with. This means most HTML elements
β Containers
header, main, footer, aside, section, div, ul, li
* most used elements
β Text
h1, h2, h3, p, span, strong, pre, code
β Media
img, picture, video, audio
β Forms
form, label, input, select, textarea
β Actions
a, button
β OrganizingΒ most web pages
<header>
<main>
<footer>
<aside>
β If there's an <img>, let there be an alt
<img src="/images/avatar.png"
alt="Bob's avatar" />
β If it takes you to another page it's an anchor
<a href="/settings"> Settings </a>
β If it does something when clicking it, it's a button
<button type="button">
Save progress
</button>
β Always put labels on inputs
<label>
<span> Email or username*</span>
<input type="text" name="emailOrUsername">
</label>
β If there's an input, there should be a form
β Aaaand, if there's a form β‘ add a submit input/button
<form>
<label>
<span> Email or username*</span>
<input type="text" name="emailOrUsername">
</label>
<button type="submit"> Login </button>
</form>
β Keep HTML as minimalist as possible! NO, REALLY!
π https://linkedin.com
PS: check DevDrive over the weekend for practice exercises
Week #2
border: 5px solid black;
background: blue;
value
property
β percentage (%)
β vh/vw
β em
β rem
β px
Β
Β
...
Try to avoid fixel px dimensions whenever
My favorite β€
<p style="font-weight: bold">
A simple styled paragraph...
</p>
* most
<html>
<head>
<style>
h1 {
text-align: center;
}
</style>
</head>
<body>
<h1> Smth </h1>
</body>
</html>
* most
<!-- index.html -->
<html>
<head>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1> Smth </h1>
</body>
</html>
/* style.css */
h1 {
text-align: center;
}
* most
@media screen and (max-width: 500px) {
nav {
background: blue;
border: 5px solid black;
}
}
@media screen and (orientation: landscape) {
nav {
width: 100%;
}
}
@media (prefers-color-scheme: dark) {
body { background: black; }
h1, h2, h3 {
color: #fff;
}
}
@media (prefers-color-scheme: dark) {
header,
footer,
main {
color: #fff;
background: #000;
}
}
Determines weather it's block or inline and the inner layout for it's children.
all the available width. Next element will come below
just the width it needs. Next element comes inline
just like inline-block, only that width/height have no effect
the go-to method for semi-complex layouts.
β Make sure you LEARN & USE IT in the project!
Where to "position" an element inside the our Website.
Default position of all elements.
β from Top to Bottom
β from Left to Right
Position it based on some parent's/ancestor's position
The first one with a position other than static
{
top: 1em;
right: 10%;
bottom: 20px;
left: 2vh;
}
Position it relative to it's default static position
#1 Slightly adjust it's position by a couple of units
#2 To absolute position children according to itself
Usecases
Position it based on the viewport or the first ancestor with a transform property.
Scroll to top button on blogs
Fixed side content, ads, etc
Usecases
{
transform: scale(1.5);
/* transform: rotate(10deg); */
/* transform: translateX(5em); */
/* ... */
}
Default (static) position until the scroll reaches it. Then it sticks!
Extra prop: "transform"
Extra prop: "transform"
<p>
Text
<span> Help info </span>
</p>
Help info
Extra prop: "background"
<main>
<div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</main>
*Pseudo-selector: nth-child
@media screen and (max-width: 500px) {
}
PS: check DevDrive over the weekend for practice exercises
Week #3
flex
items
Flex Container
.gallery {
display: flex;
flex-flow: row wrap;
/* row no-wrap; column wrap; ... */
justify-content: space-between;
/* space-evenly; center; ... */
align-items: center;
/* space-between; space-evenly;... */
}
Which HTML element/elements we want to style?
* {
font-family: sans-serif;
}
h1,
h2,
h3 {
text-align: center;
}
<button type="button"> Log In </button>
<button type="button"> Register </button>
<button type="button"> Sign Out </button>
<button type="button" class="btn-round">
Log In
</button>
<button type="button" class="btn-round">
Register
</button>
<button type="button" class="btn-green">
Sign Out
</button>
.btn-round {
border-radius: 50%;
}
.btn-success {
color: #fff;
background: green;
}
<p id="hello">
A simple styled paragraph...
</p>
<style>
#hello {
font-weight: bold;
}
</style>
It's all about how specific you are!
<img
class="square-image round-image"
id="profile" src="user.jpg"
alt="user profile"/>
<style>
img {
border: 1px solid black;
}
.round-image {
border-radius: 50%;
border: 5px dotted red;
}
.square-image {
border-radius: 0;
border: 5px dashed green;
}
#profile {
border: 2px solid blue;
}
</style>
1)#ID
2).Class
3) TagName
π₯ !important
<style>
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<p class="red blue"> Bob </p>
<p class="blue red"> Alice </p>
<style>
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<p class="red blue"> Bob </p>
<p class="blue red"> Alice </p>
Hmmmmm...?!
.raining .human {
/*
"human" class elements
inside "raining"-class elements
*/
display: hidden;
position: under-blanket;/
}
.valentines.in-love {
/*
both "valentines" & "in-love"
classes
*/
text-decoration: make-up;
}
main > .card {
/*
* Elements with class 'card' which
* are a direct child of a
* 'main' element
*/
}
BEM is naming pattern to keep our CSS clean and our minds sane! π
Elements that make sense on their own.
eg: image gallery, login form on home page...
<body>
<div class="gallery">
</div>
</body>
They make sense only as part of a block.
eg: image in an image gallery, form group in a form, etc
<body>
<div class="gallery">
<img class="gallery__image" />
</div>
</body>
An element or a block might have a certain state, like success, error, etc
<div class="gallery">
<img class="gallery__image" />
<img class="
gallery__image
gallery__image--downloaded
" />
</div>
PS: check DevDrive over the weekend for practice exercises
Week #4
.gallery {
display: flex;
flex-flow: row wrap;
}
.gallery img {
width: 30%;
margin-top: 1em;
margin-bottom: 1em;
}
@media screen and (min-width: 500px) {
.gallery img:nth-child(2) {
margin-left: 5%;
margin-right: 5%;
}
}
@media screen and (max-width: 500px) and (min-width: 350px) {
.gallery img {
width: 45%;
}
.gallery img:nth-child(2n + 1) {
margin-right: 10%;
}
}
@media screen and (max-width: 350px) {
.gallery img {
width: 100%;
}
}
#logo {
tranform: scale(1.1) rotate(35deg);
transform-origin: center;
}
.5 sec
#logo {
transition: transform .5s ease-in;
}
#logo:hover {
transform: scale(1.1);
}
property
timing function
duration
A
A
A
A
#logo {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg)
}
}
iteration count
PS: check DevDrive over the weekend for practice exercises
Week #5
Download and install XAMPP if you've chosen PHP!
π Download link
β we can have PHP only files or mix them with HTML for inserting content into the page
<!DOCTYPE html>
<html lang="en">
<head>
<title>PHP & HTML</title>
</head>
<body>
<h1> Some header </h1>
<?php
$today = date('d/m/Y');
echo "<h2> Today is " . $today . "</h2>";
?>
</body>
</html>
index.php
all variables must start with $
concatenate strings with . operator
β there are no type-declarations needed when we create new variables
<?php
$name = 'Bob';
$age = 31;
$isMarried = false;
// ...
β Arrays are actually key-value pairs & the keys don't necessarily have to be numbes, as we are used to
<?php
$phones = ['Bob' => 0740000000];
echo sizeof($phones); // 1
$loteryNumbers = [11, 5, 3];
$loteryNumber['smth'] = 'smth else';
echo sizeof($loteryNumbers); // 3
foreach($loteryNumbers as $element) {
echo $element;
}
β PHP has support for OOP style programming via Classes
<?php
class Human {
public function __construct($name, $age) {
$this -> name = $name;
$this -> age = $age;
}
public function greet() {
echo 'Hello! I am ' . $this -> name . '. Nice to meet you!';
}
}
class Programmer extends Human {
public function __construct($name, $age, $preferedLanguage) {
parent::__construct($name, $age);
$this -> preferedLanguage = $preferedLanguage;
}
public function code() {
echo 'Nom nom, I am coding in ' . $this -> preferedLanguage;
}
}
$fiiDeveloper = new Programmer('Bob', 31, 'PHP');
$fiiDeveloper -> greet();
echo '<br/>';
$fiiDeveloper -> code();
?>
β Add a action attribute to the form specifying the path the the PHP script handling the submit
β Add a method attribute to the form configuring what HTTP Verb to use (usually GET or POST)
On the client
On the server
β Use the global arrays $_GET or $_POST to read the submitted data
β Add the name attribute to all inputs/textareas/selects so that the server can read their values
JSON is one of the most popular data formats out there, used frequently on the Web to exchange data from client-server. - Working with JSON
<?php
$jsonAsText = file_get_contents("./gallery.json");
$galleryArr = json_decode($jsonAsText);
foreach($galleryArr as $image) {
echo '<div>
<img src="'. $image -> src. '">
<p>'. $image -> description .'</p>
</div>';
}
?>
index.php
[{
"src": "./images/barcelone.png",
"description": "Sunset in Barcelone",
"date": "22 June 2019"
}, {
"src": "./images/madrid.png",
"description": "Quiet street in Madrid",
"date": "23 June 2019"
}]
gallery.json
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Calendar.php</title>
<style>
body {
font-family: sans-serif;
}
li {
margin: .5em 0;
}
</style>
</head>
<body>
<?php
include_once './calendar.class.php';
$myCalendar = new Calendar();
// Add next week's schedule
$myCalendar -> add('04 Apr 2021', '09:00AM', 'Team coffee');
$myCalendar -> add('03 Apr 2021', '2:00PM', 'TW Grupa B3');
$myCalendar -> add('03 Apr 2021', '12:00PM', 'TW Grupa X');
$myCalendar -> add('03 Apr 2021', '10:00AM', 'TW Grupa B1');
$myCalendar -> add('02 Apr 2021', '6:00PM', 'Prepare for TW');
// Get next week's schedule
$nextWeekSchedule = $myCalendar -> getSchedule('01 Apr 2021', '05 Apr 2021');
echo '<h1> Next week: </h1> <ul>';
foreach($nextWeekSchedule as $entry) {
printEntry($entry);
};
echo '</ul>';
// Get the schedule for Apr 3rd
$apr3 = $myCalendar -> getSchedule('03 Apr 2021');
echo '<h1> On 3rd Apr: </h1> <ul>';
foreach($apr3 as $entry) {
printEntry($entry);
};
function printEntry($entry) {
echo '<li>
Date: <strong>'. $entry -> date .'</strong> |
Time: <strong>'. $entry -> time.'</strong> |
Description: <strong>'. $entry -> description .'</strong>
</li>';
}
?>
</body>
</html>
Implement the Calendar class so that the code above runs flawlessly and outputs
PS: check DevDrive over the weekend for practice exercises
Week #6
MVC is one of the most popular back-end patterns out there, and the one I recommend when building your project. π₯
β this is where all the interaction with our database happens (storing & retrieving data) β consists of Classes/Objects/Functions depending on your app β is passed by the Controller to the View for Rendering
β what the User sees and interacts directly with β will render part of the model/models β should only contain very simple logic, like iterating through data and simple if-else
β where the logic happens β it connects the Model with the appropriate View based on the URL β it also responds to form submit and decides what view to render next
PS: check DevDrive over the weekend for practice exercises
π Week 8 deadline: 11 Apr 2021
Week #7
Information about a user stored on it's computer (in the browser).
Β
Primarily used to track us all over the internet... π
<?php
$preferredLang = 'RO';
setcookie("PreferredLanguage", $preferredLang, time() + 3600);
?>
<?php
if(!isset($_COOKIE['PreferredLanguage'])) {
echo 'No cookie set';
} else if($_COOKIE['PreferredLanguage'] === 'RO') {
echo 'Salut';
} else {
echo 'Hello';
}
Setting up a cookie that expires in 1 hour regarding the language preference
Reading the cookie later in a different page
Similar to cookies but they store information about a user on the server.
How do they work? π€
β A cookie having a unique ID - calledΒ Session ID - is stored on the client (browser)
β On the server there's some data attached to that ID
β When the user goes back to the server, the cookie is read and thus the data attached to that ID is found and can be accessed
<?php
/**
START - Persist session for 2 hours,
even after closing the browser.
Needs to be called only once, when starting the server.
*/
$TWO_HOURS = 60 * 60 * 2;
ini_set('session.cookie_lifetime', $TWO_HOURS);
ini_set('session.gc_maxlifetime', $TWO_HOURS);
session_start();
if(isset($_SESSION['count'])) {
$_SESSION['count'] ++;
} else {
$_SESSION['count'] = 1;
}
echo $_SESSION['count'];
?>
Continuing from our gallery exercise last week, let's add πͺ Cookies to persist the date
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Gallery.php</title>
<link rel="stylesheet" href="./gallery.css">
</head>
<body>
<header>
<h1> Gallery.php </h1>
</header>
<main>
<form action="." method="POST">
<div>
<label for="date">Date </label>
<input type="date" name="date" id="date" value="<?php
if(isset($_POST['submit'])) {
echo $_POST['date'];
}
?>">
</div>
<button type="submit" name="submit">Filter by date </button>
</form>
<div class="gallery">
<?php
$filter = NULL;
if(isset($_POST['submit'])) {
$filter = $_POST['date'];
}
$images = json_decode(file_get_contents('./gallery.json'));
foreach($images as $i) {
if(!$filter || strtotime($i -> date) === strtotime($_POST['date'])) {
echo '
<div>
<img src="'. $i -> src .'" alt="'. $i -> description.'" >
<p>Date: '. $i -> date .' </p>
</div>
';
}
}
?>
</div>
</main>
</body>
</html>
[
{
"src": "https://images.unsplash.com/photo-1593642532009-6ba71e22f468?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
"description": "Laptop",
"date": "10 Mar 2021"
},
{
"src": "https://images.unsplash.com/photo-1615125468484-088e3dfcabb6?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw3fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"description": "Car",
"date": "11 Mar 2021"
}
]
gallery.json
index.html
Implement a simplistic user login using Sessions
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User login</title>
</head>
<body>
<form method="POST" action="">
<label>
<span> Username </span>
<input type="text" name="username" required />
</label>
<label>
<span> Password </span>
<input type="password" name="password" required />
</label>
<button type="submit">Login</button>
</form>
</body>
</html>
<?php
$CONFIG = [
'servername' => "localhost",
'username' => "root",
'password' => '',
'db' => 'test'
];
$conn = new mysqli($CONFIG["servername"], $CONFIG["username"], $CONFIG["password"], $CONFIG["db"]);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
} else {
echo "Successfully connected to DB";
}
?>
π Connecting to a MySQL database π
We're using Prepared Statement to prevent this π
<?php
$username = "Bob";
$pass = "12345";
$insertStatement = $conn -> prepare("INSERT INTO users VALUES(?, ?)");
$insertStatement -> bind_param("ss", $username, $pass);
$insertStatement -> execute();
$insertStatement -> close();
?>
<?php
$getUsersStatement = $conn -> prepare("SELECT * FROM users WHERE username = ?");
$getUsersStatement -> bind_param("s", $username);
$getUsersStatement -> execute();
$users = $getUsersStatement -> get_result();
foreach($users as $row) {
echo $row['username'];
echo ' -- ';
echo $row['password'];
echo '<br/>';
}
?>
<?php
$countUsersStatement = $conn -> prepare("SELECT COUNT(username) FROM users");
$countUsersStatement -> execute();
$row = $countUsersStatement -> get_result() -> fetch_row();
echo "We have " . $row[0] . " rows";
?>
Let's use the same Gallery exercise as before and instead of a JSON file, let's use an SQL Database
PS: check DevDrive over the weekend for practice exercises
Week #9
There are multiple methods for Authentication suitable in different scenarios
β APP Authentication
β API Authentication
β "on my behalf" authentication
API Key
Session Cookies
JWT
OAuth
π¨βπ» DIY
Identity Management Solutions (eg: Auth0)
Β
Β
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./app.css" />
<title>Home page</title>
</head>
<body class="home-page">
<header>
<h1> Home Page </h1>
</header>
<main>
<form method="" action="">
<label>
<span> Username*</span>
<input required type="text" name="username">
</label>
<label>
<span> Password*</span>
<input required type="password" name="password">
</label>
<button type="submit">
Sign in
</button>
</form>
</main>
</body>
</html>
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
body * {
font-family: inherit;
}
h1 {
font-size: 4em;
}
h2 {
font-size: 3em;
}
h3 {
font-size: 2.5em;
}
a {
font-size: 1.5em;
text-decoration: none;
font-family: inherit;
border-bottom: 2px solid currentColor;
color: rgb(3, 169, 244);
font-weight: bold;
}
header {
position: relative;
color: #fff;
text-align: center;
padding: 0.5em 0;
background: rgb(3, 169, 244);
}
header h1 {
margin: 0;
}
header a {
color: #000;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 2em;
}
.home-page main {
display: flex;
margin-top: 10em;
flex-flow: row wrap;
justify-content: space-around;
}
.home-page img {
max-width: 10em;
}
.home-page main a {
text-align: center;
}
/* Product page */
.product-page main {
display: flex;
align-items: center;
flex-flow: row nowrap;
justify-content: space-around;
min-height: calc(100vh - 7em);
}
.product-page img {
max-width: 50%;
max-height: 50vh;
}
.not-found-page {
text-align: center;
padding: 0 3em;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.not-found-page h1 {
margin-top: 0;
}
.not-found-page a {
margin-top: 2em;
}
.not-found-page h3 {
font-weight: normal;
}
label {
margin: 2em 0;
display: block;
}
label > span {
display: block;
font-weight: bold;
}
input {
padding: 0.5em;
border-radius: 0.5em;
}
PS: check DevDrive over the weekend for practice exercises
Week #10
The DOM is a tree-like structure representing an XML document.
Β
Most often though, you'll hear about it in the context of HTML but it applies to any XML document.
The DOM provides us with an API (functions) through which we'll interact with it. And since it's a standard, those functions are the same in any programming language.
<?php
$dom = new DOMDocument();
$p = $dom -> createElement('p');
$p -> textContent = 'I am a paragraph';
$img = $dom -> createElement('img');
$img -> setAttribute('src', 'https://www.info.uaic.ro/wp-content/uploads/2019/05/cropped-engl-100x600v2.png');
$img -> setAttribute('alt', 'UAIC logo');
$p -> appendChild($img);
$dom -> appendChild($p);
echo $dom -> saveXML();
PHP example of using DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM</title>
</head>
<body>
<script>
var p = document.createElement('p');
p.textContent = 'I am a paragraph';
var img = document.createElement('img');
img.setAttribute('src', 'https://www.info.uaic.ro/wp-content/uploads/2019/05/cropped-engl-100x600v2.png');
img.setAttribute('alt', 'UAIC logo');
p.appendChild(img);
document.body.appendChild(p);
</script>
</body>
</html>
JS example of using DOM
πSee, the exact same functions!
Write a simple crawling app which retrieves an URL and displays an information card with the title, description and cover image of that page, similar to how social-networks display links you share.
π‘ Hints:
use the built-in file_get_contents function to retrieve the HTML as a string
use DOMDocument and loadHTML, getElementsByTagName, getAttribute functions to parse & find the elements you need
for title β‘ search for the <title> tag & retrieve it's textContent
for description β‘ search for a <meta name="description"> tag & retrieve it's content attribute
for cover image β‘ search for a <meta property="og:image"> tag & retrieve it's content attribute. If it doesn't exist, find the first <img> tag in the page and return that image.
PS: check DevDrive over the weekend for practice exercises
Week #11
A Web service is a software system designed to support machine-to-machine interaction over a network.
Web Services are similar to real-life services.
Β
For example: we have Food Delivery Services so that we don't have to drive to the store. Similarly, OpenWeatherMap offers weather information, or AWS S3 offers a Storage Service.
π What I love about Web Services is that you can combine them and create brand new products.
These types of products are called "mash-ups".
β Maps Service
β Weather Service
show realtime weather information on the Map so you can plan your trip
When creating a Web Service it is recommended to follow a set of patterns & best practices.
Β
There are 2 main approaches SOAP & REST. We'll be talking with both in the following time.
βit can be adapted to any communication protocol, not just HTTP
βthe functionality provided by the Service (including data types) is described in WSDL
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header> </soap:Header>
<soap:Body>
<m:GetStockPrice xmlns:m="http://www.example.org/stock/Surya">
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
βtransfered information (for both request and response) must be in XML format and should respect a standard format of Envelope, Headers and Body
Using WSDL to describe the service π
PHP already has two utility classes SoapServer and SoapClient for easily building and talking to SOAP Services.
Here's a demo of using them to build a dummy Game of Thrones Service (no spoilers π )
<?php
$client = new SoapClient(NULL, [
"location" => "http://localhost:8080/got-service.php",
"uri" => "http://got-soap-service.com"
]);
// var_dump($client -> __getFunctions());
// var_dump($client -> __getTypes());
echo $client -> getEpisodesCount() . "<br/>";
$episode = $client -> getSynopsis(62);
echo $episode -> name . ": " . $episode -> description;
Client
<?php
$service = new SoapServer(NULL, [
"uri" => "http://got-soap-service.com"
]);
class Episode {
public $name;
public $description;
public function __construct($name, $description)
{
$this -> name = $name;
$this -> description = $description;
}
}
class GotService
{
public function getSynopsis($episodeNo)
{
if ($episodeNo === 62) {
return new Episode(
"Battle of the bastards",
"Fight between good and evil!"
);
}
return null;
}
public function getEpisodesCount()
{
return 73;
}
}
$service->setObject(new GotService());
$service->handle();
Server
We haven't used Headers yet so let's modify our example by adding authentication
βthe Client will need to send a header named CustomAuthHeader with two propertis: username & pass
βthe Server will read this header and only allow access to the getSynopsis function if the credentials match
<?php
$client = new SoapClient(NULL, [
"location" => "http://localhost:8080/got-service.php",
"uri" => "http://got-soap-service.com"
]);
// var_dump($client -> __getFunctions());
// var_dump($client -> __getTypes());
class CustomAuthHeader
{
public $username;
public $pass;
public function __construct()
{
$this->username = "bob";
$this->pass = "1234";
}
}
$header = new SoapHeader(
"http://got-soap-service.header.com",
"CustomAuthHeader",
new CustomAuthHeader()
);
$episode = $client->__soapCall("getSynopsis", [
[
"seasonNo" => 6,
"episodeNo" => 3
]
], NULL, [$header]);
echo $episode -> name . ": " . $episode -> description;
Client
<?php
$service = new SoapServer(NULL, [
"uri" => "http://got-soap-service.com"
]);
class Episode {
public $name;
public $description;
public function __construct($name, $description)
{
$this -> name = $name;
$this -> description = $description;
}
}
class GotService
{
private $isAuthenticated = false;
public function CustomAuthHeader($header)
{
if (
$header->username === "bob" &&
$header->pass === "1234"
) {
$this->isAuthenticated = true;
}
}
public function getSynopsis($args)
{
if (!$this->isAuthenticated) {
throw new Error("Must be authenticated!");
}
if ($args['seasonNo'] === 6 && $args['episodeNo'] === 3) {
return new Episode(
"Battle of the bastards",
"Fight between good and evil!"
);
}
return null;
}
public function getEpisodesCount()
{
return 73;
}
}
$service->setObject(new GotService());
$service->handle();
Server
Implement a Calendar Meetings Service for your company using SOAP. You have one or more rooms and in each room can be only one meeting at the same time.
The Service should offer the following functions:
We want the bookMeetingΒ function to only be accessed by authorized users, so implement a mock authentication using SoapHeader.
PS: check DevDrive over the weekend for practice exercises
Week #12
ful
REpresentational
State Transfer
REST
=
The computational results are actually resource representations
each resource representation has an associated URL
clients interact with those resources via http verbs
https://demo.app/v3/users
https://demo.app/v3/users/iampava
{
"users": [{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}]
}
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}
π Accept: application/json
https://demo.app/v3/users/iampava/settings
{
"theme": "light-gray",
"notifications": false
}
https://demo.app/v3/users/
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png",
"id": 1234
}
https://demo.app/v3/users/1234
When designing REST APIs, the GET, PUT and DELETE methods must be idempotent
multiple identical requests have the same effect as a single one
Apart from REST APIs, idempotency is a valuable practice when building cron-jobs
eg: when building weekly jobs that notifies users via Email, it's critical to make it idempotent, in case a bug gets it to trigger twice
π Chuck Norris API π Dog Ceo API
1. I LIVE CODE
<?php
// echo "hello! from api";
$requestUri = $_SERVER["REQUEST_URI"];
$requestMethod = $_SERVER["REQUEST_METHOD"];
$response = [
"uri" => $requestUri,
"method" => $requestMethod
];
// β
-> URL
// β
-> method (GET, POST, PUT, etc?)
// β
-> payload (body) | if any?
// -> headers
$bodyString = file_get_contents("php://input");
if ($bodyString) {
$response["body"] = json_decode($bodyString);
} else {
$response["body"] = "N/A";
}
$allHeaders = getallheaders();
if (isset($allHeaders["Accept"])) {
if ($allHeaders["Accept"] == "text/plain") {
echo "Text plain: ". $response["uri"] . "," . $response["method"];
header("Content-Type: text/plain");
} else if($allHeaders["Accept"] == "text/html") {
echo "<html><body>Text plain: ". $response["uri"] . "," . $response["method"]."</body></html>";
header("Content-Type: text/html");
} else {
echo json_encode($response);
header("Content-Type: application/json");
}
} else {
echo json_encode($response);
header("Content-Type: application/json");
}
http_response_code(401);
// β
<- status code
// β
<- headers
// β
<- body
2. WE LIVE CODE
/got_api/key
{
"key": "ZO5zFDWk"
}
Retrieve a secret key which allows you to call this API 5 times.
/got_api/season/${s_no}/episode/${e_no}
π Authorization: Bearer {secret_key}
Add details to that episode
{
"title": "Battle of the bastards",
"length": 61
}
or
or
/got_api/season/${s_no}/episode/${e_no}
π Authorization: Bearer {secret_key}
Get details about an episode in the requested format
or
or
π Accept: application/json || text/html
PS: check DevDrive over the weekend for practice exercises
Week #13
Before AJAX we were stuck to this π
Fat
Server
Thin
Client
But now, we have a choice between π and π
Thin
Server
Fat
Client
Or variations in between *
I code
Let's ask for a Chuck Norris joke and add it to a simple HTML page.
<!DOCTYPE html>
<html lang="en">
<head> <title>Chuck Norris API</title> </head>
<body>
<button id="refreshBtn" type="button">Refresh Joke</button>
<script>
let body = document.querySelector('body');
let btnEl = document.getElementById('refreshBtn');
btnEl.addEventListener('click', () => {
btnEl.disabled = true;
fetch('https://api.chucknorris.io/jokes/random', {
method: 'GET'
})
.then(resp => resp.json())
.then(jsonResp => {
const p = document.createElement('p');
p.innerText = jsonResp.value;
body.appendChild(p);
btnEl.disabled = false;
})
.catch(err => {
alert(err);
btnEl.disabled = false;
});
});
</script>
</body>
</html>
You code #1
BONUS
Let's turn the buttons into radios & add a text input to free search for jokes in that category.
Week #14
In case you won't finish the project and don't want to present it during the normal evaluation, let me know. *
β Fully implemented and functional app
β Detailed application architecture (via diagrams, drawings, relevant code snippets etc) in scholarly format
*Make sure you have submitted all your code in GitHub, on the master/main branch
β User guide, in scholarly format as well
β APIs Documentation (Swagger)Β - if you need to build APIs
β Demo movie - for M class projects
β Responsive & valid HTML pages
β At least one AJAX call