Skip to content

Sumários

Miguel Gamboa edited this page Jan 15, 2021 · 51 revisions

Aulas

Livro de Referência:


06-10-2020

  • Apresentação da disciplina de Programação na Internet -- PI
  • Regras de avaliação
  • Bibliografia
  • Documentação suplementar: nodeschool.io
  • Evolução histórica do Javascript desde o seu aparecimento em 1995 com o objectivo inicial de uma linguagem de scripting para o browser até à sua execução no ambiente Node.js
  • Papel da linguagem Javascript como: alto nível (e.g. Java, C, etc) e intermédia (e.g. bytecodes, IL).
  • SLIDES: pi-52d-aula01.pdf

08-10-2020

  • Análise das características da linguagem de programação Javascript como: dinâmica, untyped, e interpretada.
  • Duck Typing
  • Dinâmica -- Adicionar e remover propriedades em Tempo de Execução:
    • obj.nova_prop -- adicionar uma propriedade que não existe
    • delete obj.prop -- remover uma propriedades existente
  • Ambiente de desenvolvimento:
    • Modo use strict
    • ESLint -- Javascript linter
    • Editor e.g. Visual Code, Notepad, InteliJ, etc.
  • Scopes:
    • let e const – variáveis que NÃO podem ser usadas fora do bloco em que foram declaradas. Temporal Dead Zone
    • var - scope da função onde é declarada. Recomendação de NÃO usar.
  • Sistema de tipos EcmaScript edição 6: Object e Primitivos (todos os outros que não são Object)
  • Tipos Primitivos: Undefined, Null, Boolean, Number, String.
  • operador typeof e instanceof
  • Objecto Literal: { prop1: valor1, prop: valor2, …}
  • propriedades são membros de um objecto que armazenam valores.
  • SLIDES: pi-52d-aula02.pdf

09-10-2020

  • Node.js:
    • = AVE + gestão de dependencias (bibliotecas)
    • = V8 + NPM package manager
  • V8 JavaScript Engine projecto open-source de uma máquina virtual da Google, parte integrante do Browser Chrome, lançado em 2008.
  • V8 como um Ambiente Virtual de Execução com as mesmas características de outros ambientes como JVM, ou CLR.
  • Os componentes são distribuídos em código fonte JavaScript, podendo o JavaScript ter também uma perspectiva de linguagem intermédia como target de compiladores de linguagens como o TypeScript, Python, entre outras.

  • Uma propriedade que armazena uma função é um método
  • Função Construtora --- tem uma propriedade explícita prototype.
  • Objecto ––– constructor –––> função Construtora (código) ––– prototype –––> objecto Protótipo.
  • O protótipo tem a semântica do padrão de desenho Prototype
  • O protótipo serve de “modelo” à criação de novos objectos
  • Exemplos de actualização do prototype e reflexo nos objectos com esse prototype
  • Properties Lookup (o objecto tem precedência sobre o protótipo)
    • Primeiro procura no objecto uma propriedade com o nome igual
    • Caso não encontre, então procura no prototype uma propriedade com esse nome

  • Funções são first-class objects -- as funções têm todas funcionalidades que tem qualquer outro objecto JavaScript:
    • Podem ser atribuídas a variáveis
    • Podem ser passadas por parâmetro
    • Podem ter propriedades definidas pelo programador (campos ou métodos)
  • Funções têm uma capacidade adicional sobre os objectos que é poderem ser invocadas.,

  • Introspecção sobre objectos em Javascript (comparação com Reflexão via .Net ou Java):
    • Enumeração sobre nomes das propriedades de um objecto – for(let key in objRef)
    • Aceder a uma propriedade com nome dado por uma expressão: obj[exp]
    • Chamar um método com nome dado por uma expressão: obj[exp]()

13-10-2020


  • Função Construtora
  • Chamada realizada com o operador prefixo new
  • O construtor retorna implicitamente o novo objecto (this) a não ser que haja retorno explícito
  • Associação de método de instância por via do Prototype
    • e.g. Point.prototype.module = function() {return Math.sqrt(this.x*this.x + this.y*this.y)}

  • Definição equivalente com class em ECMAScript 6
  • Os métodos correspondem a proprieades not enumerable <=>:
