Esta es la última lección del curso. Si has llegado hasta aquí, tu tenacidad y dedicación al aprendizaje de node.js está casi confirmada. A estas alturas, es de esperar que ya haya dominado la devolución de llamadas y el streaming, dos conceptos fundamentales en node.js, además de todos los demás conocimientos básicos de JavaScript que necesita tener.

Leccion-13 learnyounode Lección 13 – HTTP JSON API Server

Para la lección final, necesitamos crear un servidor de la API de JSON que acepte una cadena de consulta de URL que incluya una cadena de tiempo ISO. El servidor debe responder con un objeto que contenga la hora, minuto y segundo, o con un objeto que contenga la hora de época de Unix, dependiendo del punto final que se incluya en la cadena de consulta de la url.

En este punto, sabemos cómo configurar un servidor. Sin embargo, no se ha dicho mucho sobre el análisis de las URLs. El módulo url tiene algunos métodos útiles, incluyendo el método parse(). El método parse() devuelve un objeto con los distintos componentes de una url.

Intenta introducir el siguiente comando en la línea de comandos, tal y como sugiere la sugerencia.

node -pe «require(‘url’).parse(‘/test?q=1’, true)»

Este comando analiza una url en un archivo de prueba incluido en el directorio de learnyounode. El comando -pe es la abreviatura de imprimir' yevaluar’. Usted está evaluando su programa e imprimiendo el resultado en la consola. Para más información sobre las opciones de la línea de comandos del nodo, consulte la documentación.

Después de presionar Enter, debería ver un resultado similar al del ejemplo de abajo. Los componentes de la url ‘/test?q=1’ se muestran como un objeto llamado Url.

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: ‘?q=1’,
  query: { q: ‘1’ },
  pathname: ‘/test’,
  path: ‘/test?q=1’,
  href: ‘/test?q=1’ }

Como puedes ver, el método parse() es muy útil porque nos permite acceder a las diferentes propiedades del objeto. Por ejemplo, podemos asignar una url que hace una petición a nuestro servidor a una variable llamada url vía notación por puntos con request.url. Vea abajo un ejemplo.

var http = require(‘http’)
var url = require(‘url’)
 
http.createServer(function (request, response) {
  // assign request.url to variable url
  url = url.parse(request.url, true)
}).listen(+process.argv[2])

Puede basarse en el ejemplo anterior para hacerse una idea de cómo es la petición que se envía a su servidor. Intente crear el programa en el ejemplo de abajo y ejecutarlo con el comando learnnyounode run.

var http = require(‘http’)
var url = require(‘url’)
 
http.createServer(function (request, response) {
  // assign request.url to variable url
  url = url.parse(request.url, true)
  // log contents of url to console
  console.log(url)
}).listen(+process.argv[2])

learnyounode run myTest.js

Debería ver un objeto similar al que vio cuando probó el método parse() anteriormente.

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: ‘?iso=2019-09-14T15:29:28.234Z’,
  query: { iso: ‘2019-09-14T15:29:28.234Z’ },
  pathname: ‘/api/unixtime’,
  path: ‘/api/unixtime?iso=2019-09-14T15:29:28.234Z’,
  href: ‘/api/unixtime?iso=2019-09-14T15:29:28.234Z’ }

¿Nota cómo la propiedad de la consulta del objeto Url es también un objeto?.

query: { iso: ‘2019-09-14T15:29:28.234Z’ }

El objeto tiene una propiedad llamada iso, para el tiempo de formato iso, y el valor es una cadena de tiempo de formato iso. Puede acceder al valor de la propiedad iso con notación por puntos. Por ejemplo, si registra url.query.iso en la consola, el resultado será una cadena de tiempo iso similar a ésta:

‘2019-09-14T15:29:28.234Z’

Entre las sugerencias aquí y los ejemplos de las lecciones, usted debería tener suficiente para seguir adelante con la construcción de su programa. Voy a dejarte con una pista más. Tendrá más suerte en esta lección si crea una función o dos que acetúen un argumento como el tiempo y devuelvan un objeto que utilice una hora',minuto’ y segundo', ounixtime’ como nombres de propiedad del objeto. Los valores de las propiedades de los objetos pueden ser métodos como getHours() o getTime() para devolver los resultados que busca. Para crear una función como ésta, comience con algo similar al ejemplo de abajo.

var myFunc = function (argument) {
  return {
    myProperty: argument.method()
  }
}

Si pasa esta función al método JSON.stringify(), convierte el valor de retorno de la función en un objeto JSON.

JSON.Stringify(myFunc())

Otra solución

Para resolver este desafío, escribí un programa con tres funciones y un servidor http. He creado una función para analizar una cadena de tiempo iso y devolver la hora, los minutos y los segundos como un objeto JSON, y he creado otra función que acepta una cadena de tiempo iso y devuelve un objeto JSON con la conversión de época unix de la cadena iso. Además, he creado una función que utiliza una instrucción de conmutación para llamar a mis otras funciones dependiendo del punto final al que se acceda.

Para ver la solución que se me ocurrió, o la solución oficial, haga clic en el enlace para ver la solución.

var http = require(‘http’)
var url = require(‘url’)
 
var port = process.argv[2]
 
var parseTime = function (time) {
  return {
    hour: time.getHours(),
    minute: time.getMinutes(),
    second: time.getSeconds()
  }
}
 
