2017-07-04 25 views
9

Ứng dụng của tôi hỗ trợ nối tiếp protobuf và JSON. Đối với serialization JSON tôi sử dụng com.trueaccord.scalapb.json.JsonFormat, dtos của tôi được tạo từ các định nghĩa proto.Tôi làm cách nào để sử dụng tiêu đề yêu cầu http để đàm phán nội dung trong Mashaller?

Các loại tùy chọn kết thúc com.trueaccord nối tiếp các đối tượng JSON gây ra sự cố cho một số khách hàng vì vậy tôi muốn có thể hỗ trợ org.json4s mà không cần phanh máy khách hiện tại.

Tôi muốn có thể chọn trình nối tiếp dựa trên tiêu đề http tùy chỉnh được gọi là JFORMAT. Ý tưởng là nếu tiêu đề này được gửi, tôi sẽ sử dụng json4s nếu không tôi sẽ sử dụng serializer trueaccord.

tôi cố gắng tạo ra một Unmarshaller có thể chọn một serializer yêu cầu dựa trên một giá trị tiêu đề:

Unmarshaller.withMaterializer[HttpRequest, T](_ => implicit mat => { 
    case request: HttpRequest => 
    val entity = request.entity 
    entity.dataBytes.runFold(ByteString.empty)(_ ++ _).map(data => { 
     entity.contentType match { 
     case `applicationJsonContentType` => 
      val jsFormat = { 
      val header = request.headers.find(h => h.name() == jsonFormatHeaderName) 
      if (header.isEmpty) "1.0" else header.get.value() 
      } 

      val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity) 
      val jsonText = data.decodeString(charBuffer.nioCharset().name()) 
      val dto = if(jsFormat == "2.0") { 
      write[T](value)(formats) // New Formatter 
      } else { 
      JsonFormat.fromJsonString[T](jsonText) // Old Formatter 
      } 
      dto 
     case `protobufContentType` => 
      companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)) // Proto Formatter 
     case _ => 
      throw UnsupportedContentTypeException(applicationJsonContentType, protobufContentType) 
     } 
    }) 

Tôi muốn làm điều tương tự với marshaller của tôi mà tôi sử dụng với Marshaller.oneOf và xử lý một JSON trông giống như:

Marshaller.withFixedContentType(contentType) { value => 
    val jsonText = JsonSerializer.toJsonString[T](value) 
    HttpEntity(contentType, jsonText) 
    } 

Có cách nào để xây dựng Mashaller nhận thức được tiêu đề http yêu cầu không? Tài liệu HTTP Akka không có bất kỳ ví dụ nào và tôi không thể hiểu được PredefinedToRequestMarshallers.

Tôi có cần kết hợp nhiều trình khắc phục sự cố bằng cách nào đó hoặc tôi có thể thêm một số siêu dữ liệu vào ngữ cảnh trong quá trình tuần tự yêu cầu mà tôi có thể sử dụng sau trong Marshaller không? Tôi muốn tránh thêm meta vào dto của mình nếu có thể hoặc sử dụng loại nội dung tùy chỉnh như application/vnd.api+json

Có rất nhiều thông tin hữu ích khác mà tôi có thể sử dụng từ yêu cầu khi tôi định dạng phản hồi như Accept-Encoding, tiêu đề tùy chỉnh như duy nhất yêu cầu id để tạo ra một id tương quan, tôi có thể thêm hỗ trợ JSONP bằng cách đọc các parmeter callback truy vấn vv

để làm rõ: tôi cần một giải pháp để sử dụng Mashaller, lớp con của nó hoặc một phiên bản tùy chỉnh được tạo ra bởi một phương pháp nhà máy hoặc có thể nhiều Marshallers xích lại với nhau. Marshaller.withFixedContentType đã sử dụng tiêu đề Accept do đó phải có cách. Tôi đã thêm tiền thưởng để thưởng cho một giải pháp cho một thử thách cụ thể. Tôi là kho của hacks và cách giải quyết và tôi hỏi câu hỏi bởi vì tôi cần một giải pháp sạch sẽ giải quyết một kịch bản cụ thể.

+0

Tôi có thể thiếu điều gì đó ở đây: tại sao bạn không khởi tạo trình khắc phục sự cố sau khi nhận yêu cầu và khi bạn biết bạn cần yêu cầu nào? Nó có ý nghĩa khi unmarshalling để quản lý tất cả các loại nội dung, nhưng marshalling là khá nhiều bạn chuyển câu trả lời của bạn để bất cứ điều gì bạn muốn, vì vậy nếu bạn muốn nó phụ thuộc vào yêu cầu, làm cho nó một chức năng của yêu cầu? – C4stor

Trả lời

0

Custom Marshallers phần đề cập đến Marshaller.oneOf phương pháp quá tải, điều đó dường như là những gì bạn muốn:

Helper để tạo ra một "siêu marshaller" từ một số "sub-marshallers". Nội dung thương lượng xác định, trong đó "tiểu thủ công" cuối cùng được thực hiện công việc.

Đối tượng đồng hành Marshaller có nhiều phương thức nhận được Seq[HttpHeader]. Bạn cũng có thể xem xét triển khai của chúng.

Tôi không có thời gian để tự xem mã nguồn, nhưng nếu điều này không đủ để đưa bạn đi đúng hướng, hãy cho tôi biết.

Sửa:

Làm thế nào về?

get { 
    optionalHeaderValueByName("JFORMAT") { format => 
    complete { 
     format match { 
     case Some(f) => "Complete with json4s" 
     case _ => "Complete with trueaccord" 
     } 
    } 
    } 
} 
+0

Tôi đang sử dụng Marshaller.oneOf với nhiều trình soạn thảo Marshaller.withFixedContentType nhưng chỉ sử dụng tiêu đề Chấp nhận. WithOpenCharset và Opaque cũng không có ref trong bối cảnh yêu cầu. –

+0

Tôi cần một marsheller có thể được sử dụng với oneOf nhưng cho phép ra quyết định dựa trên tiêu đề tùy chỉnh. –

+0

@JenoLaszlo Ah, bạn đã không đề cập đến trong câu hỏi của bạn rằng bạn đã sử dụng marshaller 'oneOf'. Bạn đang sử dụng loại nội dung nào? Và, thay vì trả lời trên tiêu đề tùy chỉnh, bạn có cân nhắc sử dụng tiêu đề 'Content-Type' để giải quyết vấn đề này không? –

Các vấn đề liên quan