Как вернуть PDF файл в мутацию Graphql? - PullRequest
0 голосов
/ 15 апреля 2020

Я использую React и Graphql на внешнем интерфейсе, а Django и Графен на внутреннем.

Я хочу иметь возможность загрузить файл отчета в формате PDF. Я пытаюсь сделать это, используя мутацию следующим образом:

const [createPdf, {loading: createPdfLoading, error: createPdfError}] = useMutation(CREATE_PDF)
const handleCreatePDF = async (reportId) => {
        const res = await createPdf({variables: {reportId: parseInt(reportId) }})
        debugger;
    };

export const CREATE_PDF = gql`
    mutation ($reportId: Int!) {
        createPdf (reportId: $reportId){
            reportId
        }
    }
`;

На сервере у меня есть что-то вроде этого:

class CreatePDFFromReport(graphene.Mutation):
    report_id = graphene.Int()

    class Arguments:
        report_id = graphene.Int(required=True)

    def mutate(self, info, report_id):
        user = info.context.user

        if user.is_anonymous:
            raise GraphQLError("You are not logged in!")

        report = Report.objects.get(id=report_id)
        if not report:
            raise GraphQLError("Report not found!")

        if user != report.posted_by:
            raise GraphQLError("You are not permitted to do that!")

        html_string = render_to_string('report.html', {'report_id': 1})

        pdf_file = HTML(string=html_string)
        response = HttpResponse(pdf_file, content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="rapport_{}"'.format(report_id)
        return response


        # return CreatePDFFromReport(report_id=report_id)

Когда я раскомментирую return CreatePDFFromReport(report_id=report_id) это отлично работает.

Но я хочу вернуть pdf файл.

Есть ли возможность сделать это?

Спасибо.

1 Ответ

2 голосов
/ 15 апреля 2020

Это не может быть сделано только мутацией.

Вы не можете вернуть файл (двоичный файл) / заголовки (mime) / et c (необходимо обрабатывать браузером как запрос на загрузку) используя json 'ed связь. Запрос и ответ GraphQL имеют формат json.

Решение

Рабочий процесс:

  • вызов мутации (передача параметра в переменные)
  • resolver создает содержимое файла и сохраняет его где-то (хранилище файлов на сервере или s3)
  • resolver возвращает файл id, который будет частью URL-адреса загрузки, или полный url (строка) в целевой файл

id или url в этом случае должен быть частью требуемого ответа мутации

 mutation ($reportId: Int!) {
     createPdf (reportId: $reportId){
        reportDownloadId
    }
 }
  • результат мутации (и наш reportDownloadId) доступен в data

data (результат / ответ) от мутации можно получить двумя способами:

... по { data }:

const [addTodo, { data }] = useMutation(ADD_TODO);

... или обработчиком onCompleted:

addTodo({ 
  variables: { type: input.value },
  onCompleted = {(data) => {
    // some action with 'data'
    // f.e. setDownloadUrl(data.reportDownloadId)
    // from 'const [downloadUrl, setDownloadUrl] = useState(null)'
  }}
});

Оба метода описаны в документах

Оба метода позволят вам (условно) отобразить кнопку загрузки / link / component, fe

{downloadUrl && <DownloadRaport url={downloadUrl}/>}

{downloadUrl && <a href={downloadUrl}>Raport ready - download it</a>}

// render download, share, save in cloud, etc.

Метод обработчика может использоваться для автоматического вызова запроса загрузки файла , без визуализации нг дополнительная кнопка. Это будет выглядеть как одно действие, а технически есть два следующих запроса (мутация и загрузка graphql). В этой ветке описывается, как обрабатывать загрузки, используя js.

.
...