function unixTime (time) {
  return {unixtime: time.getTime()}
}
 
var parseQuery = function (url) {
  switch (url.pathname) {
    case ‘/api/parsetime’:
      return parseTime(new Date(url.query.iso))
    case ‘/api/unixtime’:
      return unixTime(new Date(url.query.iso))
    default: return ‘please enter a valid endpoint url’
  }
}
 
http.createServer(function (request, response) {
  if (request.method === ‘GET’) {
    response.writeHead(200, {‘Content-Type’: ‘application/json’})
    url = url.parse(request.url, true)
    response.end(JSON.stringify(parseQuery(url)))
  } else {
    response.writeHead(405)
    response.end()
  }
}).listen(+port, function () {
  console.log(‘Server listening on http://localhost:%s’, port)
})

En mi solución, estoy asignando los módulos http y url a las variables http y url. También estoy asignando el primer argumento de mi programa al puerto variable. Mi primera función se llama parseTime. La función acepta un argumento llamado tiempo, y devuelve un objeto con la hora, los minutos y los segundos analizados a partir del argumento tiempo. Estoy usando los métodos getHours(), getMinutes(), y getSeconds() para analizar la cadena de tiempo iso que se pasa como argumento a la función parseTime. Al devolver un objeto en formato de notación de objetos JavaScript, es fácil convertir los resultados de mi función al formato JSON con el método JSON.stringify().

La segunda función se llama unixTime, y es muy similar a parseTime. La función unixTime también acepta un argumento llamado time, que esperamos que sea una cadena de tiempo iso. En lugar de analizar la cadena para devolver la hora, los minutos y los segundos, estoy usando el método getTime(), que devuelve el equivalente de época de unix. También estoy devolviendo un objeto en formato de notación de objetos JavaScript en esta función con una propiedad llamada unixtime.

La última función es parseQuery. La función parseQuery acepta un argumento llamado url y utiliza una sentencia de cambio para analizar la url. ¿Por qué usar una declaración de cambio? Si alguna vez he querido añadir puntos finales adicionales, una instrucción de cambio puede ayudar a dirigir las direcciones URL a esos puntos finales sin hacer una larga cadena de instrucciones if/else if/else if/else. Las sentencias de los conmutadores también pueden tener un valor predeterminado, como por ejemplo `por favor, introduzca una url de punto final válida’. Por último, se sabe que las sentencias de cambio tienen un mejor rendimiento, aunque esto puede variar de un navegador a otro.

La condición de la sentencia de cambio en parseQuery es la propiedad url.pathname. Si la ruta es’/api/parsetime’, devolviendo los resultados de mi función parseTime, que estoy pasando un nuevo objeto Date() que contiene la propiedad url.query.iso. Si el nombre de la ruta es ‘/api/unixtime’, estoy devolviendo el resultado de la función unixTime, que también está pasando un nuevo objeto Date() que contiene la propiedad url.query.iso. Si el valor de url.pathname no es igual a ninguno de los dos endpoints, estoy devolviendo el valor por defecto de la sentencia switch, que es ‘por favor, introduzca una url de endpoints válida’.

Después de declarar todas mis funciones, estoy creando un servidor. Si el método request (request.method) de la url que se envía a mi servidor es igual a GET', estoy escribiendo estado 200 y el tipo de contenido, que es application/json. Luego estoy analizando el valor de request.url con el método url.parse(), y asignándolo a la variable url. Finalmente, estoy llamando a mi función parseQuery y pasándole la URL de la variable. La función parseQuery se pasa al método JSON.stringify(), que convierte el resultado en un objeto JSON, y el objeto JSON se pasa al método response.end(). Si el método de solicitud no es igual aGET’, estoy escribiendo el estado 405 al jefe de la solicitud, y terminando la respuesta.

Finalmente, estoy escuchando en el puerto que se pasa como primer argumento a mi programa y registrando la url del servidor en la consola.

Solución oficial

La solución oficial varía ligeramente de mi solución. Una tercera función para analizar la consulta no se utiliza. Además, si/en caso de que se utilicen sentencias en lugar de una sentencia switch. Para ver la solución oficial, haga clic en el enlace para revelarla.

var http = require(‘http’)
var url = require(‘url’)
 
function parsetime (time) {
  return {
    hour: time.getHours(),
    minute: time.getMinutes(),
    second: time.getSeconds()
  }
}
 
function unixtime (time) {
  return { unixtime : time.getTime() }
}
 
var server = http.createServer(function (req, res) {
  var parsedUrl = url.parse(req.url, true)
  var time = new Date(parsedUrl.query.iso)
  var result
 
  if (/^\/api\/parsetime/.test(req.url))
    result = parsetime(time)
  else if (/^\/api\/unixtime/.test(req.url))
    result = unixtime(time)
 
  if (result) {
    res.writeHead(200, { ‘Content-Type’: ‘application/json’ })
    res.end(JSON.stringify(result))
  } else {
    res.writeHead(404)
    res.end()
  }
})
server.listen(Number(process.argv[2]))

Reader Interactions

Deja un comentario

Tu dirección de correo electrónico no será publicada.

About David Moya

Apasionado de la Seguridad Informática, aprendiendo en todo momento y profundizando en el mundo web y en el posicionamiento en buscadores.

Share This