{"id":38916,"date":"2020-04-17T09:59:17","date_gmt":"2020-04-17T16:59:17","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/premier-developer\/?p=38916"},"modified":"2020-03-27T10:23:51","modified_gmt":"2020-03-27T17:23:51","slug":"como-fazer-arquivos-de-configuracao-editaveis","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/como-fazer-arquivos-de-configuracao-editaveis\/","title":{"rendered":"Como fazer: Arquivos de Configura\u00e7\u00e3o Edit\u00e1veis"},"content":{"rendered":"<p>The Portuguese translation for this article is provided by App Dev Manager <a href=\"https:\/\/www.linkedin.com\/in\/julio-madeira\/\">Julio Madeira<\/a>.\nEnglish version available <a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/angular-how-to-editable-config-files\/\">here<\/a>.<\/p>\n<hr \/>\n<p>O Angular-CLI \u00e9 a maneira recomendada de criar um aplicativo pronto para produ\u00e7\u00e3o, completo com agrupamento, atualiza\u00e7\u00e3o e testes. Um Aplicativo desenvolvido com o Angular-CLI vem com um mecanismo para criar vers\u00f5es especificas para cada ambiente, contudo, esses arquivos de configura\u00e7\u00f5es vem em formato TypeScript e n\u00e3o permitem que sejam editados pela equipe de TI ou por processos automatizados de Deployment, como por exemplo o VSTS.<\/p>\n<p>Esse Post vai explicar em alguns passos e exemplos como usar um arquivos JSON de configura\u00e7\u00e3o que pode ser customizado para m\u00faltiplos ambientes.<\/p>\n<p><strong>Defina a Interface TypeScript para configura\u00e7\u00e3o:<\/strong><\/p>\n<p>O uso de interfaces numa App Angular, prov\u00ea uma serie de funcionalidades (intellisense) e seguras (type-safety) para as entidades que voc\u00ea estiver usando. No exemplo abaixo, vamos usar um arquivo-exemplo como \u201cArquivo de Configura\u00e7\u00e3o\u201d:<\/p>\n<p><strong>app-config.model.ts<\/strong><\/p>\n<pre class=\"lang:default decode:true \">export interface IAppConfig {\r\n    env: {\r\n        name: string;\r\n    };\r\n    appInsights: {\r\n        instrumentationKey: string;\r\n    };\r\n    logging: {\r\n        console: boolean;\r\n        appInsights: boolean;\r\n    };\r\n    aad: {\r\n        requireAuth: boolean;\r\n        tenant: string;\r\n        clientId: string;\r\n\r\n    };\r\n    apiServer: {\r\n        metadata: string;\r\n        rules: string;\r\n    };\r\n}\r\n<\/pre>\n<p><strong>Crie um arquivo de configura\u00e7\u00e3o JSON fils<\/strong><\/p>\n<p>A convenient place to store configuration files is under the assets folder of your project. Using the interface defined above, sample files could look as follows:<\/p>\n<p>Um local conveniente para armazenar arquivos de configura\u00e7\u00e3o est\u00e1 na pasta \u201cAssets\u201d do seu projeto. Usando a interface definida acima, os arquivos de exemplos podem ter a seguinte apar\u00eancia:<\/p>\n<p><strong>assets\\config\\config.dev.json<\/strong><\/p>\n<pre class=\"lang:default decode:true \">{\r\n    \"env\": {\r\n    \"name\": \"DEV\"\r\n     },\r\n    \"appInsights\": {\r\n    \"instrumentationKey\": \"&lt;dev-guid-here&gt;\"\r\n     },\r\n    \"logging\": {\r\n    \"console\": true,\r\n    \"appInsights\": false\r\n    },\r\n    \"aad\": {\r\n    \"requireAuth\": true,\r\n    \"tenant\": \"&lt;dev-guid-here&gt;\",\r\n    \"clientId\": \"&lt;dev-guid-here&gt;\"\r\n    },\r\n    \"apiServer\": {\r\n    \"metadata\": \"https:\/\/metadata.demo.com\/api\/v1.0\/\",\r\n    \"rules\": \"https:\/\/rules.demo.com\/api\/v1.0\/\"\r\n    }\r\n}\r\n<\/pre>\n<p><strong>assets\\config\\config.deploy.json\u00a0<\/strong><em>(Observe os espa\u00e7os reservados que s\u00e3o substitu\u00eddos durante a implanta\u00e7\u00e3o)<\/em><\/p>\n<pre class=\"lang:default decode:true\">{\r\n    \"env\": {\r\n    \"name\": \"#{envName}\"\r\n    },\r\n    \"appInsights\": {\r\n    \"instrumentationKey\": \"#{appInsightsKey}\"\r\n    },\r\n    \"logging\": {\r\n    \"console\": true,\r\n    \"appInsights\": true\r\n    },\r\n    \"aad\": {\r\n    \"requireAuth\": true,\r\n    \"tenant\": \"#{aadTenant}\",\r\n    \"clientId\": \"#{aadClientId}\"\r\n    },\r\n    \"apiServer\": {\r\n    \"metadata\": \"https:\/\/#{apiServerPrefix}.demo.com\/api\/v1.0\/\",\r\n    \"rule\": \"https:\/\/#{apiServerPrefix}.demo.com\/api\/v1.0\/\",\r\n    }\r\n}\r\n<\/pre>\n<p><strong>Continue a usar o \u201cenvironment.ts\u201c com o build do Angular-CLI <\/strong><\/p>\n<p>A Angular-CLI cria v\u00e1rios arquivos de ambiente TypeScript na pasta de ambientes. Eles ainda ser\u00e3o usados, mas cont\u00eam apenas o nome do ambiente.<\/p>\n<p><strong>environments\\environment.dev.json<\/strong><\/p>\n<pre class=\"lang:default decode:true \">export const environment = {\r\n    name: 'dev'\r\n};\r\n<\/pre>\n<p><strong>environments\\environment.deploy.json<\/strong><\/p>\n<pre class=\"lang:default decode:true \">export const environment = {\r\n    name: 'deploy'\r\n};\r\n<\/pre>\n<p><strong>angular.json<\/strong><\/p>\n<pre class=\"lang:default decode:true \">\"projects\": {\r\n  \"my-app\": {\r\n    \"architect\": {\r\n      \"build\": {\r\n        \"configurations\": {\r\n          \"deploy\": {\r\n            \"fileReplacements\": [\r\n              {\r\n                \"replace\": \"src\/environments\/environment.ts\",\r\n                \"with\": \"src\/environments\/environment.deploy.ts\"\r\n              }\r\n            ],\r\n            . . .\r\n          }\r\n        }\r\n      },\r\n      \"serve\": {\r\n        . . .\r\n        \"configurations\": {\r\n          \"deploy\": {\r\n            \"browserTarget\": \"my-app:build:deploy\"\r\n          }\r\n<\/pre>\n<p><strong>Crie um servi\u00e7o para ler o arquivo de Config<\/strong><\/p>\n<p>Este servi\u00e7o ler\u00e1 o arquivo de configura\u00e7\u00e3o correto e armazenar\u00e1 o resultado em um campo est\u00e1tico nesta classe.<\/p>\n<p><strong>app.config.ts\u00a0<\/strong><em>(Observe o uso da interface definida acima e a conven\u00e7\u00e3o de nomenclatura do arquivo de configura\u00e7\u00e3o para recuperar o arquivo correto.)<\/em><\/p>\n<pre class=\"lang:default decode:true \">import { Injectable } from '@angular\/core\u2019;\r\nimport { HttpClient } from '@angular\/common\/http';\r\nimport { environment } from '..\/environments\/environment';\r\nimport { IAppConfig } from '.\/models\/app-config.model';\r\n@Injectable()\r\nexport class AppConfig {\r\n    static settings: IAppConfig;\r\n    constructor(private http: HttpClient) {}\r\n    load() {\r\n        const jsonFile = `assets\/config\/config.${environment.name}.json`;\r\n        return new Promise&lt;void&gt;((resolve, reject) =&gt; {\r\n            this.http.get(jsonFile).toPromise().then((response : IAppConfig) =&gt; {\r\n               AppConfig.settings = &lt;IAppConfig&gt;response;\r\n               resolve();\r\n            }).catch((response: any) =&gt; {\r\n               reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);\r\n            });\r\n        });\r\n    }\r\n}\r\n<\/pre>\n<p><strong>Carregue o arquivo de Config antes de criar a Aplica\u00e7\u00e3o<\/strong><\/p>\n<p>Angular inclui um token chamado APP_INITIALIZER que permite ao nosso aplicativo executar c\u00f3digo quando o aplicativo \u00e9 inicializado. No m\u00f3dulo do aplicativo, use esse token para chamar o m\u00e9todo load em nosso servi\u00e7o de configura\u00e7\u00e3o. Como nosso m\u00e9todo retorna uma promessa\/promissoe, o Angular atrasar\u00e1 a inicializa\u00e7\u00e3o at\u00e9 que a promessa\/promisse seja resolvida.<\/p>\n<p><strong>app.module.ts<\/strong><\/p>\n<pre class=\"lang:default decode:true \">import { APP_INITIALIZER } from '@angular\/core';\r\nimport { AppConfig } from '.\/app.config';\r\n \r\nexport function initializeApp(appConfig: AppConfig) {\r\n  return () =&gt; appConfig.load();\r\n}\r\n@NgModule({\r\n    imports: [ , , , ],\r\n    declarations: [ . . . ],\r\n    providers: [\r\n       AppConfig,\r\n       { provide: APP_INITIALIZER,\r\n         useFactory: initializeApp,\r\n         deps: [AppConfig], multi: true }\r\n    ],\r\n    bootstrap: [\r\n      AppComponent\r\n    ]\r\n})\r\nexport class AppModule { }\r\n<\/pre>\n<p><strong>Consuma as configura\u00e7\u00f5es da App atrav\u00e9s de toda a aplica\u00e7\u00e3o<\/strong><\/p>\n<p>As configura\u00e7\u00f5es agora est\u00e3o dispon\u00edveis em qualquer lugar do aplicativo e incluem a verifica\u00e7\u00e3o de tipo fornecida pela interface.<\/p>\n<pre class=\"lang:default decode:true \">export class DataService {\r\n    protected apiServer = AppConfig.settings.apiServer;\r\n    . . .\r\n    if (AppConfig.settings.aad.requireAuth) { . . . }\r\n}\r\nexport class LoggingService {\r\n    . . .\r\n    instrumentationKey: AppConfig.settings &amp;&amp; AppConfig.settings.appInsights ?\r\n                        AppConfig.settings.appInsights.instrumentationKey : ''\r\n    . . .\r\n    if (AppConfig.settings &amp;&amp; AppConfig.settings.logging) { . . . }\r\n}\r\n<\/pre>\n<p>Nota: para criar uma vers\u00e3o de produ\u00e7\u00e3o do aplicativo usando um nome de ambiente diferente de prod, use este comando:<\/p>\n<pre class=\"lang:default decode:true \">ng build \u2013configuration=deploy<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Esse Post vai explicar em alguns passos e exemplos como usar um arquivos JSON de configura\u00e7\u00e3o que pode ser customizado para m\u00faltiplos ambientes.<\/p>\n","protected":false},"author":582,"featured_media":38586,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[122],"tags":[51,1036,3],"class_list":["post-38916","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular","tag-angular","tag-region_latam","tag-team"],"acf":[],"blog_post_summary":"<p>Esse Post vai explicar em alguns passos e exemplos como usar um arquivos JSON de configura\u00e7\u00e3o que pode ser customizado para m\u00faltiplos ambientes.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/38916","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=38916"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/38916\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/38586"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=38916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=38916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=38916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}