Introdução ao Parse

Sou um grande fan do Parse, uma solução que torna o desenvolvimento de aplicações para o mobile e web muito mais simples e rápida. O Parse permite que você sincrionize informações na nuvem sem a necessidade de uma linguagem de servidor, ou server side. Acompanhe este artigo aprender a integrar o Parse no seu próximo projeto.

Este post faz parte do projeto que participo de tradução dos artigos dos blogs da Envato, Webdesigntuts+, Gamedevelopmenttuts+ e Nettuts+. Todos os direitos reservados para Envato.

Link para artigo original: Getting Started with Parse
Autor do artigo original: Tilo Mitra
Link da Envato para o artigo traduzido: Introdução ao Parse


Informações do ramo

Intaragir com uma base de dados é muito cansativo!

Vamos dar um passo atrás e analisar como andava o desenvolvimento web cinco anos atrás. Utilizávamos linguagens server side como PHP ou Ruby no back end dos sistemas para interagir com base dados relacionais (tipo o MySQL), e vários blocos de código em JavaScript para o front end. Não sei vocês, mas a maioria dos meus projetos estão em servidores com pouco espaço, memória e banda.

Muitas soluções levaram a nuvem a sério, então é comum desenvolvedores se aproveitarem desses serviços que geram custo benefício, como a AWS, Amazon S3, Heroku, entre outros. O surgimento dessas soluções certamente mudou a forma de trabalhar nessa área; cada vez mais o que nós fazemos (informações) está sendo armazenado na nuvem.

Hoje vamos dar uma olhada no Parse, uma startup que oferece um sistema de gerenciamento de dados na nuvem e que simplifica o desenvolvimento de aplicações web. Utilizando o Parse, fui capaz de criar rapidamente novos apps para mobile e para web. Neste tutorial vamos utilizar o Parse para criar o obrigatório To-do app, acredito que com esse exemplo você já consiga entender como funciona o Parse.

Envato Todo List App

O que é o Parse?

Simplificando, o Parse é uma plataforma que permite manipular informações em uma base dados e a criação rápida de apps para web e mobile.

O desenvolvimento fica realmente muito simples quando você não precisa se preocupar com o back-end.

Então, como funciona o Parse? Bom, vamos assumir que você é um desenvolvedor web. Você adiciona o arquivo JavaScript do Parse na sua página, solicita sua API Key, e então já pode começar a salvar objetos na nuvem com apenas algumas linhas de código. O Parse te livra da configuração de um servidor para armazenar e gerenciar dados.

Pense nisso por um minuto. Geralmente, configuramos uma servidor padrão (LAMP, RoR, APS.NET ou qualquer outro), configuramos a base de dados, e depois interagimos com a mesma utilizando Ajax no cliente. O Parse reduz este trabalho a apenas algumas linhas de JavaScript.

Neste tutorial, vamos utilizar o SDK JavaScript do Parse. Você não precisa utilizar apenas JavaScript; existem bibliotecas do Parse em várias linguagens, incluindo PHP, NodeJS, Java, C#, entre outras. Você pode encontrar todas as bibliotecas disponíveis neste link.


Utilizando o Parse para projetos Web

Antes de começarmos, vamos pensar na lógica de criação de um To-do app utilizando um servidor LAMP.

  • Vamos criar uma base de dados no MySQL.
  • Devemos ter uma classe ou várias funções em PHP para operações CRUD.
  • Utilizamos JavaScript ou Ajax no cliente para chamar os scripts PHP para execução dos scripts no servidor.
  • Vamos precisar configurar a segurança do servidor para evitar ataques e garantir a segurança da base dados.
  • Se for um app colaborativo, você vai precisar monitorar diferentes usuários e suas listas. Mais código, mais tabelas e mais lógica.
  • Você precisa ter certeza que sua base de dados está OK.

Você deve ter entendido. Existem muitos pontos que devemos atenção e muitas áreas que podem proporcionar falhas. O Parse cuida dessa parte cansativa para nós.

Criando uma conta no Parse

Antes de mais nada, crie uma conta grátis no Parse. Depois crie um app chamado EnvatoTodo.

Criando um novo app no Parse

Download do Empty Project

O Parse tem um ótimo guia de introdução para ajudar iniciantes. Selecione JavaScript e escolha EnvatoTodo no menu dropdown conforme o passo 2 (imagem abaixo). O Parse vai gerar um arquivo zipado com o seu SDK e o arquivo index.html.

