Perhatikan aliran berikut:

public client ----> DRF API on Service A ------> DRF API on Service B

Beberapa API DRF pada Layanan A hanya mem-proxy ke Layanan B, jadi pada API tertentu pada Layanan A terlihat seperti ini:

class SomeServiceAPI(APIView):
    def get(request):
        resp = requests.get('http://service-b.com/api/...')
        return Response(resp.json())

Meskipun ini berfungsi pada status normal, tetapi memiliki beberapa masalah:

  1. Itu tidak mem-proxy kode status aktual dari layanan b.
  2. Perjalanan serialisasi json yang tidak perlu dalam Response()
  3. Jika layanan b mengembalikan kesalahan non-json, layanan tidak mengembalikan kesalahan aktual dari layanan b.

Pertanyaannya adalah, apakah ada cara yang lebih baik untuk melakukannya? Saya telah melihat proyek Django Rest Framework Proxy, tetapi saya tidak sepenuhnya yakin jika itu benar-benar sesuai dengan kasus penggunaan saya di sini.

10
James Lin 10 Agustus 2017, 12:51

2 jawaban

Jawaban Terbaik
  1. Anda dapat menyelesaikan bagian kode status dengan memodifikasi Response Anda:

    return Response(resp.json(), status=resp.status_code)
    
  2. Untuk bagian kedua, inilah inti dari Proxying... (Benar, terkadang Anda ingin memanipulasi permintaan dan/atau respons di perantara proxy, tetapi yang Anda lakukan adalah intinya).

Catatan:

  • Proxy DRF yang Anda sarankan tampaknya berfungsi dengan baik baiklah, tanpa perlu Anda menulis tampilan tertentu hanya untuk perjalanan pulang pergi.
  • Ada alat lain, DRF Reverse Proxy yang merupakan port DRF dari Django Revproxy dan Anda mungkin ingin mempertimbangkan.

Gagasan umum dari kedua hal di atas adalah Anda membuat jalur URL khusus untuk Proksi jalur ke API lain:

Proxy DRF:

Tambahkan proxy Anda ke settings.py:

REST_PROXY = {
    'HOST': 'http://service-b.com/api/'
}

Dalam urls.py:

url(
    r'^somewere_in_a/$', 
    ProxyView.as_view(source='somewere_in_b/'), 
    name='a_name'
) 

Proxy Terbalik DRF:

Hampir mirip dengan yang di atas, tanpa bagian pengaturan:

url(
    r'^(?P<path>.*)$', 
    ProxyView.as_view(upstream='http://service-b.com/api/somewere_in_b/'),
    name='a_name'
)

Pendapat: Proxy DRF tampaknya lebih solid.. .

6
John Moutafis 10 Agustus 2017, 11:57

Saya telah melihat kedua paket yang ada yang disebutkan dalam jawaban John tetapi tampaknya tidak cocok dengan kasus penggunaan saya, jadi saya telah membuat pembungkus sederhana untuk mem-proksi respons permintaan terhadap respons DRF.

# encoding: utf-8
from __future__ import unicode_literals
from __future__ import absolute_import
from rest_framework.response import Response
from requests.models import Response as RResponse


class InCompatibleError(Exception):
    pass


class DRFResponseWrapper(Response):
    """
    Wraps the requests' response
    """
    def __init__(self, data, *args, **kwargs):
        if not isinstance(data, RResponse):
            raise InCompatibleError

        status = data.status_code
        content_type = data.headers.get('content_type')

        try:
            content = data.json()
        except:
            content = data.content

        super(DRFResponseWrapper, self).__init__(content, status=status, content_type=content_type)

Dan gunakan seperti di bawah ini:

    resp = requests.get(
        '{}://{}/api/v5/business/'.format(settings.SEARCH_HOST_SCHEMA, settings.SEARCH_HOST),
        params=request.query_params
    )
    return DRFResponseWrapper(resp)
4
James Lin 10 Agustus 2017, 22:15