HTTP-Verbs est une bibliothèque Scala fournissant une interface pour effectuer des appels HTTP asynchrones.
Il résume certaines préoccupations communes pour appeler d'autres services HTTP sur la plate-forme fiscale HMRC, notamment:
Voir Changelog pour les changements et les migrations.
Dans votre build SBT Ajouter:
resolvers + = MavenRepository ( " HMRC-open-artefacts-maven2 " , " https://open.artefacts.tax.service.gov.uk/maven2 " )
libraryDependencies + = " uk.gov.hmrc " %% " http-verbs-play-xx " % " x.x.x " Où play-xx est votre version de Play (par exemple play-30 ).
Il y a deux HTTPClients disponibles, mais l'API HttpClient et associée ont été obsolètes. Veuillez utiliser uk.gov.hmrc.http.client.HttpClientV2 à la place.
Ce client a plus de fonctionnalités que le HttpClient d'origine et est plus simple à utiliser.
Il nécessite un HeaderCarrier pour représenter le contexte de l'appelant et un HttpReads pour traiter la réponse HTTP.
C'est aussi:
play.api.libs.ws.WSRequest sous-jacent transformjava.net.URL ; Vous pouvez utiliser l'interpolateur URL fourni.Des exemples peuvent être trouvés ici et ici
Ce client a été obsolète. Vous pouvez migrer comme suit:
httpClient. GET [ ResponseType ](url)devient
httpClientV2.get( url " $url " ).execute[ ResponseType ]et
httpClient. POST [ ResponseType ](url, payload, headers)devient
httpClientV2.post( url " $url " ).withBody( Json .toJson(payload)).setHeader(headers).execute[ ResponseType ]Si vous créiez auparavant plusieurs HTTPClients pour configurer des proxys ou modifier l'agent utilisateur, cela ne sera plus que nécessaire car ceux-ci peuvent tous être contrôlés avec l'API HTTPClientv2 par appel.
Le HeaderCarrier doit être largement traité comme une représentation immuable de l'appelant. Si vous avez besoin de manipuler les en-têtes envoyés dans les demandes, vous pouvez le faire avec l'API HttpClientV2 .
Par exemple, pour remplacer l'agent utilisateur par défaut ou l'en-tête d'autorisation défini dans le HerecCarrier, vous pouvez utiliser setHeader qui remplacera tous les existants.
httpClientV2.get( url " $url " )
.setHeader( " User-Agent " - > userAgent)
.setHeader( " Authorization " - > authorization)
.execute[ ResponseType ] Si vous souhaitez ajouter des en-têtes par défaut, vous pouvez accéder addHttpHeaders sur le WSClient sous-jacent avec transform . par exemple
httpClientV2.get( url " $url " )
.transform(_.addHttpHeaders( " User-Agent " - > userAgent))
.execute[ ResponseType ] Sachez que "Content-Type" ne peut pas être modifié une fois défini avec WSRequest , donc si vous en voulez un différent à celui défini par le BodyWriter implicite, vous devrez le définir avant de fournir le corps. par exemple
httpClientV2.post( url " $url " )
.setHeader( " Content-Type " - > " application/xml " )
.withBody(< foo >bar</ foo >) Avec HttpClient , pour utiliser un proxy requis, créant une nouvelle instance de httpclient pour mélanger dans WSProxy et configurer. Avec HttpClientV2 cela peut être fait avec le même client, appelant withProxy par appel. par exemple
httpClientV2.get( url " $url " ).withProxy.execute[ ResponseType ]WSProxyConfiguration.buildWsProxyServer qui est activé avec http-verbs.proxy.enabled en configuration. Il est désactivé par défaut, ce qui convient au développement local et aux tests, mais devra être activé lors du déploiement (s'il n'est pas déjà activé par la configuration environnementale). Le streaming est pris en charge avec HttpClientV2 et sera audité de la même manière que les appels non diffusés. Notez que les charges utiles seront tronquées dans les journaux d'audit s'ils dépassent le maximum pris en charge (comme configuré par http-verbs.auditing.maxBodyLength ).
Les demandes en difficulté peuvent simplement être transmises à withBody :
val reqStream : Source [ ByteString , _] = ???
httpClientV2.post( url " $url " ).withBody(reqStream).execute[ ResponseType ] Pour les réponses en difficulté, utilisez stream plutôt que execute :
httpClientV2.get( url " $url " ).stream[ Source [ ByteString , _]] HttpClientv2 tronque les charges utiles pour les journaux d'audit s'ils dépassent le maximum pris en charge (comme configuré par http-verbs.auditing.maxBodyLength ).
Cela signifie que les audits qui ont été rejetés pour être trop volumineux avec httpclient seront probablement acceptés avec httpclientv2.
Un interpolateur URL a été fourni pour aider à échapper correctement à la requête et au chemin des paramètres.
import uk . gov . hmrc . http . StringContextOps
url " http://localhost:8080/users/ ${user.id} ?email= ${user.email} " Le HeaderCarrier doit être créé avec HeaderCarrierConverter lorsqu'une demande est disponible, cela garantira que les en-têtes appropriés sont transmis aux hôtes internes.
Par exemple pour les backends:
HeaderCarrierConverter .fromRequest(request)Et pour les fronts:
HeaderCarrierConverter .fromRequestAndSession(request, request.session) Si un point de terminaison Frontend sert un appel API, il devrait probablement utiliser fromRequest car fromRequestAndSession ne recherchera qu'un jeton d'autorisation dans la session et ignorez tout en-tête de demande.
Pour les appels asynchrones, où aucune demande n'est disponible, un nouveau HeaderCarrier peut être créé avec des paramètres par défaut:
HeaderCarrier ()Les en-têtes sont transmis différemment aux hôtes selon qu'ils sont internes ou externes . Cette distinction est faite par la configuration InternalServiceHostPatterns.
Pour les hôtes externes, seul l'en-tête utilisateur-agent est envoyé. Tout autre en-têtes doit être fourni explicitement à la fonction verbale ( get , post etc.).
httpClientV2
.get( url " https://externalhost/api " )(hc)
.setHeader( " Authorization " - > " Bearer token " ) // explicit Authorization header for external request En plus de l'agent utilisateur, tous les en-têtes modélisés explicitement dans le HeaderCarrier sont transmis à des hôtes internes. Il transmettra également tout autre en-têtes dans le HeaderCarrier s'il est répertorié dans la configuration bootstrap.http.headersAllowlist .
Vous pouvez remplacer l'un de ces en-têtes transmis implicitement ou en ajouter d'autres en les fournissant à la fonction setHeader .
Remarque, pour le HttpClient d'origine, les en-têtes fournis à la fonction verbale sont envoyés en plus de ceux du HeaderCarrier, donc si vous souhaitez en remplacer un, vous devrez manipuler le HeaderCarrier par exemple:
client. GET ( " https://internalhost/api " )(hc.copy(authorization = Some ( Authorization ( " Basic 1234 " ))))La réponse est désérialisée par une instance de httpreads.
Vous pouvez soit créer vos propres instances, soit utiliser les instances fournies
import uk . gov . hmrc . http . HttpReads . Implicits . _Les implicits par défaut (sans importation explicite) ont été obsolètes. Voir ici pour plus de détails.
Le HttpReads décrit comment convertir une HttpResponse en votre modèle en utilisant le code d'état et le corps de réponse.
Les instances fournies, apportées à l'importation ci-dessus, vous permettent de:
client. GET [ HttpResponse ](url) implicit val reads : Reads [ MyModel ] = ???
client.get[ MyModel ](url)UpstreamErrorResponse pour les codes de statut de non-succès. Les échecs d'analyse JSON seront également retournés à mesure que JsValidationException , ces exceptions peuvent être récupérées si nécessaire.None implict val reads : Reads [ MyModel ] = ???
client.get[ Option [ MyModel ]](url)UpstreamErrorResponse dans Either implict val reads : Reads [ MyModel ] = ???
client.get[ Either [ UpstreamErrorResponse , MyModel ]](url)Dans votre SBT Build, ajoutez ce qui suit dans vos dépendances de test:
libraryDependencies + = " uk.gov.hmrc " %% " http-verbs-test-play-xx " % " x.x.x " % TestNous recommandons que WireMock soit utilisé pour tester le code HTTP-Verbes, avec des affirmations approfondies sur l'URL, les en-têtes et les champs corporels pour les demandes et les réponses. Cela testera la plupart des choses, n'implique pas de "se moquer de ce que vous ne possédez pas" et garantit que des modifications à cette bibliothèque seront capturées. C'est-à-dire que le résultat de l'utilisation de cette bibliothèque est ce qui était prévu, pas seulement si la bibliothèque a été invoquée comme prévu.
Le trait WireMockSupport aide à configurer WireMock pour vos tests. Il fournit wireMockHost , wireMockPort et wireMockUrl qui peuvent être utilisés pour configurer votre client de manière appropriée.
par exemple avec une application:
class MyConnectorSpec extends WireMockSupport with GuiceOneAppPerSuite {
override def fakeApplication () : Application =
new GuiceApplicationBuilder ()
.configure(
" connector.host " - > wireMockHost,
" connector.port " - > wireMockPort
).build()
private val connector = app.injector.instanceOf[ MyConnector ]
} Le trait HttpClientV2Support peut fournir une instance de HttpClientV2 comme alternative à l'instanciation de l'application:
class MyConnectorSpec extends WireMockSupport with HttpClientV2Support {
private val connector = new MyConnector (
httpClientV2,
Configuration ( " connector.url " - > wireMockUrl)
)
} Le trait ExternalWireMockSupport est une alternative à WireMockSupport qui utilise 127.0.0.1 au lieu de localhost pour le nom d'hôte qui est traité comme un hôte externe pour les règles de transfert d'en-tête. Ceci doit être utilisé pour les tests de connecteurs qui appellent les points de terminaison externes à la plate-forme. La variable externalWireMockHost (ou externalWireMockUrl ) doit être utilisée pour fournir le nom d'hôte en configuration.
WireMockSupport et ExternalWireMockSupport peuvent être utilisés ensemble pour les tests d'intégration si nécessaire.
Le trait ResponseMatchers fournit des aides utiles pour tester les réponses.
Ce code est un logiciel open source sous licence Apache 2.0.