Parse Quickstart Guide


O lado do cliente/client-side

Antes de começarmos a interagir com o Parse, vamos configurar uma estrutura básica no cliente para nossa aplicação. Como o design UI não é o foco deste tutorial, vou apresentar apenas o código que eu usei. Estou utilizando YUI3. Você pode utilizar jQuery se quiser. Tudo está no arquivo index.html.

<!DOCTYPE html>
<head>
  <meta charset="utf-8">

  <title>Todo App Built on Parse</title>
  <meta name="description" content="My Parse App">
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="css/reset.css">
  <link rel="stylesheet" href="css/styles.css">
  <script src="http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js"></script>
  <script type="text/javascript" src="http://www.parsecdn.com/js/parse-1.0.19.min.js"></script>

<style>
        body {
            font-family: "HelveticaNeue-Light", sans-serif;
            font-weight:300;
        }
        h2 {
            font-size:16px;
            text-transform:uppercase;
        }
        a {
            text-decoration:none;
        }
        .hidden {
            display:none;
        }
        #main {
            text-align:center;
        }
        input {
            padding: 10px;
            border-radius: 3px;
            border:1px solid #ccc;
            box-shadow: inset 0 0 10px #eee;
            font-size:24px;
        }

        #input-wrapper {
            padding-bottom:15px;
        }

        #list-item-submit {
            background: #73D175;
            color: white;
            box-shadow:none;
            border-color: #599E5A;
        }

        li {
            text-align:left;
            font-family:sans-serif;
            list-style: none;
            padding: 10px 0;
            border-bottom:1px solid #ccc;
            margin-left:-10px;      
        }
        li input {
            margin-right:15px;
        }
    </style>
</head>

<body>
  <h1>Todo List built on <a href="http://www.parse.com" alt="Parse">Parse</a></h1>
  <div id="main">
        <div id="input-wrapper">
            <input type="text" id="list-input" placeholder="Enter a todo here...">
            <input type="button" id="list-item-submit" value="Add">
        </div>
        <div>
            <h2>Incomplete Tasks</h2>
            <ul id="incomplete-items">
                <li id="no-incomplete-message">There are no incomplete tasks! Consider adding one above.</li>
            </ul>
        </div>
  </div>

    <!-- template que vamos utilizar para criar a lista -->
    <script id="todo-items-template" type="x/handlebars">
        <li class="list-item"><input type="checkbox" id="{id}">{content}</li>
    </script>

    <script>
        //YUI 'node' module
        YUI().use('node', function(Y) {

            //declaramos algumas variáveis que vamos utilizar
            var ListItem,
            query,
            noTasksMessage = Y.one('#no-incomplete-message'),
            submitBtn = Y.one("#list-item-submit"),
            incompleteItemList = Y.one('#incomplete-items'),
            completeItemList = Y.one('#complete-items'),
            input = Y.one("#list-input");

            //resto da aplicação.

            submitBtn.on('click', function(e) {

                /*
                quando o botão submit é clicado, pegamos as informações do input e salvamos na lista de todos.
                */

            });


            /*

            quando um <li> é clicado, vamos salvar o item como completo. aqui utilizamos o 'delegate' ao invés do 'on' assim utilizamos apenas um event listener ao invés de um para cada checkbox.
            */

            incompleteItemList.delegate('click', function(e) {

            }, 'li');


            /* também queremos visualizar as ultimas dez tarefas incompletas e adicionar a div <div id="incomplete-items"></div> */


        });
    </script>
</body>

</html>

Importante notar a inclusão do arquivo JavaScript do Parse na linha <script src="http://www.parsecdn.com/js/parse-1.0.19.min.js"></script>. Esse arquivo contém o objeto do Parse que vamos interagir.

Adicionando Classes ao Data Browser

O Parse te livra da configuração do servidor/server-side.

Vamos voltar ao Parse. Veja que menu de informações (data browser) para o nosso app EnvatoTodo ainda está vazio. O menu de informações é similar ao menu de base de dados do MySQL, porém o do Parse é mais schema-less, em português, é mais simples/tem menos lógica. Enquanto você cria colunas no menu, você pode salvar qualquer objeto com apenas um simples JSON (diferente de muitas base de dados NoSQL). Essa é um recurso extremamente importante e útil do Parse.

Vamos continuar e adicionar uma “class” a base de dados. Pense na classe como uma tabela. A razão pela qual é chamado de “class” é porque a partir de classes você cria objetos, e estes são salvos na base dados.