Object.defineProperty(Point.prototype, 'module', {
    value: function() {
        return Math.sqrt(this.x*this.x + this.y*this.y)
    }
})

  • Enumerar propriedades visíveis: for(let propName in obj)
  • Enumerar todas as propriedades: for(let propName of Object.getOwnPropertyNames(obj))

  • As funções são declaradas como literais que criam um valor função. 3 formas:
    • função com nome e.g. function foo() {}
    • função sem nome e.g. function () {} (função anónima)
    • arrow function e.g. () => {} (função anónima)

  • Uma função tem uma propriedade name que guarda o nome declarado na função.
  • Funções anónimas têm a propriedade name igual "" string vazia.
  • O nome da variável que refere uma função != da propriedade name dessa função

  • Todas as funções recebem dois parâmetros implícitos: this e arguments
  • arguments é uma colecção com o mesmo comportamento de array mas sem os seus métodos.
  • O número de argumentos, não tem que coincidir com o número de parâmetros
  • 4 formas de chamar uma função:
    • Como uma função (sem target) => this igual a undefined
    • Como um método de instância -- this igual ao target e.g. target.methodName()
    • Como construtor -- this igual ao objecto criado e.g. new funcName()
    • com apply() ou call()

  • Função Construtora
  • Chamada realizada com o operador prefixo new
  • O operador new altera o significado do this que refere o objecto criado;
  • O construtor retorna implicitamente o novo objecto (this) a não ser que haja retorno explícito;

Closure:

  • Por cada chamada a uma função é criado um novo conjunto de variáveis com o contexto dessa função;
  • As funções internas têm acesso às variáveis locais (parâmetros, ou não);
  • NESTE caso, o ciclo de vida das variáveis externas é prolongado (apenas se for usada a função interna).

  • package.json
  • npm init
  • npm install <pkg> --save -- download módulo <pkg> e actualiza package.json
  • repositório local node_modules -- Adicionar ao .gitignore
  • npm install -- download das bibliotecas especificadas em package.json

  • CommonJS -- definição do formato dos módulos.
  • require(‘nome’) -- incorpora um módulo Node na forma de um objecto.
  • module.exports
  • fs = require('fs') -- módulo file system
  • Exemplos de utilização da API síncrona de sync-request:
    • req('GET', 'http://example.com').getBody().toString()

  • Node.js: Google's V8 JavaScript engine + event loop + low-level I/O API;
  • Event Loop para executar operações (na forma de callbacks) quando um evento ocorre.
  • Felix Geisendörfer: “everything runs in parallel except your code.”
  • Vários callbacks podem responder a um mesmo evento, mas só um é executado em cada instante – sequencialmente.
  • Os callbacks NÃO são interrompidos por outros callbacks, nem correm em paralelo com outros callbacks.
  • Do ponto de vista da linguagem JavaScript o Node.js oferece um ambiente single-threaded.
  • Todas as operações de IO do Node.js podem ser executadas emsimultaneo e.g. ler ficheiros; peidos HTTP,….
  • As operações de IO usam técnicas non-blocking.

github.com/maxogden/art-of-node

  • Distinção entre modelo de chamada síncrono versus assíncrono. Exemplos.
  • Exemplificação em Node Js de uma sequência de pedidos Http de forma Síncrona versus Assíncrona através dos módulos sync-request vs request.
  • Idiomatic Node.js callback convention -- (err, data) => void
  • Características do modelo de callback do node.js:
    • (err, data) => void
    • O callback é o último parâmetro passado a um método assíncrono.
    • Idioma: if(err) return cb(err)
    • Em caso de sucesso: cb(null, data)

