Skip to content
This repository has been archived by the owner on Aug 13, 2020. It is now read-only.

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MauricioRobayo committed Dec 3, 2018
0 parents commit fa08828
Show file tree
Hide file tree
Showing 34 changed files with 13,333 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Normalizes editor configuration.
# http://editorconfig.org
root = true

[src/**.js]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
# Two spaces in markdown is the same as a <br>.
# Removing them changes the output of the markdown.
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
10 changes: 10 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
extends: ["airbnb-base", "prettier"],
env: {
jest: true
}
// rules: {
// "require-jsdoc": "error",
// "valid-jsdoc": "error"
// }
};
63 changes: 63 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
dist

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next
21 changes: 21 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
language: node_js
sudo: false
cache:
directories:
- $HOME/.npm
notifications:
email:
on_failure: always
install:
- npm install
- pip install --user awscli
- pip install --user aws-sam-cli
node_js:
- "8.10"
script:
- npm run sam:validate
- npm run lint
- npm test
- npx codecov
after_success:
- npx semantic-release
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Mauricio Robayo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
191 changes: 191 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# TRMAPI

JSON API para consultar la [Tasa Representativa del Mercado](http://www.banrep.gov.co/es/tasa-cambio-del-peso-colombiano-trm) (TRM) en el [Servicio Web](https://www.superfinanciera.gov.co/inicio/60819) de la Superintendencia Financiera de Colombia (SFC).

Esta API es una función Lambda que se ejecuta en AWS y a la cual se accede por API Gateway, lo que garantiza su estabilidad, escalabilidad y rapidez.

La función lambda solicita la información al servicio web de la SFC y almacena el valor de la TRM en una tabla de Dynamodb.

Al usar esta API se reduce la carga sobre los servidores de la SFC y se garantiza la disponibilidad del servicio.

## Uso

El servicio es gratuito y de libre acceso. Todas las solicitudes se hacen usando el método `GET` especificando el recurso solicitado a la url base:

https://api.trmapi.com/

Por ejemplo, para acceder a la información de la TRM del día 11 de octubre de 2018:

```http
GET https://api.trmapi.com/2018-03-29 HTTP/1.1
{
"value": 2780.47,
"date": "2018-03-29",
}
```

Todos los endpoints aceptan el parámetro `validity` que indica si se desea consultar el rango de validez de un dato:

```http
GET https://api.trmapi.com/2018-03-29?validity=true HTTP/1.1
{
"value": 2780.47,
"date": "2018-03-29",
"validityTo": "2018-04-02T00:00:00-05:00",
"validityFrom": "2018-03-29T00:00:00-05:00"
}
```

### Endpoints

Obtener la información más reciente de la tasa de cambio:

```http
GET https://api.trmapi.com/latest HTTP/1.1
```

Obtener un valor de una fecha en específico de la tasa de cambio a partir de `2013-01-01`:

```http
GET https://api.trmapi.com/2015-09-21 HTTP/1.1
```

Obtener los valores diarios de la tasa de cambio entre dos fechas. Se limita a un máximo de 365 días devueltos y la fecha mínima es `2013-01-01`:

```http
GET https://api.trmapi.com/timeseries?start_date=2017-01-01&end_date=2017-12-31 HTTP/1.1
```

### Errores

Cuando se solicita un recurso que no está disponible o hay un error en la API por alguna otra razón, se devuelve el código del error en los encabezados de la respuesta acompañado de un objecto JSON indicando el mensaje del error.

| Código | Descripción |
| ------ | ------------------------------------------------------------ |
| 404 | No se encontró la fecha solicitada |
| 422 | La fecha solicitada no es una fecha válida |
| 502 | Se ha recibido una respuesta inválida del servidor de la SFC |
| 504 | Se agotó el tiempo de respuesta para el servidor de la SFC |

Ejemplo de una solicitud errónea:

```http
GET api.trmapi.com/2017-1-10 HTTP/1.1
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": "La fecha solicitada debe ser una fecha válida en formato 'YYYY-MM-DD'. La fecha solicitada '2017-1-10' no es una fecha válida."
}
```

## Desplegar en AWS

Para desplegar la API se debe contar con:

- Cuenta de [Amazon Web Services](https://aws.amazon.com/es/) (AWS)
- [Credenciales de AWS](https://docs.aws.amazon.com/es_es/cli/latest/userguide/cli-config-files.html)
- [aws-cli](https://docs.aws.amazon.com/es_es/cli/latest/userguide/installing.html)
- [aws-sam-cli](https://docs.aws.amazon.com/es_es/lambda/latest/dg/sam-cli-requirements.html)

Una vez confirmados los requisitos anteriores se debe clonar el repositorio:

```shell
git clone https://github.com/archemiro/trmapi.git
```

Ingresar a la carpeta:

```shell
cd trmapi
```

Ejecutar el script `deploy`:

```shell
npm run deploy
```

Esto creará los siguientes recursos en la cuenata de AWS:

1. Tabla de DynamoDB
2. API Gateway
3. Función Lambda

Al final del script se mostrarán la información de los recursos creados, incluidos la url de la API (`ApiUrl`):

```json
[
{
"OutputKey": "DateApi",
"OutputValue": "trmapi-DateApi-XXXXXXXXXXX"
},
{
"OutputKey": "ApiUrl",
"OutputValue": "https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/Prod/latest"
},
{
"OutputKey": "TrmTable",
"OutputValue": "trmapi-TrmTable-XXXXXXXXXXX"
}
]
```

Tenga en cuenta que la tabla de DynamoDB creada no contendrá la información histórica de la TRM por lo que el endpoint `timeseries` que permite consultar rangos históricos no proveerá datos.

Para llenar los valores históricos se pude ejecutar un script como el siguiente que llamará a la API para cada fecha desde `2013-01-01` hasta la fecha actual lo que hará que los datos se vayan guardando en la tabla de DynamoDB:

```bash
#!/bin/bash

dCurrent="2013-01-01"
dEnd="$(date -I)"
until [[ $dCurrent > $dEnd ]]; do
printf "Writing $(date -Im) "
curl -s {{ApiUrl}}/$dCurrent | jq -r '"\(.date) \(.value)"'
d=$(date -I -d "$dCurrent + 1 day")
sleep 1
done
```

Se escribe un dato cada segundo ya que la `WCU` de la tabla creada es `1`. Se puede aumentar moficando la definición de la tabla en la [plantilla de SAM](template.yaml).

También puede cargar los datos deel archivo [`csv`](dynamodb/data.csv) que se encuentra en la carpeta `dynamodb` directamente a la tabla. Este archivo es usado para cargar la base de datos local para desarrollo y se proporciona el el script [bootstrap-remote.js] para cargar los datos en la tabla de AWS (asegúrese de usar el nombre de la tabla correspondiente):

```js
node dynamodb/bootstrap-remote.js
```

Puede consultar el nombre de la tabla creada ejecutando `npm run outputs`.

## Desarrollo

Instalar las dependencias:

````sh
npm i
```

Ejecutar el script `start:dev`:

```shell
npm run start:dev
```

Este script lanzará un contenedor con una base de datos de DynamoDB local, cargará en la tabla `trm` los datos de la trm, y usará `sam local` para crear una `API Gateway` local a la que se carga la función Lambda.

Se puede acceder a la API en desarrollo en `http://localhost:3000` y allí a cada uno de los endpoints disponibles, por ejemplo:

```http
GET http://localhost:3000/latest HTTP/1.1
```

## Licencia

[MIT](LICENSE)

Hecho en ![Bandera de Colombia](https://upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Colombia.svg/16px-Flag_of_Colombia.svg.png) con mucho ☕.
````
30 changes: 30 additions & 0 deletions __mocks__/cambio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const dates = {
"2018-10-31": {
status: 200,
trm: {
date: "2018-10-31",
validityFrom: "2018-10-31T00:00:00-05:00",
validityTo: "2018-10-31T00:00:00-05:00",
value: 3202.44
}
}
};

module.exports = date =>
new Promise(resolve => {
process.nextTick(() => {
resolve(
dates[date]
? dates[date]
: {
status: 200,
trm: {
date,
validityFrom: dates["2018-10-31"].trm.validityFrom,
validityTo: dates["2018-10-31"].trm.validityTo,
value: dates["2018-10-31"].trm.value
}
}
);
});
});
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: ["@babel/env"]
};
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: ["@commitlint/config-conventional"] };
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3"
services:
dynamodb:
image: amazon/dynamodb-local:1.11.119
ports:
- "8000:8000"
networks:
- dynamodb
networks:
dynamodb:
Loading

0 comments on commit fa08828

Please sign in to comment.