Aviso: O JavaScript não suporta oficialmente classes (por enquanto), mas possui o equivalente logico. Para garantir a simplicidade, vamos utilizar a “class” presente neste tutorial.

O Parse possui cinco tipos de classes.

  • User classes para guardar dados de usuários, além disso o Parse fornece métodos como signUp(), login(), entre outros para ajudar na administração.
  • Installation classes são utilizadas geralmente para notificações push em mobile apps. O Parse suporte notificações push em todos os clientes.
  • Role classes ajuda a controlar regras de usuários através das permissões de ler e escrever. No Parse isso é chamado de ACL (access control list/lista de controle de acesso).
  • Product classes guardam informações do app.
  • Custom classes são para qualquer outra necessidade.

Vamos criar uma custom class chamada ListItem. Assim que ela estiver criada, você vai notar que ela já vai possui quatro propriedades. O Parse atualiza automaticamente as propriedades de qualquer classe criada. Algumas classes, como as classes de usuário/user classes, precisam de propriedades especificas.

Nossos objetos ListItem vão conter uma propriedade content para mostrar o que tem para fazer, o Todo do app, e uma propriedade isComplete para indicar que a tarefa está finalizada. Podemos adicionar colunas nessas propriedades, mas o Parse vai puxar essas informações do nosso JSON.


Inicializando o Parse

Vamos voltar o arquivo index.html para adicionar um pouco de código. A primeira coisa que precisamos fazer é inicializar o Parse com nosso App ID e a chave/key JavaScript sobrepondo os campos APP_ID e JS_KEY com os seus dados:

Parse.initialize(APP_ID, JS_KEY);

Salvando Todos/tarefas

Vamos começar adicionando funcionalidades a nossa aplicação. Primeiro vamos salvar um tarefa quando o usuário clicar no botão add. O bloco de código abaixo é tudo que precisamos pra executar essa operação:

submitBtn.on('click', function(e) {

//Extend Parse.Object class.
    var ListItem = Parse.Object.extend("ListItem");

    //novo objeto da classe listItem
    var listItem = new ListItem();

    //listItem agora é o obejto que queremos salvar, então declaramos as propriedades do mesmo.
    listItem.set("content", text);
    listItem.set("isComplete", false);

    //executamos o método para salvar e os callbacks para sucesso ou falha da operação
    listItem.save(null, {      
        success: function(item) {
        //Sucesso Callback
    },
    error: function(gameScore, error) {
        //Falha Callback
    }
    });
});

Interagir com uma base de dados é extremamente cansativo! Toda custom class do Parse é gerada a partir do Parse.Object; então, ListItem é uma sub classe. A linha que contem o argumento "ListItem" informa ao Parse que essa classe está relacionada com a tabela ListItem que nós criamos. Então, criamos um novo objeto ListItem, configuramos suas propriedades, e executamos o método save().

Exibindo tarefas

Precisamos apresentar uma listas das tarefas a fazer, para isso vamos utilizar a Parse JavaScript API para processar os dez últimos itens salvos. Isso vai te dar uma ideia de como funcionam as queries no Parse.

//novamente, criamos uma classe ListItem a partir da Parse.Object
ListItem = Parse.Object.extend("ListItem");

//agora, utilizamos o Parse.Query para gerar uma querie no ListItem
query = new Parse.Query(ListItem);

//aqui limitamos um pouco a query.
query.equalTo('isComplete', false)
query.limit = 10;
query.descending('createdAt');

//executamos a query, e os callbacks em caso de sucesso ou falha
query.find({
  success: function(results) {
//sucesso callback
  },
  error: function(error) {
    //erro Callback
  }
});

Veja, novamente, como é simples a leitura do código. O método Parse.Query() é bem poderoso. Aqui simulamos uma query bem básica, mas o Parse também é capaz de executar queries mais complexas. Você pode executar queries para expressões especificas, queries relacionais, e mais. Dê uma olhada na Documentação sobre Queries/Query Documentation para mais exemplos e testes práticos.

Juntando tudo isso

O próximo passo é criar o recurso de marcar como finalizada uma tarefa de acordo com uma checkbox. Cada checkbox tem um único ID relacionado ao objeto do Parse que este representa. Quando uma checkbox é marcada, precisamos:

  • Pegar o ID.
  • Executar uma query para localizar um Parse Object com o mesmo ID.
  • Após retornar o Parse object, atualizamos a propriedade isComplete para true.
  • Salvamos o objeto atualizado.
  • Removemos o item da lista apresentada.