github.com/maxogden/art-of-node

  • Revisão do modelo Assíncrono baseado em Callback
  • Menção a outras formas de utilização de um modelo de chamada assíncrono (tratado na UC de Programação Concorrente):
    • Promises
    • async/await
  • Características do modelo de callback do node.js:
    • (err, data) => void
    • O callback é o último parâmetro passado a um método assíncrono.
    • Idioma: if(err) return cb(err)
    • Em caso de sucesso: cb(null, data)
  • Implementação de uma API assíncrona baseada em callback
  • Retornar o tamanho do ficheiro e outra função que calcula o somatório dos ficheiros.

  • Martin Fowler “Enterprise applications are about the display, manipulation, and storage of large amounts of often complex data and the support or automation of business processes with that data” [Fowler, 2003].
  • Simplistic view: 📂 --> Data Layer --> Domain --> UI --> 👤
  • 3 Layers or Tiers
  • Exemplo: BD SQL --> JDBC --> Model + Services --> HTML + CSS + Css --> 🌐
  • vinyl -- Desenho de uma aplicação Web para gestão de listas de bandas favoritas por utilizador.
  • vinyl:
Last.fm API     ---> urllib ---> lastfm \
                                         ---> vinyl ---> UI
users.json File ---> fs     ---> users  /
  • lastfm - Análise da fontes de dados Last.fm API
  • users - Desenho do formato de dados para armazenar utilizadores e suas bandas favoritas

  • vinyl -- obter o top das músicas das bandas favoritas de um utilizador.
  • Implementação dos módulos da aplicação vinyl: 1. lastfm, 2. users e 3. vinyl:
    1. lastfm -- getTopTracks(artist, cb)
    2. users -- function getUser(username, cb)
    3. vinyl -- function getTopTracks(username, limit, cb)
  • Documentação da API com JSDoc

  • JavaScript Testing Frameworks: nodeunit, mocha, jest, etc
  • Using jest:
    1. npm install --save-dev jest
    2. npm install --save-dev @types/jest -- To provide full typing and e.g. intellisense in VS Code
    3. jest --init -- Generate a basic configuration file
    4. npm run test calls jest to run tests
    5. jest --coverage to check code coverage
  • Code Coverage
  • Testing Asynchronous Code
  • Mock - simulated objects that mimic the behavior of real objects.
  • Implementing a mock for urllib
    1. jest.mock('urllib')
    2. urllib.request.mockImplementationOnce(function ....)
  • URIs, Resources and Representation
  • Schemes, e.g. scheme http://-- protocolo http
  • App WEB: HTTP Server; Routing; Representation (e.g. HTML, Json, CSV, other; aka Views)
  • Request Methods: GET, POST, PUT, DELETE.
  • Idempotent property defined by RFC 7231.
  • PUT <versus> POST
  • Designing routes for vinyl web application:
