Skip to content

Commit

Permalink
docs: add english and portuguese README
Browse files Browse the repository at this point in the history
  • Loading branch information
ViniciusMarchi committed Jan 10, 2023
1 parent ba903af commit 9cbbcc1
Show file tree
Hide file tree
Showing 3 changed files with 344 additions and 1 deletion.
172 changes: 171 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,171 @@
# go-graphql-password-validator
<p align="center">
<a href="./README_pt-BR.md">Portuguese Version </a>
<span>:brazil:</span>
</p>

<details>
<summary>Table of contents</summary>

* [The project](#the-project)
* [API Dataflow](#api-dataflow)
* [Running API](#running-api)
* [With Docker](#with-docker)
* [Without Docker](#without-docker)
* [Consuming API](#consuming-api)
* [Query](#query)
* [Arguments](#arguments)
* [Unit and integration tests](#unit-and-integration-tests)
* [Project directory structure](#project-directory-structure)
</details>

# The project
GraphQL API that performs password validation based on a set of password validation rules chosen by the user.

Main technologies used:
* Golang
* [Gqlgen](https://gqlgen.com/)
* Docker

## API Dataflow
![Data flow diagram of the API](./assets/api-flow-diagram.png)

The data flow (shown in the figure above), in a simplified way, is defined as follows: the user makes a `query` providing a password and a set of password validation rules. The rules chosen by the user will be used to validate the provided password.

The `query` is received by the `resolver`, which extracts the data from the query and represents it within the API, and subsequently passes the data on to the `input check`, the module responsible for validating that the data format is correct. For example, in the case of the rules, they can be an empty list `[]` (in this scenario, every password will be valid), however, when defined, they must respect the format `{ rule: <RULE_NAME>, value: <RULE_VALUE> }`. As an example, a rule without the `<value>` field (e.g. `{ rule: <rule> }`) does not respect the expected format, so it is invalid. Another point to consider is the `<value>` field. This field does not accept negative values by definition. For example, imagine that the chosen rule is that the password must have a minimum number of digits. It doesn't make sense for a password to have a minimum of -1 digits, so negative numbers as rule values are not accepted.

If the input format is not respected, a descriptive error of the problem is informed to the user. If the data is in the correct format, the flow continues and the data is passed on to the module that actually validates the password, the `password validator`, which checks if the password meets the rules established by the user. The result of this process is sent to the user as a response.

# Running API
## With Docker
Ensure that the necessary dependencies are installed, these being: Docker and Docker Compose (optional, as it helps in building the image and container, but this action can be done manually).

With Docker Compose installed, go to the root folder of the project and run:
```bash
docker-compose up
```

Wait for the image and container to build. After the process is complete, the API will be available at http://localhost:8080/graphql

Note: If you chose not to use Docker Compose, that's fine. You can still build the container manually with the following commands:
1. Build image
```bash
docker build -t <image-name> .
```

2. Build container
```bash
docker run -p 8080:8080 <image-name>
```
In the end, we will also have the API running at http://localhost:8080/graphql

## Without docker
Make sure you have Go version 1.19.3 or higher. After that, go to the root folder of the project and install the dependencies with the command:
```bash
go mod download
```

Wait for the dependencies to download and run:
```bash
go run server/server.go
```

After that, the server will be available at http://localhost:8080/graphql

# Consuming API
## Query
To consume the API, just build a GraphQL query in the format shown below. The query is used to validate a password based on a set of rules.

```graphql
{
verify(
password:<PASSWORD>,
rules: [{rule:<RULE_NAME>, value: <RULE_VALUE>}]
) {
verify
noMatch
}
}
```
### Arguments
The query consists of a single field called `verify`, which takes two arguments: `password` and `rules`.

* `password (string)`: represents the password to be verified.
* `rules (json)`: contains objects specifying the rules to be applied to the password. Each object has two fields:
* `rule (string)`: represents the name of the rule.
* `value (int)`: represents the value of the rule.

### Fields
To use this query, just substitute the placeholders `<PASSWORD>`, `<RULE_NAME>`, and `<RULE_VALUE>` with the desired values. The format of the rules is described below in [Rules](#rules).

The returned result is an object with two fields: `verify` and `noMatch`.

* `verify (boolean)`: result of the password validation. `True` if the password is valid, `False` if it is invalid.
* `noMatch (list[string])`: list of rules that were not satisfied by the password. If the password is valid, this list will be empty.

## Rules
The rules for validating passwords have the following format:

`{rule:<RULE_NAME>, value: <RULE_VALUE>}`

`rule` is a `string` and represents the name of the rule and `value` are positive integers.

The table below lists the available rules for password validation.

| rule name | accepted values | description |
| ------------- | ---------------------------- | ---------------------------- |
`minSize` | positive integer (ex: 1,2,3,4...) | set a minimum size
`minUppercase` | positive integer | sets a minimum amount of capital letters
`minLowercase` | positive integer | sets a minimum amount of lowercase letters
`minDigit` | positive integer | sets a minimum amount of digits (0-9)
`minSpecialChars` | positive integer | sets a minimum amount of special characters (e.g `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `-`,`+`,`/`,`{`,`}`,`[`,`]`)
`noRepeted` | positive integer (this value will be ignored) | defines that two or more sequential characters must not be repeated (ex: `senha` is valid, but `seenha` is not, because the character `e` was repeated sequentially

# Unit and integration tests
The project is covered by unit and integration tests. To run the tests:

* On Unix systems:
Basta executar o script `run_tests.sh com o comando:`
```bash
bash run_tests.sh
```


* On Windows systems, to run a bash script, some extra programs are needed (such as Cygwin). So, I recommend that you directly run the command contained in the `run_test.sh` script, so:
```bash
go test graphpass graphpass/password graphpass/utils -cover
```


# Project directory structure
```
.
├── graph
│ ├── model // graphql model
│ │ └── models_gen.go
│ ├── resolver
│ │ ├── resolver.go
| | └── verify.go // resolver that handle verify query
│ ├── schema
│ | └── schema.graphqls // graphql schema
│ └── generated.go // runtime generated code by gqlgen
├─ password // rule based password validator module
│ ├── password_check_test.go
| └── password_check.go
├─ server
│ └── server.go // api entrypoint
├─ utils // utils to help validate and structure input data
│ ├── map2struct_test.go
│ └── map2struct.go
├─ api_integration_test.go // API integration tests
├─ docker-compose.yml
├─ Dockerfile
├─ go.mod // manages the list of application packages
├─ go.sum // package integrity
├─ gqlgen.yml // gqlgen library configuration file
├─ README.md
└─ run_tests.bash // script that run all tests
```
173 changes: 173 additions & 0 deletions README_pt-BR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<p align="center">
<a href="./README.md">Versão em Inglês </a>
<span>:us:</span>
</p>


<details>
<summary>Tabela de Conteúdos</summary>

<!-- # Tabela de conteúdos -->
* [O projeto](#o-projeto)
* [Fluxo de dados](#fluxo-dos-dados)
* [Executando o projeto](#executando-o-projeto)
* [Com Docker](#com-docker)
* [Sem Docker](#sem-docker)
* [Consumindo a API](#consumindo-a-api)
* [Formato da Query](#formato-da-query)
* [Formato das Regras](#formato-das-regras)
* [Testes de unidade e integração](#testes-de-unidade-e-de-integração)
* [Estrutura de diretórios](#estrutura-de-diretórios-do-projeto)
</details>

# O projeto
API GraphQL que realiza a validação de senha se baseando em um conjunto de regras de validação de senha escolhidas pelo usuário.

Principais tecnologias utilizadas:
* Golang
* [Gqlgen](https://gqlgen.com/)
* Docker

## Fluxo dos dados
![Diagrama do fluxo de dados da API](./assets/api-flow-diagram.png)

O fluxo de dados (demonstrado pela figura acima), de maneira simplificada, é definido da seguinte maneira: o usuário realiza uma `query` informando uma senha e um conjunto de regras de validação de senha. As regras escolhidas pelo usuário serão utilizadas para validar a senha informada.

A `query` é recebida pelo `resolver`, o qual extrai os dados da query e os representa dentro da API, posteriormente repassa os dados para o `input check`, módulo responsável por validar se o formato dos dados estão corretos. Por exemplo, no caso das regras, elas podem ser uma lista vazia `[]` (nesse cenário toda senha será válida), entretanto, quando definidas, devem respeitar o formato `{ rule: <NOME_DA_REGRA>, value: <VALOR_DA_REGRA> }`. Como exemplo, uma regra sem campo `<value>` (ex: `{ rule: <regra> }`) não respeita o formato esperado, logo é inválida. Outro ponto observado é o campo `<value>`. Esse campo não aceita valores negativos por definição, por exemplo, imagine que a regra escolhida é que a senha possua um número minímo de digitos, logo, não faz sentido que uma senha tenha no mínimo -1 dígito, por isso números negativos como valores de regras não são aceitos.

Se o formato do input não for respeitado um erro descritivo do problema é informado ao usuário. Se os dados estiverem no formato correto o fluxo continua e eles serão repassados para o módulo que valida a senha de fato, o `password validator`, que verifica se a senha cumpre as regras stabelecidas pelo usuário, o resultado desse processo é enviado ao usuário como resposta.

# Executando o projeto
## Com Docker
Garanta que dependências necessárias estão instaladas, sendo elas: Docker e Docker Compose (opcional, pois auxilia na construção da imagem e do container, mas essa ação pode ser feita manualmente).

Com o Docker Compose instalado acesse a pasta raiz do projeto e execute:
```bash
docker-compose up
```

Aguarde a construção da imagem e do container, após o processo completo a API estará disponível em http://localhost:8080/graphql

Obs: Se você optou por não utilizar o Docker Compose não há problemas, ainda é possível construir o container manualmente com os seguintes comandos:

1. Construa a imagem
```bash
docker build -t <image-name> .
```

2. Depois, construa o container
```bash
docker run -p 8080:8080 <image-name>
```
Ao final, também obteremos a API executando em http://localhost:8080/graphql

## Sem docker
Certifique-se de instalar Go na versão 1.19.3 ou superior. Após isso, acesse a pasta do projeto e instale as dependências com o comando:
```bash
go mod download
```

Aguarde as dependências baixarem e execute:
```bash
go run server/server.go
```

Após isso, o servidor estará disponível em http://localhost:8080/graphql


# Consumindo a API
## Formato da query
Para consumir a API basta constrir uma query GraphQL no formato demonstrado abaixo. A query é usada para validar uma senha com base em um conjunto de regras.

```graphql
{
verify(
password:<PASSWORD>,
rules: [{rule:<RULE_NAME>, value: <RULE_VALUE>}]
) {
verify
noMatch
}
}
```
### Argumentos
A query consiste em um único campo chamado `verify`, que recebe dois argumentos: `password` e `rules`.

* `password (string)`: representa a senha a ser verificada.
* `rules (list[object])`: contém uma lista de objetos especificando as regras a serem aplicadas à senha. Cada objeto possui dois campos:
* `rule (string)`: representa o nome da regra.
* `value (int)`: representa o valor da regra.

### Fields
Para usar essa query basta substituir os placeholders `<PASSWORD>`, `<RULE_NAME>` e `<RULE_VALUE>` pelos valores desejados. O formato das regras é descrito abaixo [Formato da Regra](#Formato-da-regra)

O resultado retornado é um objeto com dois campos: `verify` e `noMatch`.

* `verify (boolean)`: resultado da validação da senha. `True` se a senha for válida, `False` se for inválida.
* `noMatch (list[string])`: lista de regras que não foram satisfeitas pela senha. Se a senha for válida essa lista estará vazia.

## Formato das regras
As regras para validar as senhas possuem o seguinte formato:

`{rule:<RULE_NAME>, value: <RULE_VALUE>}`

`rule` é uma `string` e representa o nome da regra e `value` são inteiros positivos.

A tabela abaixo exibe as regras disponíveis para a validação de senha.

| nome da regra | valores aceitos | descrição |
| ------------- | ---------------------------- | ---------------------------- |
`minSize` | inteiro positivo (ex: 1,2,3,4...) | define um tamanho mínimo
`minUppercase` | inteiro positivo | define uma quantidade mínima de letras maíusculas
`minLowercase` | inteiro positivo | define uma quantidade mínima de letras minúsculas
`minDigit` | inteiro positivo | define uma quantidade mínima de digitos (0-9)
`minSpecialChars` | inteiro positivo | define uma quantiade mínima de caracteres especiais (ex: `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `-`,`+`,`/`,`{`,`}`,`[`,`]`)
`noRepeted` | inteiro positivo (esse valor será ignorado) | define que dois ou mais caracteres sequencias não devem se repetir (ex: senha é válido, mas seenha não, pois o caractere `e` se repetiu de maneira sequencial)

# Testes de unidade e de integração
O projeto é coberto por testes de unidade e de integração. Para executar os testes:

* Em sistemas Unix.
Basta executar o script `run_tests.sh com o comando:`
```bash
bash run_tests.sh
```

* Em sistemas Windows para executar um script bash se faz necessário alguns programas extras (como Cygwin), por isso recomendo que simplesmente execute diretamente o comando contido no script `run_test.sh`, ou seja
```bash
go test graphpass graphpass/password graphpass/utils -cover
```

# Estrutura de diretórios do projeto
```
.
├── graph
│ ├── model // modelos graphql
│ │ └── models_gen.go
│ ├── resolver
│ │ ├── resolver.go
| | └── verify.go // resolver que lida com a query verify
│ ├── schema
│ | └── schema.graphqls // schema graphql
│ └── generated.go // código gerado em runtime pelo pacote gqlgen
├─ password // módulo de validação de senha baseado em regras
│ ├── password_check_test.go
| └── password_check.go
├─ server
│ └── server.go // api entrypoint
├─ utils // utilitários que ajudam a validar e estruturar os dados de input
│ ├── map2struct_test.go
│ └── map2struct.go
├─ api_integration_test.go // testes de integração da API
├─ docker-compose.yml
├─ Dockerfile
├─ go.mod // gerencia a lista de pacotes da aplicação
├─ go.sum // garantia de integridade dos pacotes
├─ gqlgen.yml // arquivo de configuração biblioteca gqlgen
├─ README.md
└─ run_tests.bash // script que executa todos os testes
```
Binary file added assets/api-flow-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9cbbcc1

Please sign in to comment.