Abaixo o código que vamos utilizar:

incompleteItemList.delegate('click', function (e) {

//tenha uma refência para o this
    var self = this;

    //criamos a query
    var query = new Parse.Query(ListItem);

    //o método query.get() requer o objectId como primeiro argumento. ele retorna o objeto com o mesmo ID.
    query.get(self.one('input').get('id'), {
      success: function(item) {

        //após retornar o valor do objeto, atualizamos sua propriedade e salvamos o mesmo.
        item.set('isComplete', true);
            item.save();

            //como o item não está mais incompleto, ele é removido da lista
            self.remove();

            //se não houver nada na lista, apresentar informação de que a lista está vazia.
            if (incompleteItemList.all('li').size() >= 1) {
                noTasksMessage.removeClass('hidden');
            }

      },
      error: function(object, error) {
            alert("Erro ao atualizar a tarefa: " + error.code + " " + error.message);
      }
    });
}, 'li');

Neste snippet, executamos uma query para um único elemento com id especifico, atualizamos, e salvamos o mesmo. Depois, removemos o item da lista com o método self.remove().

No Parse, atualizar objetos é muito parecido com salvar objetos — utilizamos o método save() nos dois casos. O Parse identifica se aquele já é um objeto existente, e partir daí executa a ação apropriada.


Código fonte completo

Com isso, estamos prontos! Fácil não? Baixe o arquivo ZIP e de uma fuçada no arquivo index.html para ver o código fonte completo.

Outro recursos

Neste tutorial, analisamos o Parse como desenvolvedores. De qualquer forma, o projeto foi criado pensando em desenvolvedores mobile. O Parse tem uma SDK bem robusta para o Android e iOS, e possui recursos com notificações push para todos os usuários do seu app.

Outros recursos que não analisamos neste tutorial foram usuários, regras, e como guardar informações relacionadas.

Com o Parse é relativamente simples criar usuários e definir diferentes regras de acesso. Por exemplo, em um sistema de ensino/escola, você pode ter “professores”, “estudantes” e “administradores”. Definindo regras, você pode especificar que tipo de usuário tem acesso a certos objetos do Parse.

E a segurança?

Uma porção de tecnologias utilizam serviços na nuvem…

Como desenvolvedor, eu considero que o Parse de conta de problemas de segurança. Como informado no site da solução, o Parse foi elaborado para que você não se preocupe em como as informações foram salvas. Persiste o problema de qualquer usuário conseguir acessar qualquer informação, mas podemos resolver isso utilizando as permissões Object-level e Class-level.

As permissões Object-level permitem ao desenvolvedor especificar um array para ler e escrever em objetos. As permissões Class-level permitem especificar quais informações podem ser manipuladas a partir da API. As operações podem ser executadas ou não com base em cada classe: get, find, update, create, delete, e add fields (operações relacionadas a API).

Pros e Contras

O Parse não é ideal para qualquer tipo de projeto. Mesmo assim, o plano grátis é bem generoso (o Parse é um produto pago). Ele pode ser bem caro se você ultrapassar alguns limites. Pelo menos, o preço é bem justo e você deve ter em mente quanto seu app gasta em média. Utilizo o Parse em projetos pequenos, ainda não cheguei a testa-lo em projetos grandes.

Um problema comum em serviços como o Parse é o efeito lock-in.

Se você utilizar o Parse para certo projeto, e de repente deixa de utilizar o serviço, pode dar um certo trabalho transferir as informações para outro serviço similar. Como você pode imaginar, substituir o Parse pelo seu próprio back-end pode gerar bastante trabalho. Isso não significa que você não deve utilizar o Parse, é apenas algo que você precisa ter em mente.


Conclusão

Neste tutorial analisamos como podemos utilizar o Parse para criar simples aplicações web. Já utilizei o Parse em vários projetos para vários clientes, e o pessoal do suporte do Parse ajuda bastante quando surge um problema. Vale a pena conferir o serviço, e tirar as próprias conclusões.

Nota: não tenho nenhuma ligação com o Parse ou com quem trabalha na empresa. Sou apenas um desenvolvedor que testou a solução e achou que poderia ser útil escrever sobre, para os demais desenvolvedores. Ela ajudou muito a melhorar meu workflow, é por isso que criei e compartilho com vocês este tutorial.