GET    /vinyl/users/<username>          => getUser()
GET    /vinyl/users                     => getUsers()
DELETE /vinyl/users/<username>          => removeUser()
PUT    /vinyl/users/<username>          => addUser()   // unique usernames
POST   /vinyl/users/<username>/artists  => addArtist() // allows repetitions

  • const server = http.createServer((req, res) => ...) - instance of HTTP server.
  • server.listen(8000) - run and listen on port.
  • res.writeHead(statusCode[, statusMessage][, headers])
  • res.write(chunk) - sends a chunk of the response body.
  • res.end([data]) - signals that response headers and body have been sent

  • Some headers: Host; content-type; content-length;
  • Internet Media Types e.g. text/xhtml, image/png, application/json, etc (RFC2046)
  • HTTP status codes
  • Inconsistent responses:
    • Uncomplete HTTP response
    • Absence of content-type

  • Vinyl web app
  • Implement routes-vinyl
  • Handling errors and distinguishing between errors on server or client side
  • Parsing route parameters and query string
  • Modules url and querystring

  • Solving the TPC8
  • Highlight the difference between changing the Resource versus its Representation

  • Distinguish between Unit and Integration tests.
  • Mention different alternatives and approaches for integration tests of a web API.
  • E.g. Postman, frisby js
  • Validate responses status codes and JSON content.
  • expect(handler, [...args])
  • handler: status, header and json
  • Ensure that Web API server is running before starting tests.
  • beforeAll(() => server = fork('./index', ... )
  • Routing : app.METHOD(PATH, HANDLER)
    • app is an instance of express.
    • METHOD is an HTTP request method, in lowercase.
    • PATH is a path on the server.
    • HANDLER is the function executed when the route is matched.
  • HANDLER - handling middleware function - function(req, resp, next)
  • app.use(PATH, HANDLER) - for any method.
  • app.use(HANDLER) - for any method and any path.
  • route parameters - /path/:param1/
  • req.params - route parameters specified in path
  • req.query - query string parameters
  • resp.send() -- includes call to end() and content-type as HTML
  • resp.json() -- serializes (JSON.stringify) to JSON and content-type as JSON.
  • Error Handler -- added at the end of the pipeline by default.
  • Error Handler custom - function(err, req, resp, next)

  • Composing pipelines through express.Router:
    • A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.


Node.js 8 the right way:

  • Chapter 7 - Advantages of Express
  • Chapter 7 - Serving APIs with Express
  • POST passing parameters in HTTP body rather than in query-string
  • Using express body-parser middleware
  • app.use(bodyParser.json()) for application/json
  • app.use(bodyParser.multipart({ extended: false })) for application/x-www-form-urlencoded

  • Download: https://www.elastic.co/downloads/elasticsearch
  • ElasticSearch - Resources are JSON documents
  • ElasticSearch - schema-free + RESTful + NoSQL
  • ElasticSearch - Stores and indexes JSON documents via HTTP:
  • run: > elasticsearch
  • RESTFull API: HTTP based + Resources by URI
    • HTTP GET - returns a resource
    • HTTP PUT - updates a resource identified by given URI
    • HTTP POST - inserts a new resources and generates a new URI
    • HTTP DELETE - removes a resource
  • URI = <elastic host>:<port>/index/type/<_id>
  • URI e.g. localhost:9200/tasks/_doc_/t01
  • Use cases:
    • curl http://localhost:9200/_cat -- info about the cluster
    • curl http://localhost:9200/_cat/indices -- listing indexes
    • curl http://localhost:9200/_cat/indices?v -- v stands for verbose
    • curl http://localhost:9200/_all -- details about all indexes
    • curl http://localhost:9200/tasks -- details about a particular index, e.g. tasks
    • curl http://localhost:9200/tasks/_search -- listing documents of an index, e.g. tasks
    • curl http://localhost:9200/tasks/_doc_/t01 -- details of a document with _id = t01 and type = _doc
  • Manipulate:
    • curl -X PUT http://localhost:9200/tasks -- Creates an index e.g. tasks
    • curl -X DELETE http://localhost:9200/tasks/_doc_/t01 -- Removes the document with _id = t01
    • curl -X POST versus PUT to create or update a document, e.g. task1.json:
> curl -X PUT --data "@task1.json" -H "Content-Type: application/json" http://localhost:9200/tasks/_doc/t01
> curl -X POST --data "@task2.json" -H "Content-Type: application/json" http://localhost:9200/tasks/_doc

  • Project Gutenberg -- Project Gutenberg is a library of over 60,000 free eBooks.
  • databases/rdf-to-bulk.js -- JavaScript app that migrates RDF filed in XML --> JSON (i.e. bulk_pg.js)
  • Insert JSON documents into ElasticSearch in bulk with content frombulk_pg.json:
curl -X POST 
     -H "Content-Type: application/json" 
     --data-binary "@bulk_pg.ldj" 
     http://localhost:9200/books/_bulk
  • Sample of a bundle:
{
    "name": "light reading",
    "books": [{
        "id": "pg132",
        "title": "The Art of War"
    },{
        "id": "pg2680",
        "title": "Meditations",
    },{
        "id": "pg6456",
        "title": "Public Opinion"
    }]
}
  • module Bundle service:
    • create(name, cb)
    • delete(id, cb)
    • get(id, cb)
    • addBook(id, pgId, cb) => includes 3 HTTP requests:
      1. GET /localhost:9200/bundles/bundle/<pgid>
      2. GET /localhost:9200/books/book/<pgid>
      3. PUT /localhost:9200/bundles/bundle/<pgid> novo bundle
  • ALERT for the sequential execution of 1. and 2. that could be performed concurrently instead.
  • Implement a function parallel(tasks, callback) that:
    • Run the tasks array of functions in parallel. If any of the functions pass an error to its callback, the main callback is immediately called with the value of the error. Once the tasks have completed, the results are passed to the final callback as an array.
  • Highlight the sequential execution of tasks: 1. get bundle and 2. get book.
  • Compare the two possible approaches to perform those tasks: sequential vs concurrent
  • Modify addBook(id, pgid, cb) of bundles to run 1. get bundle and 2. get book concurrently.
  • Modify addArtist(id, pgid, cb) of vinyl to run 1. get user and 2. search artist concurrently.
  • Extract to a distinct module the logic of running tasks concurrently and aggregating their results.
  • Implement in module asyncutils a function parallel(tasks, callback) that:
    • "Run the tasks array of functions concurrently. If any of the functions pass an error to its callback, the main callback is immediately called with the value of the error. Once the tasks have completed, the results are passed to the final callback as an array."
  • !!!ALERT!!! to the order of the results in aggregation array.
  • Implement a unit test to validate parallel(...) of asyncutils
  • Update bundles and vinyl to take advantage of parallel(...), e.g.:
const task1 = cb => users.getUser(username, cb)
const task2 = cb => lastfm.searchArtist(artist, cb)
asyncutils.parallel([task1, task2], (err, res) => {
   if(err) return cb(err)
   const [user, arr] = res
   if(arr.length == 0) return cb(Error('There is no artist with name ' + artist))
   users.addArtist(user.username, arr[0].name, cb) 
})
  • https://en.wikipedia.org/wiki/Futures_and_promises
  • Promise - Container for an asynchronous result: successful or failure.
  • Asynchronous alternatives examples:
    1. callback (err, data) => {...} -- err and data are 2 possible results.
    2. EventEmitters .on('error’, callback) e .on('data’, callback).
    3. Promise - e.g. Java CompletableFuture, .Net Task, Js Promise, etc
    4. async/await -- in most environments e.g. Dotnet, Python, Js, etc. except Java.
    5. suspend functions, e.g. Kotlin
  • Js Promise:
    • 3 possible states: Pending, Fulfilled (success) or Rejected (error)
    • chaining a callback: ….then(callback) or ….catch(callback)
    • then() and catch() return new Promise objects
  • Implement delay(timeout, success) that returns a Promise
  • Chaining Promises through then() that behaves like flatMap()

Node.js 8 the right way:

  • Refactoring vinyl app to use Promises rather than callbacks
  • async / await -- "allows you to write pseudo-synchronous code to describe asynchronous computation.":
    • Forgetting try/catch may lead to Unresolved Promises Warning!
    • Chaining consecutive await calls may lead to a sequential execution!
  • Module require('fs').promises
  • Module fetch-node
  • Jest with promises
  • Jest mocking fetch-node
  • Chaining continuations:
function getTopTracks(username, limit) {
  return users
    .getUser(username)                                                   // P<User>
    .then(user => user.artists)                                          // P<Array<Artist>>
    .then(artists => artists.map(artist => lastfm.getTopTracks(artist))) // P<Array<P<Array<String>>>>
    .then(arr => Promise.all(arr))                                       // P<Array<Array<String>>>
    .then(tracks => tracks.map(arr => arr.slice(0, limit)))              // P<Array<Array<String>>>
    .then(tracks => tracks.flat())                                       // P<Array<String>>>
}

Node.js 8 the right way:

  • HTML: structure and content semantics
  • E.g. semantic elements: <caption>, <thead>, <nav>, etc
  • Elements, Tags and Attributes
  • Text nodes
  • HTML basics:
    • <!DOCTYPE html>
    • <html>, <body>
    • <head>
    • <meta charset="utf-8">
  • self-closing elements: <img>, <br>, <hr>, etc

  • CSS: styling language to define HTML content presentation.
  • CSS: Selector, Properties e Values
  • Syntax: selector{propriedade:valor; ...}
  • inline, internal e external styles.

  • GetBootstrap
  • <link href="bootstrap.min.css" rel="stylesheet">
  • Responsive, mobile-first front-end web development

  • View -- Template for HTML presentations
  • handlebars semantic templates
  • data -- context object -- referência na view através de {{.}}
  • Layouts and {{{body}}}
  • Express with handlebars:
    1. npm install --save hbs
    2. app.set('view engine', 'hbs') and app.set('views', './lib/views')
    3. resp.render(<view name>, <object>)
  • view handlebars :
    • {{#each property-array}} … {{/each}}
    • {{#if }} ...{{else }}

  • HTML, Handlebars and CSS
  • CSS frameworks e.g. Bootstrap
  • CSS use of classes e.g. container, table, table-striped, etc
  • External CSS
  • Serving static resources. E.g. express.static()

  • Forms
  • Submiting data through POST
  • enctype application/x-www-form-urlencoded
  • app.use(bodyParser.urlencoded({ extended: false }))
  • Body parameters on req.body
  • Post/Redirect/Get (PRG) idiom that lets the page shown after a form submission be reloaded, shared, or bookmarked without ill effects.

  • Authentications includes:
    • 1x Credentials ---> User ---> User Id (on session state)
    • Further requests: User ID ----> User (on Web App)

  • Cookies keep stateful information across different HTTP requests.
  • Request header Cookie and response header Set-Cookie
  • Cookies attributes: expires, domain e path.
  • Module cookie-parser.
  • Use cases:
    • Read: req.cookies
    • Write: resp.cookie(key, value)
  • Setup Middleware for session state: app.use(expressSession({...}))
  • req.session - read write properties kept in session state

Node.js 8 the right way:

  • Chapter 9 - Managing User Sessions in Express

  • Authentications includes:
    • 1x Credentials ---> User ---> User Id (on session state)
    • Further requests: User ID ----> User (on Web App)
  • passport includes:
    1. passport.session() - middleware to keep User Id in session state.
    2. passport.initialize() - middleware that setup req with methods:
      • req.login(user, cb) ---> updates req.user and stores User Id in session.
      • req.logout() ---> deletes req.user and User Id from session.
      • req.isAuthenticated() ---> true or false as a result ofreq.login() or req.logout().
  • req.login(user, callback):
    • Error if it fails to create a new session for the user.
    • Uses passport.serialize to get the User Id that is stored in session.
  • passport.session() uses passport.deserialize to build the User instance from the User Id.

  • front-end -- Resources in HTML, CSS and JavaScript to produce a GUI
  • <script type='text/javascript' src='/js/vinyl.js'></script>
  • JavaScript DOM API:
    • Data representation of the objects that comprise the structure and content of a document on the web.
    • API that enables the connection between web pages to scripts/programming languages.
  • fetch() - Browser API to perform HTTTP request in Javascript.
    • node-fetch shares the same API of fetch()

  • Use cases of Javascript DOM:
    • window - reference to a Window object that contains a document
    • document – reference to root Element
    • document.location – information about the URL of the document
    • document.getElementById(<String>) - return an Element by its id
    • <Element>.addEventListener(type: String, listener: Function)
    • <Node>.querySelector(<selector>) – first occurrence
    • <Node>.querySelectorAll(<selector>) – returns a list of Node objects with all occurrences
    • <Node>.insertAdjacentHTML(position, String) - where position may be: 'afterbegin', 'beforeend', etc
    • <Node>.innerHTML - gets or sets the HTML or XML markup contained within the element.
    • <Node>.remove() - removes the node from the document it belongs to.

  • EventEventHandler and EventListener
interface EventTarget : Node{ 
   void  addEventListener(String type, EventListener listener, bool Capture/Buble);
}
  • e.g. buttonElement.addEventListener('click', function (event) {...})
  • Alternative: node.["on" + type] = handler(): AVOID it in HTML documents.
    • Event handler property as a placeholder, to which a single event handler can be assigned.

Vinyl Web App:

  • Implement server routes to handle delete on /api/vinyl/users/:username/artists/:artist
  • Implement service for removeArtist() on module users and unit tests.
  • Using fetch('api/...', {method: 'DELETE', ...}) to former route.
  • NOTICE the browser does not refresh (nor redirect) on response status 300 for a request via fetch().
  • HTML data attributes for extensibility and data that should be associated with elements.
  • Alternatives:
    • Hidden input
    • User programmer own attributes Avoid it
    • HTML data attributes.