http-verbs เป็นไลบรารี Scala ที่ให้อินเทอร์เฟซเพื่อโทรแบบอะซิงโครนัส HTTP
มันห่อหุ้มข้อกังวลทั่วไปบางประการสำหรับการโทรหาบริการ HTTP อื่น ๆ บนแพลตฟอร์มภาษี HMRC รวมถึง:
ดูการเปลี่ยนแปลงสำหรับการเปลี่ยนแปลงและการอพยพ
ในการสร้าง SBT ของคุณเพิ่ม:
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 " โดยที่ play-xx เป็นรุ่น Play ของคุณ (เช่น play-30 )
มี httpClients สองตัว แต่ HttpClient และ API ที่เกี่ยวข้องได้ถูกเลิกใช้แล้ว โปรดใช้ uk.gov.hmrc.http.client.HttpClientV2 แทน
ไคลเอนต์นี้มีคุณสมบัติมากกว่า HttpClient ดั้งเดิมและใช้งานง่ายกว่า
มันต้องใช้ HeaderCarrier เพื่อเป็นตัวแทนบริบทของผู้โทรและ HttpReads เพื่อดำเนินการตอบกลับ HTTP
มันยัง:
play.api.libs.ws.WSRequest ด้วย transform ทำให้ง่ายต่อการปรับแต่งคำขอjava.net.URL ; คุณสามารถใช้ประโยชน์จากการสอดแทรก URL ที่ให้ไว้ตัวอย่างสามารถพบได้ที่นี่และที่นี่
ลูกค้ารายนี้เลิกใช้แล้ว คุณสามารถโยกย้ายได้ดังนี้:
httpClient. GET [ ResponseType ](url)กลายเป็น
httpClientV2.get( url " $url " ).execute[ ResponseType ]และ
httpClient. POST [ ResponseType ](url, payload, headers)กลายเป็น
httpClientV2.post( url " $url " ).withBody( Json .toJson(payload)).setHeader(headers).execute[ ResponseType ]หากก่อนหน้านี้คุณกำลังสร้าง httpClients หลายตัวเพื่อกำหนดค่าพร็อกซีหรือเปลี่ยนตัวแทนผู้ใช้สิ่งนี้จะไม่จำเป็นต้องใช้เวลานานขึ้นเนื่องจากสิ่งเหล่านี้สามารถควบคุมได้ด้วย HTTPClientv2 API ต่อการโทร
HeaderCarrier ควรได้รับการปฏิบัติเป็นตัวแทนที่ไม่เปลี่ยนรูปของผู้โทร หากคุณต้องการจัดการส่วนหัวที่ถูกส่งในคำขอคุณสามารถทำได้ด้วย HttpClientV2 API
ตัวอย่างเช่นการแทนที่ตัวแทนผู้ใช้เริ่มต้นหรือส่วนหัวการอนุญาตที่กำหนดไว้ใน HeaderCarrier คุณสามารถใช้ setHeader ซึ่งจะแทนที่คนที่มีอยู่
httpClientV2.get( url " $url " )
.setHeader( " User-Agent " - > userAgent)
.setHeader( " Authorization " - > authorization)
.execute[ ResponseType ] หากคุณต้องการผนวกส่วนหัวเริ่มต้นคุณสามารถเข้าถึง addHttpHeaders บน WSClient ที่มี transform เช่น
httpClientV2.get( url " $url " )
.transform(_.addHttpHeaders( " User-Agent " - > userAgent))
.execute[ ResponseType ] โปรดทราบว่า "Content-Type" ไม่สามารถเปลี่ยนแปลงได้เมื่อตั้งค่าด้วย WSRequest ดังนั้นหากคุณต้องการสิ่งที่แตกต่างจากที่กำหนดโดย BodyWriter โดยนัยคุณจะต้องตั้งค่าก่อนให้ร่างกาย เช่น
httpClientV2.post( url " $url " )
.setHeader( " Content-Type " - > " application/xml " )
.withBody(< foo >bar</ foo >) ด้วย HttpClient เพื่อใช้พร็อกซีที่จำเป็นในการสร้างอินสแตนซ์ใหม่ของ httpClient เพื่อผสมใน WSProxy และกำหนดค่า ด้วย HttpClientV2 สิ่งนี้สามารถทำได้ด้วยไคลเอนต์เดียวกันโทร withProxy ต่อการโทร เช่น
httpClientV2.get( url " $url " ).withProxy.execute[ ResponseType ]WSProxyConfiguration.buildWsProxyServer ซึ่งเปิดใช้งานด้วย http-verbs.proxy.enabled ในการกำหนดค่า มันถูกปิดใช้งานโดยค่าเริ่มต้นซึ่งเหมาะสมสำหรับการพัฒนาและการทดสอบในท้องถิ่น แต่จะต้องเปิดใช้งานเมื่อปรับใช้ (หากไม่ได้เปิดใช้งานโดยการกำหนดค่าสภาพแวดล้อม) การสตรีมได้รับการสนับสนุนด้วย HttpClientV2 และจะได้รับการตรวจสอบในลักษณะเดียวกับการโทรแบบไม่สตรีม โปรดทราบว่าเพย์โหลดจะถูกตัดทอนในบันทึกการตรวจสอบหากพวกเขาเกินกว่าที่รองรับสูงสุด (ตามที่กำหนดค่าโดย http-verbs.auditing.maxBodyLength )
คำขอสตรีมสามารถส่งผ่านไปยัง withBody :
val reqStream : Source [ ByteString , _] = ???
httpClientV2.post( url " $url " ).withBody(reqStream).execute[ ResponseType ] สำหรับการตอบกลับแบบสตรีมให้ใช้ stream แทนที่จะ execute :
httpClientV2.get( url " $url " ).stream[ Source [ ByteString , _]] httpClientv2 ตัดทอน payloads สำหรับบันทึกการตรวจสอบหากพวกเขาเกินกว่าที่รองรับสูงสุด (ตามที่กำหนดโดย http-verbs.auditing.maxBodyLength )
ซึ่งหมายความว่าการตรวจสอบที่ถูกปฏิเสธว่ามีขนาดใหญ่เกินไปกับ HTTPClient อาจได้รับการยอมรับด้วย HTTPClientv2
มีการจัดเตรียม URL เพื่อช่วยในการหลบหนีและพารามิเตอร์เส้นทางอย่างถูกต้อง
import uk . gov . hmrc . http . StringContextOps
url " http://localhost:8080/users/ ${user.id} ?email= ${user.email} " HeaderCarrier ควรถูกสร้างขึ้นด้วย HeaderCarrierConverter เมื่อมีการร้องขอสิ่งนี้จะช่วยให้มั่นใจได้ว่าส่วนหัวที่เหมาะสมจะถูกส่งต่อไปยังโฮสต์ภายใน
เช่นสำหรับแบ็กเอนด์:
HeaderCarrierConverter .fromRequest(request)และสำหรับส่วนหน้า:
HeaderCarrierConverter .fromRequestAndSession(request, request.session) หากปลายทางส่วนหน้ากำลังให้บริการการโทร API มันควรจะใช้ fromRequest เนื่องจาก fromRequestAndSession จะมองหาโทเค็นการอนุญาตในเซสชั่นและไม่สนใจส่วนหัวของคำขอ
สำหรับการโทรแบบอะซิงโครนัสหากไม่มีคำขอพร้อมใช้งาน HeaderCarrier ใหม่สามารถสร้างได้ด้วยพารามิเตอร์เริ่มต้น:
HeaderCarrier ()ส่วนหัวจะถูกส่งต่อไปยังโฮสต์แตกต่างกันไปขึ้นอยู่กับว่าพวกเขาอยู่ ภายใน หรือ ภายนอก ความแตกต่างนี้ทำโดยการกำหนดค่า InternalServiceHostPatterns
สำหรับโฮสต์ภายนอกจะมีการส่งเฉพาะส่วนหัวของตัวแทนผู้ใช้เท่านั้น ควรให้ส่วนหัวอื่น ๆ อย่างชัดเจนกับฟังก์ชั่นคำกริยา ( get post ฯลฯ )
httpClientV2
.get( url " https://externalhost/api " )(hc)
.setHeader( " Authorization " - > " Bearer token " ) // explicit Authorization header for external request นอกเหนือจากตัวแทนผู้ใช้แล้วส่วนหัวทั้งหมดที่ได้รับการจำลอง อย่างชัดเจน ใน HeaderCarrier จะถูกส่งต่อไปยังโฮสต์ภายใน นอกจากนี้ยังจะส่งต่อส่วนหัวอื่น ๆ ใน HeaderCarrier หากระบุไว้ในการกำหนดค่า bootstrap.http.headersAllowlist
คุณสามารถแทนที่ส่วนหัวใด ๆ ที่ส่งต่อโดยปริยายเหล่านี้หรือเพิ่มคนอื่น ๆ โดยการจัดหาให้กับฟังก์ชัน setHeader
หมายเหตุสำหรับ HttpClient ดั้งเดิมส่วนหัวที่มีให้กับฟังก์ชั่นคำกริยาจะถูกส่ง นอกเหนือ จากที่อยู่ใน HeaderCarrier ดังนั้นหากคุณต้องการแทนที่หนึ่งคุณจะต้องจัดการกับ HeaderCarrier เช่น:
client. GET ( " https://internalhost/api " )(hc.copy(authorization = Some ( Authorization ( " Basic 1234 " ))))การตอบสนองถูก deserialised โดยอินสแตนซ์ของ httpreads
คุณสามารถสร้างอินสแตนซ์ของคุณเองหรือใช้อินสแตนซ์ที่ให้ไว้ด้วย
import uk . gov . hmrc . http . HttpReads . Implicits . _ความหมายเริ่มต้น (โดยไม่มีการนำเข้าอย่างชัดเจน) ได้รับการเลิกจ้าง ดูรายละเอียดเพิ่มเติมที่นี่
HttpReads อธิบายวิธีการแปลง HttpResponse เป็นโมเดลของคุณโดยใช้รหัสสถานะและร่างกายการตอบสนอง
อินสแตนซ์ที่ให้เข้ามาในขอบเขตที่มีการนำเข้าข้างต้นอนุญาตให้คุณ:
client. GET [ HttpResponse ](url) implicit val reads : Reads [ MyModel ] = ???
client.get[ MyModel ](url)UpstreamErrorResponse สำหรับรหัสสถานะที่ไม่ประสบความสำเร็จ ความล้มเหลวในการแยกวิเคราะห์ JSON จะถูกส่งคืนในทำนองเดียวกันเนื่องจาก JsValidationException ข้อยกเว้นเหล่านี้สามารถกู้คืนได้หากจำเป็นNone implict val reads : Reads [ MyModel ] = ???
client.get[ Option [ MyModel ]](url)UpstreamErrorResponse ใน Either implict val reads : Reads [ MyModel ] = ???
client.get[ Either [ UpstreamErrorResponse , MyModel ]](url)ในการสร้าง SBT ของคุณเพิ่มสิ่งต่อไปนี้ในการทดสอบของคุณ:
libraryDependencies + = " uk.gov.hmrc " %% " http-verbs-test-play-xx " % " x.x.x " % Testเราขอแนะนำให้ใช้ Wiremock สำหรับการทดสอบรหัส HTTP-Verbs พร้อมการยืนยันอย่างกว้างขวางเกี่ยวกับ URL ส่วนหัวและฟิลด์ร่างกายสำหรับทั้งคำขอและการตอบกลับ สิ่งนี้จะทดสอบสิ่งต่าง ๆ ส่วนใหญ่ไม่เกี่ยวข้องกับ "การเยาะเย้ยสิ่งที่คุณไม่ได้เป็นเจ้าของ" และทำให้มั่นใจได้ว่าการเปลี่ยนแปลงของห้องสมุดนี้จะถูกจับได้ นั่นคือผลลัพธ์ของการใช้ไลบรารีนี้คือสิ่งที่ตั้งใจไว้ไม่ใช่แค่ถ้าไลบรารีถูกเรียกใช้ตามที่คาดไว้
ลักษณะ WireMockSupport ช่วยตั้งค่า Wiremock สำหรับการทดสอบของคุณ มันมี wireMockHost , wireMockPort และ wireMockUrl ซึ่งสามารถใช้ในการกำหนดค่าไคลเอนต์ของคุณอย่างเหมาะสม
เช่นกับแอปพลิเคชัน:
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 ]
} ลักษณะ HttpClientV2Support สามารถให้อินสแตนซ์ของ HttpClientV2 เป็นทางเลือกในการติดตั้งแอปพลิเคชัน:
class MyConnectorSpec extends WireMockSupport with HttpClientV2Support {
private val connector = new MyConnector (
httpClientV2,
Configuration ( " connector.url " - > wireMockUrl)
)
} ลักษณะ ExternalWireMockSupport เป็นอีกทางเลือกหนึ่งสำหรับ WireMockSupport ซึ่งใช้ 127.0.0.1 แทนที่จะเป็น localhost สำหรับชื่อโฮสต์ซึ่งถือเป็นโฮสต์ภายนอกสำหรับกฎการส่งต่อส่วนหัว สิ่งนี้ควรใช้สำหรับการทดสอบของตัวเชื่อมต่อที่เรียกจุดสิ้นสุดภายนอกไปยังแพลตฟอร์ม ควรใช้ตัวแปร externalWireMockHost (หรือ externalWireMockUrl ) เพื่อให้ชื่อโฮสต์ในการกำหนดค่า
ทั้ง WireMockSupport และ ExternalWireMockSupport สามารถใช้ร่วมกันสำหรับการทดสอบการรวมหากจำเป็น
คุณลักษณะ ResponseMatchers ให้ผู้ช่วยเหลือที่มีประโยชน์สำหรับการทดสอบการตอบสนอง
รหัสนี้เป็นซอฟต์แวร์โอเพ่นซอร์สที่ได้รับอนุญาตภายใต้ใบอนุญาต Apache 2.0