backend

Backend


Motivation

Frontends können einige Dinge nicht

  • Authentifizierung
  • Autorisierung
  • Datenspeicherung
  • API Key Verwaltung

Architektur

Kommunikation üblicherweise über http


HTTP

http

URL - Uniform Resource Locator

protocol://hostname:port/path?field=value

Request

GET http://www.htlstp.ac.at/logo
Accept: image/webp, image/apng, image/*, */*;q=0.8
POST http://www.htlstp.ac.at/api/teachers/
Content-Type: application/json

{
  "name": "SCRE",
  "dept": "IF"
}

Response

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 18 May 2020 18:08:47 GMT
Content-Type: image/png
Content-Length: 4663
Connection: keep-alive
Expires: Mon, 25 May 2020 04:35:30 +0200

‰PNG

IHDR  
N‘•£%Ɏ;%”ÚCl‡³Úí:º0ºRî`Ýze++¡·1Úqƒõ.¥ôB›ëm7¹·îd%á
...

Request Methoden

GET

        GET http://www.appdomain.com/users
        GET http://www.appdomain.com/users/123
        GET http://www.appdomain.com/users?size=20&page=5
    
lädt die angegebene Resource
sollte bei jedem Aufruf dasselbe Resultat liefern
DELETE

        DELETE http://www.appdomain.com/users/123
    
löscht die angegebene Resource

POST

        POST http://www.appdomain.com/users
        Content-Type: application/json
        {resource}
    
Resource im RequestBody speichern
PUT/PATCH

        PUT http://www.appdomain.com/users/123
        Content-Type: application/json
        {resource}
    
Resource im RequestBody unter Request-URI ersetzen/updaten

Status Codes

200 - OK
400 - Bad Request
Request fehlerhaft, später sicher Fehler
Bestellt Kebab bei McDonalds
500 - Internal Server Error
Request ok, Serverfehler, später vielleicht Erfolg
Bestellt Pommes, die sind noch nicht fertig
201 - Created
204 - No Content
nach DELETE
404 - Not Found

node Server

import {createServer, IncomingMessage, ServerResponse} from "http";

const port = 3000
const server = createServer(
  (request: IncomingMessage, response: ServerResponse) => {
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.write(`
    <html>
        <body>Hello World</body>
    </html>
    `);
    response.end();
  }
);

server.listen(port, () => console.log(`Server listens on ${port}`))
GET localhost:3000 => Hello World
POST localhost:3000 => Hello World
DELETE localhost:3000/what/ever => Hello World

Routing

if (request.method === 'GET' && request.url === '/hello') 
  // send hello world
if (request.method === 'GET' && request.url === '/login')
  // login
if (request.method === 'POST' && request.url === '/transmit') {
  // Daten kommen nicht komplett an, sondern in chunks
  let rawData = '';
  request.on('data', chunk => {
    rawData += chunk
  });  
  request.on('end', () => {
    // use rawData
  });  
}

Form Data

<form action='/submit' method='POST'>
  <label for='name'>Name:</label>
  <input type='text' id='name' name='name'>
  <label for='email'>Email:</label>
  <input type='email' id='email' name='email'>
</form>
POST /submit HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 42

name=scre&email=christoph.schreiber@htlstp.at
name=value&name=value&name=value ...

CSR vs SSR


Content loading

  • SSR ✅
  • CSR Frontend lädt Daten dynamisch vom Backend
  • CRUD-Application (Create, RRead, UUpdate, DDelete)
  • Standardformat JSON(Javascript Object Notation)
{
  "grade": 3,
  "mandatory": true,
  "teacher": "SCRE",
  "subject": {
    "title": "Web und Mobile Computing",
    "short": "WMC"
  },
  "content": [
    "Frontend",
    "Backend"
  ],
  "technologies": [
    {
      "type": "IDE",
      "title": "WebStorm"
    },
    {
      "type": "Frontend",
      "title": "Angular"
    }
  ]
}

Layered Architecture


Express

const port = 3000;
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World');
});

app.post('/transmit', (req, res) => {
  let data = req.body;
  res.status(200)
     .json({'received': data});
});

app.listen(port, () => {
  console.log(`Server listens on ${port}`);
});

Error Handling

Error ⟹ 500 Internal Server Error

app.post('/students', (req, res) => {
  let student = req.body;
  try {
    let saved = service.save(student); // throw new Error('invalid')
    res.status(201)
       .json(saved);
  } catch(err: any) { // ohne catch 500
    res.status(400)
       .json({error: err.message}); // 'invalid'
  }
});
<!-- .element: class="fragment "-->

Interfaces

export interface Student {
  id: number,
  firstName: string,
  lastName: string
}

[
  {
    "id": 1, "firstName": "Alfred", "lastName": "Adler"
  },
  {
    "id": 2, "firstName": "Bernd", "lastName": "Bauer"
  }
]