How to render html in backend and save to pdf? - html

I am creating a document for my users that is prefilled/customized with each user's information, and I would like to save a copy of the document to my database/filesystem.
To show the document to the user, in the frontend I have a React page with a few blanks. I pull info from the backend to fill in those blanks, and I allow the user to print the finished document out. I would like to save a pdf for myself in the backend too, though, and I'm not sure how to do it.
Is it possible to render and populate React in my backend and convert that into a pdf, all in the backend?
I've tried Googling different solutions, but I haven't found anything helpful.

use headless browser, such as puppeteer:
const puppeteer = require('puppeteer')
async function printPDF(url) {
const browser = await puppeteer.launch({ headless: true })
const page = await browser.newPage()
await page.goto(url)
const pdf = await page.pdf({ format: 'A4' })
await browser.close()
return pdf
}

depending on what programming languague is your BE using, you can likely follow these steps with the proper library:
On the BE you should have access to your customer information already as you're sending it to FE.
With this information use a template system to render the variables to the HTML code, you may need to edit your react code a little to match the template scheme.
Then with the render template use a library to generate a PDF file and save it to the proper place (depending on your architecture, eg: on a folder on the same system, an s3 bucket, etc).
Finally after saving the pdf and getting the URL, save the string URL to your user table if any.
For example, in python you can use the following libs:
jinja (template renderer)
pdfkit (html pdf renderer)

Related

get json data from a public json file not REST api with React

I have a url similar to https://www.nonexistentsite.com/fubar.json where fubar.json is a public json file which will download to your file system if you navigate to the url with your browser. I have a React web app where I want to read that file directly so as to display some of its data. I don't want to bother with any kind of a backend that would download the file to the apps file system so that it can read it. I want the React front end to read it directly in it's client side code with a fetch or an axios call or something like that. I'm familiar with the typical situation where I have a REST url like https://www.nonexistentsite.com/fubar which I can call and get the data. I'm failing to find info on how to handle this situation.
You could use Axios to load the data from the json file.
Example usage;
axios.get('https://www.nonexistentsite.com/fubar.json')
.then(jsoncontent => {
console.log(jsoncontent);
//do stuff with jsoncontent here
});
Maybe I'm misunderstanding your question, but I believe if you are just needing to fetch the json from a hosted file, you should be able to do so with axios.get(url)

loading json files with axios.get from static directory

In my vue.js App I have been loading all the data from an API that I have configured as baseURL in my nuxt.config.js.
Now I want to load a static json file, that does not come from that API. That file will include additional names of files to load depending on user interaction.
In order to keep my code consistent I would like to use axios.get to load the static data in the same way I do with API calls.
So far I haven't managed to do so.
I placed the json files inside my static directory an have tried to access the files like this:
const { data } = await axios.get(
'_nuxt/static/json/staticData.json',
{ baseURL: window.location.origin }
)
I can access other static files like images form the static directory, but the json file generates a 404 error.
Should I choose another directory or try a totally different approach?
I included the path segment "_nuxt/static/" because the URL of the rendered image file i checked for reference had it in there too. Turns out this is not the right URL for my Axios call. Code should be written like this:
const { data } = await axios.get(
'/json/staticData.json',
{ baseURL: window.location.origin }
)

Generating PDF from json and json-schema

