# Começando com o Backstage Spotify

A gente [já falou do Backstage](https://blog.backtostage.app/backstage-o-que-e-isso), mas como eu faço para começar **hoje** com ele?

Bora lá!

![gatinho digitando no computador](https://lh4.googleusercontent.com/vmtWe3s_ZK3Y8VtFxlKsZJoQb2uCBakgHTe9JkNdEs3kc6lwbUzhfKOGWhqinflN3i0BMn3K7L6mr_b979ryrYTDN8twgHLi185Is4Y4TjlUDA8EWYUPEIua9glwxWDlYv41Ad_w2594m2cL7OBxYCSFJUZTBBrberWnd1Ueiy0RXGHhS0TWClvDFCk18Q align="center")

## Criando a sua aplicação do Backstage

A primeira coisa que eu acredito que gera muita confusão nas pessoas é como começar no Backstage. É comum as pessoas olharem o [repositório](https://github.com/backstage/backstage) e pensar que ela vai usar **esse repositório** como aplicação, o que não é verdade.

Aqui eu quero que você imagine o Backstage quase como um conjunto de bibliotecas que te permitem fazer algo, e que você precisa “instalar” na sua aplicação. Muito parecido com o que o [Create React App](https://pt-br.reactjs.org/docs/create-a-new-react-app.html#create-react-app) faz, nós vamos iniciar um novo app a partir do [CLI do Backstage](https://backstage.io/docs/getting-started/create-an-app) (considerando que você já atende os [pré-requisitos](https://backstage.io/docs/getting-started/#prerequisites)), com o nome ["angeliski-stage"](https://github.com/backtostage/angeliski-stage)

![imagem do terminal com a criação da nova app](https://lh6.googleusercontent.com/920Rm2KsN15hoE96fAyuunxgwIElLspeQX_vKQVg4h2aKUTR4M4ajZ2nu7nLw_zw0Ic7Hvb6EULit6X5got6_fTQdi4AgWIBqqOUNAg82eyhR0KNoELExh1GsdeSPfv06d8d2JMeXcDfbB8KkTU8WUUHQA9XaxZXpwCY4LnCKmpix7AwZ8cYWrP9RLMxxg align="center")

Sem muito segredo: Você roda o comando, diz o nome da sua app, ele cria um [monorepo](https://dev.to/stanley/monorepo-o-que-e-devo-usar-133c) pronto para usar. Vamos dar uma olhada na estrutura das pastas criadas (Não se preocupe, vamos aprofundar isso ao longo do tempo):

```plaintext
├── README.md
├── app-config.local.yaml
├── app-config.production.yaml
├── app-config.yaml
├── backstage.json
├── catalog-info.yaml
├── examples
|  ├── entities.yaml
|  ├── org.yaml
|  └── template
├── lerna.json
├── package.json
├── packages
|  ├── README.md
|  ├── app
|  └── backend
├── plugins
|  └── 	README.md
├── tsconfig.json
└── yarn.lock
```

* app-config.\[ENVIROMENT\].yaml -  são os arquivos de configuração. Eles podem ser separados por ambiente e tem uma hierarquia sobrescrita na execução. Destaque para o arquivo local, que é apenas para uso local e não é comitado pois está no .gitignore
    
* backstage.json - É um arquivo que carrega informação da versão do Backstage que você está usando. Já fica a dica de usar o [hellper](https://backstage.github.io/upgrade-helper/) para atualização.
    
* catalog-info.yaml - arquivo de mapeamento do catalogo no Backstage
    
* examples - Alguns exemplos, para você já sair testando o catalogo
    
* packages/app - A aplicação front-end (React)
    
* packages/backend - A aplicação backend (Express)
    
* plugins - Essa pasta vai conter possíveis implementações internas de plugins
    

Nesse momento, você pode rodar um simples `yarn dev` na raiz do projeto e ver ele rodando (se você tiver clonado ele, rode um `yarn` antes).

![imagem obtida ao acessar a tela com o yarn dev](https://lh5.googleusercontent.com/G-dOhKaDVwyE0XRP4-ZuRF8ZGC5rKDGqqVtit8ABViH_83KKXNVZDjDgA0pQmX4zzDATnmR2uXDDUFfdlgfSznAL8XHrCyE9MKF05z8TyRQHURT4YhuB0i3TR1kxgpMxUZ5O8JS6SqqLlHJpiEZgnl0HbF8tD8eaIL0Qypz-ZBmniuwzWTjaQ0UGjrDLsA align="left")

## Entendendo o Catálogo do Backstage

O [catálogo](https://backstage.io/docs/features/software-catalog/software-catalog-overview) é o coração do Backstage. Não só muitas das funcionalidades são dependentes dele, mas boa parte da visualização inicial que você tem acesso vem a partir dele.

Então é importante a gente entender mais dele antes de começar a mexer na nossa aplicação.

O catálogo carrega o conceito de Entidades ([Entity](https://backstage.io/docs/features/software-catalog/life-of-an-entity)), onde elas são ingeridas de alguma fonte externa (Github, Okta, Bitbucket, LDAP) e passa por um ciclo de vida (Ingestão, processamento, validação, erros) até ficarem disponíveis para acesso via UI (ou API)  
O catálogo tem um [modelo padrão](https://backstage.io/docs/features/software-catalog/system-model) que é onde os plugins normalmente se baseiam:

![Imagem do padrão do catalog, contendo as entidades necessárias](https://lh5.googleusercontent.com/9VP1ag3uN7BR8i2mXXe3m1AXNMO_cgR4YkwEkVCePv1iNLs9kH7Rn_IzaBTIh3TM66PCPz4IOf6KcM-VpXXjPViznFFeMzg3IaTU3qgO3FMvX2NgEikSZdZj4EKATDzfbupr-9x7XsC3C45QZjJoZPbZ4fRV_zK1x_TIcNqZlQrc02v5KhMprTyVE8oFeg align="left")

Isso significa que essas entidades são parte do fluxo padrão. Além disso, entidades como **usuários e grupos** ficam disponíveis para vínculos de responsabilidade.

Ele trabalha com o formato YAML tanto para ingestão, quanto na resposta das APIs (que são devolvidas em JSON) e tem uma [série de regras](https://backstage.io/docs/features/software-catalog/descriptor-format) de acordo com cada entidade. Normalmente ele acaba sendo parecido com isso:

```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
 name: angeliski-stage
 description: An example of a Backstage application.
 annotations:
   github.com/project-slug: angeliski/angeliski-stage
spec:
 type: service
 owner: angeliski
 lifecycle: experimental
```

Esse arquivo é comumente chamado de ***catalog-info.yaml*** e normalmente aparece na raiz do repositório, mas esse padrão não é obrigatório.

Como nosso repositório está no [Github](https://github.com/backtostage/angeliski-stage/blob/main/catalog-info.yaml) nós vamos fazer a ingestão dos serviços através dele (o Github).

## Configurando a ingestão do catálogo via Github

Eu já disse antes que o catálogo é uma parte fundamental do Backstage, mas para ele funcionar bem você precisa colocar a informação ali. Na app criada já existem alguns arquivos de demonstração, mas no mundo real a gente quer consumir esses dados de algum outro lugar.

Para isso, nós podemos usar [duas opções](https://backstage.io/docs/features/software-catalog/external-integrations): Entity Providers ou Catalog Processors.

Neste momento não vou me aprofundar nas diferenças, só dizer que para a maioria dos casos você vai **preferir usar um Entity Provider**.

No nosso exemplo, nós vamos fazer uma integração com o GIthub, utilizando o [provider](https://backstage.io/docs/integrations/github/discovery) dele.

1. adicionar o [plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-github) responsável por esse processo:
    

```bash
yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-github
```

1. modificar o arquivo onde nós configuramos nosso catálogo:
    
    ```typescript
    // No packages/backend/src/plugins/catalog.ts
    
    //importar o provider
     import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
    
    // no corpo da função
        builder.addEntityProvider(
            GithubEntityProvider.fromConfig(env.config, {
              logger: env.logger,
              schedule: env.scheduler.createScheduledTaskRunner({
                frequency: { minutes: 30 },
                timeout: { minutes: 3 },
              }),
            }),
          );
    ```
    
2. Adicionar no arquivo app-config.yaml a [configuração](https://backstage.io/docs/integrations/github/discovery#configuration) necessária para achar os arquivos do catálogo:
    

```yaml
providers:
   github:
     providerId:
       organization: 'angeliski'
       catalogPath: '/catalog-info.yaml'
       filters:
         branch: 'main'
         repository: 'angeliski-stage'
```

1. Configurar a [autenticação](https://backstage.io/docs/integrations/github/locations#configuration) com o Github. Nessa etapa a gente só precisa gerar um [token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) do Github e configurar ele na variável de ambiente ***GITHUB\_TOKEN***. Em outro momento podemos fazer a configuração com uma [Github App](https://backstage.io/docs/integrations/github/github-apps)
    

Ao colocar o nosso projeto em execução, vamos encontrar um catálogo com o seguinte resultado (O repositório pode demorar alguns segundos para aparecer, então pode ser necessário atualizar a página):

![imagem do catalogo com o repositório aparecendo](https://lh5.googleusercontent.com/QNAeKT8PMsQUvWjq4D3b-rd6QPI1MvSeCBH6ojiZWsM6gdGOdmnrtiiKG0dunN0o9mrE-VwTlLaO_821g1TrPcZtFGnhCLGEpg4oy_zxARMqx0mFvJCEweGUJ8pmlW_Y3-d6Fl7Q7uu4BCLf2LmsPywDAiiD037kScAfyDqdBFNSNK67NvOiBx7hRsmfHA align="left")

No nosso exemplo eu apenas fiz a ingestão de um repositório, mas você pode configurar essa ingestão para ser feita através da sua organização inteira. Além disso, você consegue fazer a ingestão de [usuários e grupos](https://backstage.io/docs/integrations/github/org#installation) da sua organização, de modo a ter um catalogo com a informação correta, indicando os donos de cada serviço (para isso que serve aquele campo owner no arquivo)

Commit do Github com as alterações: [aqui](https://github.com/backtostage/angeliski-stage/commit/e7850b30213ca50b1590f5098e53371773e84b96)

## Criando o primeiro template

Agora nós vamos começar a adicionar um template na nossa aplicação. A ideia aqui é criar uma simples app [express](https://expressjs.com/pt-br/), muito mais para mostrar como o Software Template funciona do que definir como serão seus templates. Você inclusive pode ver alguns [exemplos no Github](https://github.com/backstage/software-templates).

Antes de começar vamos entender quais são os elementos que fazem parte do nosso template:

* **Inputs** - Esses são os parâmetros de entrada para criar seu template. Basicamente são as informações que você vai informar para o Backstage conseguir criar sua aplicação a partir do template. Nós vamos ver como declarar isso no nosso arquivo do template mais para frente.
    
* **Actions** - É aqui onde a mágica acontece, as **actions** são responsáveis por executar operações que vão gerar seu template final. Aqui temos desde download do template até publicação do seu repositório no Github.
    
* **Outputs** - Aqui nós estamos falando da saída para o usuário final, a nível de interface. Podemos por exemplo exibir um link para o repositório do Github.
    

Vamos dar uma olhada em como vai ficar o arquivo de template para o nosso exemplo:

```yaml
apiVersion: scaffolder.backstage.io/v1beta3
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
kind: Template
metadata:
  name: express-app
  title: Example Express Template
  description: An example template for the scaffolder that creates a simple express app
spec:
  owner: user:guest
  type: service

  # These parameters are used to generate the input form in the frontend, and are
  # used to gather input data for the execution of the template.
  parameters:
    - title: Fill in some steps
      required:
        - name
      properties:
        name:
          title: Name
          type: string
          description: Unique name of the app
          ui:autofocus: true
          ui:options:
            rows: 5
    - title: Choose a location
      required:
        - repoUrl
      properties:
        repoUrl:
          title: Repository Location
          type: string
          ui:field: RepoUrlPicker
          ui:options:
            allowedHosts:
              - github.com

  # These steps are executed in the scaffolder backend, using data that we gathered
  # via the parameters above.
  steps:
    # Each step executes an action, in this case one templates files into the working directory.
    - id: fetch-base
      name: Fetch Base
      action: fetch:template
      input:
        url: ./content
        values:
          name: ${{ parameters.name }}

    # This step publishes the contents of the working directory to GitHub.
    - id: publish
      name: Publish
      action: publish:github
      input:
        allowedHosts: ['github.com']
        description: My express ${{ parameters.name }}
        repoUrl: ${{ parameters.repoUrl }}

    # The final step is to register our new component in the catalog.
    - id: register
      name: Register
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
        catalogInfoPath: '/catalog-info.yaml'

  # Outputs are displayed to the user after a successful execution of the template.
  output:
    links:
      - title: Github Repository
        url: ${{ steps.publish.output.remoteUrl }}
      - title: Open in catalog
        icon: catalog
        entityRef: ${{ steps.register.output.entityRef }}
```

O template **também**  é uma Entity do seu catálogo, então ela segue a mesma ideia de owner e metadados. Além disso, você pode reparar que no começo desse template nós temos a definição dessa [API](https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template), que  permite você saber quais são os valores e informações aceitáveis no seu template.

O field `parameters`  é onde nós declaramos nossos inputs. Essa declaração é o que o Backstage vai utilizar para montar a interface, ela segue um uso forte do [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-formhttps://github.com/rjsf-team/react-jsonschema-form), o que torna nosso front-end muito versátil e dinâmico (inclusive permitindo que você crie componentes customizados, mas isso é papo para outra hora)

Aqui vale ressaltar que você está construindo um [Wizard](https://uxdesign.cc/the-wizard-of-user-experience-6926ca41bc9a), então ele pode ter várias etapas onde você vai organizar a informação para gerar uma melhor experiência para seu time de engenharia . Nosso exemplo tem duas paradas, uma onde solicitamos o nome da aplicação e outra onde vamos solicitar as informações do Github.

A próxima seção importante é a de `steps`, onde nós vamos criar nossa receita para gerar a aplicação. Cada item dessa seção vai ser uma **action** que vai ser responsável por realizar alguma operação para gerar nosso template final.  A usa instância do Backstage permite exibir uma listagem das actions disponíveis, com informações relevantes ( no futuro a gente pode construir uma action e explorar mais isso), essa listagem está disponível em

[`http://localhost:3000/create/actions`](http://localhost:3000/create/actions%60) ou pode ser acessível pela tela em **Installed Actions**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673903406877/fabf9292-dfd4-464c-8d12-b99fb0efa30e.png align="center")

No nosso exemplo nós temos três actions:

* **Fetch Base** - Essa action é responsável por obter o template, ele busca a base do template que nós vamos aplicar. Essa action em específico ainda realiza um render alterando as variáveis que nós temos no nosso template, utilizando a sintaxe do [Nunjucks](https://mozilla.github.io/nunjucks/templating.html) (a template engine utilizada pelo Backstage)
    
* **Publish** - Essa action vai publicar o seu código no Github, inclusive realizando a criação do repositório para isso
    
* **Register** - Essa action registra a aplicação recém criada no próprio Backstage (para isso precisa existir um arquivo de catálogo, repare que nosso template final já tem essa informação)
    

O último pedaço faz referência aos nossos links de saída, o que é muito útil para permitir um rápido acesso a informação recém criada. No nosso exemplo nós temos acesso ao  serviço no catálogo e ao repositório no Github.

![](https://lh4.googleusercontent.com/N6hAg9Dg8FqheQVgO48qbhi0zA82GdclY9h5MCVTyHEfHjLSvE67ADtJZRoyZFVm14Ff32kXOABTqgJp4ZiYjKLHEAvzZl20mCUVXb5-N14a7e4OepFdx025feeEu314hi6nALGlkixabIK5nnKNzkZWTe3qy6pR9rNeFEuQBs_eqAMUAWJGomvwZIK3fg align="left")

Você pode ver o resultado final dessa app [aqui](https://github.com/backtostage/my-express-app), bem como o template utilizado [aqui](https://github.com/backtostage/angeliski-stage/tree/main/examples/express-app).

Commit do Github com as alterações: [aqui](https://github.com/backtostage/angeliski-stage/commit/522f47364d73ad296f92552cbdc986a6147e0ed6)

## Autenticando com o Github

Uma das coisas legais do nosso catálogo é permitir que ao acessar o Backstage ele consiga te dizer quais são os serviços sob sua responsabilidade, considerando os seus times e as declarações de owner presentes no catálogo.

Mas para que ele consiga fazer isso, ele precisa saber **quem** é você. Para isso ele conta com o conceito de [Identity (Identidade)](https://backstage.io/docs/auth/), que basicamente significa você se identificar no Backstage, **normalmente** considerando alguma fonte externa (no nosso exemplo nós vamos usar o Github).

Aqui vale um disclaimer muito **importante** e que costuma **gerar confusão**:

***Esse mecanismo não foi criado com o intuito de bloquear acessos (não é um mecanismo de autorização), então é muito recomendado que você tenha algum mecanismo que permita você bloquear usuários externos de acessar sua aplicação principal.***

A documentação oficial tem diversos [providers](https://backstage.io/docs/auth/) que você pode utilizar, ou se não estiver disponível você ainda pode adicionar um [novo provider](https://backstage.io/docs/auth/add-auth-provider) seguindo as interfaces necessárias.

Vamos agora ver como podemos fazer para que nossa aplicação permita o usuário se identificar através do [Github](https://backstage.io/docs/auth/github/provider).

Para isso, você precisa criar um [GitHub App](https://docs.github.com/en/developers/apps/building-github-apps/creating-a-github-app) ou [OAuth App](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app) que vão ser responsáveis por controlar o fluxo do OAuth2. Vamos criar um Github App no nosso caso.

![](https://lh5.googleusercontent.com/aIXkNwOcXtohuJC1Q_VXUjhOwN-0DGyQlSBHF0WhVtgAtkWR3y1j6V_V-Wpq_wHQyedORg0Bxp-lzaxEhumbSC0OGizO_VlqATVr0q-5G3XcZ3uiLHNY3ATyexyH29Rlrlx0lbMidnPHubCG_y4lToFBETS43PtmOQUZZa7HfHpfHZHioSj47RbVwSJy4Q align="left")

Depois de criada você vai obter um *clientId* e um *clientSecret*, eles são necessários para realizar o fluxo de OAuth2.  Agora vamos colocar a nossa nova configuração no app-config.yaml

```yaml
auth:
  environment: development
  providers:
    github:
      development:
        clientId: ${AUTH_GITHUB_CLIENT_ID}
        clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
```

No nosso backend vamos precisar setar os valores da envs antes de subir o projeto. Agora vamos configurar nossa interface para dar a opção ao nosso usuário de realizar esse processo pelo Github.

No arquivo `packages/app/src/App.tsx` nós vamos realizar algumas modificações:

```typescript
+ import { githubAuthApiRef } from '@backstage/core-plugin-api';
+ import { SignInPage } from '@backstage/core-components';

 const app = createApp({
   apis,
+  components: {
+    SignInPage: props => (
+      <SignInPage
+        {...props}
+        auto
+        provider={{
+          id: 'github-auth-provider',
+          title: 'GitHub',
+          message: 'Sign in using GitHub',
+          apiRef: githubAuthApiRef,
+        }}
+      />
+    ),
+  },
   bindRoutes({ bind }) {
```

E temos o seguinte resultado:

![](https://lh4.googleusercontent.com/xR0lS4Y_LR42CTkIF8FUQz6FaaQFesZSwEvj_IUama8lWS0rcY8rcEayoQG7IAFCZwBd-y8xeX_nzR-cbI8fKX4Tc8A0ajaO-wO-6szhYiYT_hsZSOsLGUl9GOGyHR6koSyfE3lGoJ6WQNhoYskn2N11m8iyWYL3st89K5sA0KzFEDQO6IgfSQTI1DV7lQ align="left")

Isso é suficiente para habilitar o login através do Github. Note que eu removi a opção de acessar usando **guest** user (basicamente um usuário anônimo).

Outra coisa importante é a relação entre o catálogo e a autenticação. Em versões mais antigas o usuário que estava se autenticado não precisava ter uma correspondência no catálogo, mas isso mudou (por padrão). Você ainda pode realizar essa operação, mas vai precisar customizar um pouco, basta olhar a [documentação](https://backstage.io/docs/auth/identity-resolver#sign-in-without-users-in-the-catalog). Isso foi alterado pois é uma **expectativa** que o usuário que se identificou tenha uma representação no catálogo além de suas relações com os serviços.

Commit do Github com as alterações: [aqui](https://github.com/backtostage/angeliski-stage/commit/642ca3266c3e50396522b51bae1540c29daef9fb)

## Mas e para colocar em produção?

Com isso nós colocamos um conjunto de funcionalidades na nossa aplicação que vai nos permitir tirar valor do Backstage. Em outro texto podemos falar mais de estratégias de adoção e aprofundar em caminhos para mapear nosso catálogo e como usar outras fontes além do Github.

Mas e agora, como mandar para **produção**?

Existem diversas formas de fazer o [deploy](https://backstage.io/docs/deployment/) da sua aplicação, a mais comum é fazer isso através de containers, então vamos seguir essa abordagem.

A primeira coisa a se notar é que no nosso projeto já foi criado por padrão um Dockerfile que vai permitir a gente criar essa imagem e fazer o deploy dela.

Basicamente nós precisamos fazer o seguinte processo ante de criar a imagem:

```bash
yarn install --frozen-lockfile
yarn tsc
yarn build:backend
```

Com isso o projeto vai estar pronto para construção da imagem:

```bash
docker image build . -f packages/backend/Dockerfile --tag backstage
```

E para executar localmente:

```bash
docker run -it -p 7007:7007 backstage
```

Para nosso exemplo, eu vou adicionar um Github Action que faz esse processo de construção [aqui](https://github.com/backtostage/angeliski-stage/commit/77e2c05ce57ee0a55ccf696a535aa0d545e31e5d). Não vou emburacar no processo de deploy pois cada ecossistema/empresa tem uma maneira diferente de fazer deploy (quem sabe no futuro a gente vem falar só disso?).

Importante se atentar ao build da imagem que precisa usar o [buildkit](https://docs.docker.com/build/buildkit/#getting-started).

## **Finalizando**

O movimento inicial é normalmente o mais complicado. Muita coisa nova, muita coisa confusa e difícil de compreender como encaixa tudo junto. Esse artigo tem como objetivo dar um pontapé e muitas coisas dele estão descritas na [documentação oficial](https://backstage.io/docs/overview/what-is-backstage).

“Nossa Rogerio, então porque escrever ele?”

![](https://media.giphy.com/media/cPKWZB2aaB3rO/giphy.gif align="center")

Dois motivos: Nem todo mundo sabe inglês e para organizar uma ideia.

O inglês eu nem preciso explicar, sai da sua bolha.

A organização da ideia vai te ajudar para ir do ponto ZERO até uma imagem funcional do Backstage, o que já é um SUPER adianto para quem não tem nem ideia por onde começar. Eu explorei detalhes que me deram dor de cabeça quando eu comecei (e as vezes passam despercebidos) e deixei um commit de refêrencia que fica fácil de você comparar com o seu resultado.

Fica a vontade para me contar suas dúvidas e dificuldades, mais para frente eu trago outros artigos abordando alguns detalhes do que eu falei por aqui hoje.