We're currently using Alpaca Forms to generate forms which we use to edit data stored in json for our application. We're now looking for a way to, server side, generate PDF documents, using json-schema and the json.
Ideally this would be using C#, but frankly, we really could use any language, as long as we can put it behind a web service.
Basically, it would be Alpaca, but the output would be a PDF report, which could contain a cover page and other document friendly features. It would also use the "title" and "description" fields from the json-schema.
Any ideas other than trying to roll our own? I'd rather not PDF library, since most seem to not be that document oriented.
wkhtmltopdf is my personal favourite way of doing this. You should be able to convert your JSON schema into HTML, and then render it via that.
If you are using Node: You can use Chromium's (Opensource Chrome browser) Puppeteer to launch a headless browser, server side, which can generate a PDF.
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
page.setContent('<h1>My PDF!</h1>');
const myPdf = page.pdf();
See https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagepdfoptions for more PDF options when generating from Puppeteer
I haven't tested the code above but that's the basics of what I'm using to generate PDF's
npm i puppeteer will be needed :)
It may be difficult (impossible?) to convert the Alpaca Forms JSON automatically into something that lays out pages the way you want. For example, does the Alpaca JSON provide enough information to determine page size, orientation, headers, footers, numbering location and style etc?
Docmosis may be useful to you (please note I work for Docmosis). You would layout your PDF in a word processor document and call Docmosis to merge it with your JSON data to create the PDF. The fields in your template drive the data extraction so you can put <> into your template and the title will be extracted from the JSON. In the case of Alpaca it looks like the title might be keyed under "schema" in the JSON, so you would use <> in a Docmosis template. Page layout and styles come from the template. The quickest way to test this as a candidate solution is to create a cloud account, upload a template and call the REST API with your JSON to create the document. If that does what you need you have the cloud or on-premise options.
I hope that helps.
if ideally for you is C#, then to generate PDF from json you need:
Parse JSON to some C# collection;
Loop through collection and write data into PDF-table;
Save file as PDF.
For this purpose you will need some PDF-creating library.
Here is an example, how to implement it in C# using PDFFlow library:
Prepare class for storing data:
public sealed class ReportData
{
public string name { get; set; }
public string surname { get; set; }
public string address { get; set; }
}
Read data from JSON into collection:
string jsonFilePath = Path.Combine(SubfolderName, JSONFileName);
List<ReportData> jsonData = JsonSerializer.Deserialize<List<ReportData>>(File.ReadAllText(jsonFile));
Create PDF document and add table to it:
using Gehtsoft.PDFFlow.Builder;
var section = DocumentBuilder.New().AddSection();
var table = section.AddTable();
table
.AddColumnToTable("Name", 150)
.AddColumnToTable("Surname", 250)
.AddColumn("Address", 300);
Loop through collection and add data to a table:
foreach(var rowData in jsonData)
{
var row = table.AddRow();
row
.AddCellToRow(rowData.name)
.AddCellToRow(rowData.surname)
.AddCell(rowData.address);
}
Save document to PDF file:
section
.ToDocument()
.Build("Result.PDF");
To compile this code you need to add reference to PDFFlow library to your project.
Hope, this will help.
Here is a fully working example of PDF contract generation, demonstrating how to work with JSON as a data source: contract example

Can I access a blob URL in an external page? [duplicate]

I try to write an extension caching some large media files used on my website so you can locally cache those files when the extension is installed:
I pass the URLs via chrome.runtime.sendMessage to the extension (works)
fetch the media file via XMLHttpRequest in the background page (works)
store the file using FileSystem API (works)
get a File object and convert it to a URL using URL.createObjectURL (works)
return the URL to the webpage (error)
Unfortunately the URL can not be used on the webpage. I get the following error:
Not allowed to load local resource: blob:chrome-extension%3A//hlcoamoijhlmhjjxxxbl/e66a4ebc-1787-47e9-aaaa-f4236b710bda
What is the best way to pass a large file object from an extension to the webpage?
You're almost there.
After creating the blob:-URL on the background page and passing it to the content script, don't forward it to the web page. Instead, retrieve the blob using XMLHttpRequest, create a new blob:-URL, then send it to the web page.
// assuming that you've got a valid blob:chrome-extension-URL...
var blobchromeextensionurlhere = 'blob:chrome-extension....';
var x = new XMLHttpRequest();
x.open('GET', blobchromeextensionurlhere);
x.responseType = 'blob';
x.onload = function() {
var url = URL.createObjectURL(x.response);
// Example: blob:http%3A//example.com/17e9d36c-f5cd-48e6-b6b9-589890de1d23
// Now pass url to the page, e.g. using postMessage
};
x.send();
If your current setup does not use content scripts, but e.g. the webRequest API to redirect request to the cached result, then another option is to use data-URIs (a File or Blob can be converted to a data-URI using <FileReader>.readAsDataURL. Data-URIs cannot be read using XMLHttpRequest, but this will be possible in future versions of Chrome (http://crbug.com/308768).
Two possibilities I can think of.
1) Employ externally_connectable.
This method is described in the docs here.
The essence of it: you can declare that such and such webpage can pass messages to your extension, and then chrome.runtime.connect and chrome.runtime.sendMessage will be exposed to the webpage.
You can then probably make the webpage open a port to your extension and use it for data. Note that only the webpage can initiate the connection.
2) Use window.PostMessage.
The method is mentioned in the docs (note the obsolete mention of window.webkitPostMessage) and described in more detail here.
You can, as far as I can tell from documentation of the method (from various places), pass any object with it, including blobs.

API return data in CSV format

I'm creating an API which should return data in a CSV format. I set the content-type header to text/csv but this forces a download of the contents as a csv file.
I'm using NodeJS and the express framework. It could be that this is standard behaviour. However I would like to know how you guys solved this issue.
This is a sample of the code that I'm using:
res.set('Content-Type', 'text/csv');
var toCsv = require('to-csv');
// obj is a just a standard JavaScript object.
res.send(toCsv(obj));
I would like that the person using the API can retrieve data in a CSV format without actually downloading a file
Maybe have a look at this question:
How does browser determine whether to download or show
It's your browser that decides that content of the type "text/csv" should be downloaded.
You should simply consider using another content-type, if you just want the csv to show in the browser as plain text.
Try this instead:
res.set('Content-Type', 'text/plain');