Skip to content

Commit 7ce2274

Browse files
committed
2 parents bbda63f + 53cedc5 commit 7ce2274

File tree

1 file changed

+50
-45
lines changed

1 file changed

+50
-45
lines changed

README.md

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
# ApacheFOP.Serverless
2-
*ApacheFOP.Serverless* is a ready to use server-less implementation of Apache FOP via Azure Functions. This provides a micro-service for dynamically rendering PDF binary outputs from XSL-FO source using Apache FOP.
1+
# ApacheFOP.Serverless -- Quality PDF Rendering-as-a-service for any Environment!
2+
*ApacheFOP.Serverless* is a ready to use server-less implementation of Apache FOP via Azure Functions. This provides an easy to use REST API micro-service for dynamically rendering quality PDF binary outputs from XSL-FO source using Apache FOP.
33

4-
You should be able to pull this code down, open with IntelliJ (after installing the Azure Toolkit for IntelliJ), and deploy to your own Subscription/Resource group and be up and running in minutes.
4+
When combined with the ease and simplicity of Azure Functions this project is a powerful, efficient, and scalable PDF Reporting Service that generates high quality, true paged media, reports for any environment and any client technology (.Net, NodeJS/JavaScript, Ruby, Mobile iOS/Android, Powershell, even Windows/Mac apps, etc.)!
5+
6+
You should be able to pull this code down and be up and running quickly & easily with IntelliJ or VS Code (after installing pre-requisites), or even just clone the repo and deploy directly to your Azure Subscription [via GitHub Actions with no local Java needed](#just-want-it-running-in-azure-and-dont-want-to-bother-with-any-local-installations).
57

68
If you like this project and/or use it the please give me a Star (c'mon it's free, and it'll make my day)!
79

@@ -49,12 +51,10 @@ then I do love-me-some-coffee!*
4951
- Removed dependency on `com.sun.deploy.net.HttpRequest` import as importing it no longer compiles on the latest versions of IntelliJ IDEA; little value was added by using only one constant that was needed: _ACCEPT_ENCODING_
5052
- All Heading and Content type constants are now self-contained so no additional dependencies are needed.
5153
- _This enabled removal of the dependency on com.sun.deploy.net.HttpRequest import as importing it no longer compiles on the latest versions of IntelliJ IDEA, and is a bad practice. Little value was added by using only 1 constant was needed, ACCEPT_ENCODING_
52-
5354
- Notable cleanup & optimization of the Pom.xml
5455
- Implemented a fix for a possilbe deployment risk when AppName and ResourceGroupName values are not unique with the azure-functions-maven-plugin
5556
- _As noted here: https://github.com/Azure/azure-functions-java-worker/issues/140_
5657

57-
5858
## Technical Summary:
5959
This project provides a REST API that recieves a POST body containing a well formed Xsl-FO Xml document ([like these Apache FOP samples](https://github.com/apache/xmlgraphics-fop/tree/trunk/fop/examples/fo/basic)). The service will respond with the rendered Pdf binary (file bytes).
6060

@@ -71,12 +71,10 @@ If an error occurs -- likely due to incorrect Xsl-FO syntax or structure -- then
7171

7272

7373
#### Postman Example:
74-
<p align="center">
75-
<img src="/postman-test-fonts-fo.png" style="width:auto;height:auto;max-width:1200px;">
76-
</p>
74+
<p align="center"><img src="/postman-test-fonts-fo.png" width="750px"></p>
7775

7876
## Project Overview:
79-
Generating high quality printable PDF outputs from a highly flexible [pdf templating approach (separating content/data from presentation)](https://github.com/cajuncoding/PdfTemplating.XslFO) hasn't been easy in the world of .Net -- vs the world of Java where ApacheFOP has been around for a very long time.
77+
Generating high quality printable PDF outputs from a highly flexible [pdf templating approach (separating content/data from presentation)](https://github.com/cajuncoding/PdfTemplating.XslFO) hasn't been easy in the world of .NET -- vs the world of Java where ApacheFOP has been around for a very long time.
8078

8179
For a more exhaustive dive into why PDF templating and markup based solutions are more powerful than report designer based solutions -- in today's modern web apps --
8280
I ramble on about that over here in:
@@ -85,12 +83,12 @@ I ramble on about that over here in:
8583

8684
Suffice it to say that markup based solutions have alot of value, and Xsl-FO is still one of the best ways to maintain strong software development practices by rendering PDF outputs (as a presentation output) from separated content/data + template. And Xsl-FO offers features that some approaches just can't do (looking at you *Crystal Reports*).
8785

88-
There has been a fully managed .Net C# port of [Apache FOP](https://xmlgraphics.apache.org/fop/) (FO.Net) based on a pre-v1.0 version (*is my guesstimate*); it's old & unsupported, but still fairly functional, and I've used it very successfully on several projects. But Apache FOP is now on [v2.5 as of May 2020!](https://xmlgraphics.apache.org/fop/2.5/changes_2.5.html) with annual/bi-annual support updates still being released.
86+
There has been a fully managed .NET C# port of [Apache FOP](https://xmlgraphics.apache.org/fop/) (FO.Net) based on a pre-v1.0 version (*is my guesstimate*); it's old & unsupported, but still fairly functional, and I've used it very successfully on several projects. But Apache FOP is now on [v2.5 as of May 2020!](https://xmlgraphics.apache.org/fop/2.5/changes_2.5.html) with annual/bi-annual support updates still being released.
8987

90-
So my goal has been, for a while, to take advantage of the many great innovations in the past several years to provide an interoperable integration between Java Apache FOP and .Net, without resorting to [something that makes my eyes cross (ugg).](http://codemesh.com/products/juggernet/).
88+
So my goal has been, for a while, to take advantage of the many great innovations in the past several years to provide an interoperable integration between Java Apache FOP and .NET, without resorting to [something that makes my eyes cross (ugg).](http://codemesh.com/products/juggernet/).
9189

9290
Taking advantage of some awesome new innovations (in Azure) we can do this in a much cleaner way using:
93-
- **[C# .Net for Templating using Razor](https://github.com/cajuncoding/PdfTemplating.XslFO)** *(anything other than native Java will benefit from this)*
91+
- **[C# .NET for Templating using Razor](https://github.com/cajuncoding/PdfTemplating.XslFO)** *(anything other than native Java will benefit from this)*
9492
- **Microservice** for integration architecture
9593
- **REST API** for interoperability
9694
- **Azure Function** for native Java Support
@@ -104,6 +102,12 @@ But, I did find that article left alot of nebulous details unclear, and would ex
104102

105103
And ultimately, it didn't provide any insight on how to configure Maven correctly *(I can hear some devs asking "what's Maven" right now)* or any code at all really. So, **Kudos** for the intro, but I hope this helps to bring it across the goal line!
106104

105+
### Conceptual Diagram - PDF-as-a-service:
106+
<p align="center"><img src="https://user-images.githubusercontent.com/20844814/166123451-afd6a573-9e9f-452d-a0b9-4512ee6cc189.png" width="750px" /></p>
107+
108+
### Conceptual Diagram - PDF Templating:
109+
<p align="center"><img src="https://user-images.githubusercontent.com/20844814/166123633-8e15a41b-6510-4cc9-a991-b4dfc25f08fe.png" width="750px" /></p>
110+
107111
## Getting Started:
108112
Here's the high level steps to get started...
109113

@@ -178,57 +182,58 @@ Configuration Values:
178182
- `KeepWarmCronSchedule` = `0 */5 * * * *` _(also required configuration for the KeepWarmFunction)_
179183
- `DebuggingEnabled` = `true` (Optional but very helpful once you start using it to return debug details in the responses).
180184

181-
## Calling the Service from .Net
185+
## Calling the Service from .NET
182186

183187
### Snippet:
184-
Because I talked about follow-through up above, I'd be amiss if I didn't provide a sample implementation of calling this code from .Net.
188+
Because I talked about follow-through up above, I'd be amiss if I didn't provide a sample implementation of calling this code from .NET.
185189

186-
Assuming the use of the great *RESTSharp library* for REST api calls, and the Xsl-FO content is validated and parsed as an *XDocument* (Linq2Xml)... this sample should get you started on the .Net side as a client calleing the new PDF microservice.
190+
Assuming the use of the great *Flurl library* for REST api calls, and the Xsl-FO content is validated and parsed as an *XDocument* (Linq2Xml)... this sample should get you started on the .NET side as a client calleing the new PDF microservice.
187191

188-
*NOTE: Just use RESTSharp and avoid [incorrectly implementing HttpClient (hint, it should be a singleton)](https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/)*
192+
*NOTE: Just use (Flurl)[https://flurl.dev/] or (RESTSharp)[https://restsharp.dev/] and avoid [incorrectly implementing HttpClient (hint, it should be a singleton)](https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/)*
189193

190-
Snippet taken from the [implementation here](https://github.com/cajuncoding/PdfTemplating.XslFO/blob/feature/iniial_support_for_apache_fop_serverless_rendering/PdfTemplating.XslFO.Render.ApacheFOP.Serverless/XslFOPdfRenderService.cs), in my PdfTemplating project.
194+
Here's a very simple client class that will get the job done! But this does not include functionality to handle debugging, viewing the event log which is returned in the response headers (and may be gzipped if large), etc. Therefore you might be interested in the readily available [.NET Client that's available in Nuget](https://www.nuget.org/packages/PdfTemplating.XslFO.Render.ApacheFOP.Serverless) -- more details below in the _**.NET Client**_ section.
191195

192196
```csharp
193-
using RestSharp;
194-
using RestSharp.CustomExtensions;
195197
using System;
196-
using System.CustomExtensions;
197-
using System.Threading.Tasks;
198-
using System.Xml.Linq;
198+
using System.Net.Mime;
199+
using System.Text;
200+
using Flurl;
201+
using Flurl.Http;
199202

200-
namespace PdfTemplating.XslFO.ApacheFOP.Serverless
203+
namespace PdfTemplating.XslFO.Render.ApacheFOP.Serverless
201204
{
202-
//READ from Configuration, or DI Constructor Injection
203-
private string apacheFOPServiceHost = "http://localhost:7071";
204-
private string apacheFOPServiceApi = "api/apache-fop/xslfo";
205-
206-
public static class ApacheFOPServerless
205+
public class ApacheFOPServerlessClient
207206
{
208-
public async Task<byte[]> RenderPdfBytesAsync(XDocument xslFODoc)
209-
{
210-
//Initialize the Xsl-FO microservice via configuration...
211-
var restClient = new RestClient(apacheFOPServiceHost);
212-
213-
//Get the Raw Xml Source for our Xsl-FO to be tansformed into Pdf binary...
214-
var xslFoSource = xslFODoc.ToString();
207+
public Uri ApacheFOPServerlessUri { get; protected set; }
208+
public string? AzFuncAuthCode { get; protected set; }
215209

216-
//Create the REST request for the Apache FOP micro-service...
217-
var restRequest = new RestRequest(apacheFOPServiceApi, Method.POST);
218-
restRequest.AddRawTextBody(xslFoSource, ContentType.Xml);
219-
220-
//Execute the request to the service, validate, and retrieve the Raw Binary resposne...
221-
var restResponse = await restClient.ExecuteWithExceptionHandlingAsync(restRequest);
210+
public ApacheFOPServerlessClient(Uri pdfServiceUri, string? azFuncAuthCode = null)
211+
{
212+
ApacheFOPServerlessUri = pdfServiceUri;
213+
AzFuncAuthCode = azFuncAuthCode;
214+
}
222215

223-
var pdfBytes = restResponse.RawBytes;
224-
return pdfBytes;
216+
public async Task<byte[]> RenderPdfAsync(string xslfoMarkup)
217+
{
218+
var pdfServiceUrl = ApacheFOPServerlessUri
219+
.SetQueryParam("code", AzFuncAuthCode, NullValueHandling.Remove);
220+
221+
using var response = await pdfServiceUrl.PostAsync(
222+
new StringContent(xslfoMarkup, Encoding.UTF8, MediaTypeNames.Application.Xml)
223+
);
224+
225+
var pdfBytes = await response.GetBytesAsync();
226+
return pdfBytes;
225227
}
226228
}
227229
}
228230
```
229231

230-
### .Net PdfTemplating (Full blown) Implementation:
231-
A full blown implementation of templating + ApacheFOP.Serverless is in a branch of my [Pdf Templating project here](https://github.com/cajuncoding/PdfTemplating.XslFO/tree/feature/iniial_support_for_apache_fop_serverless_rendering).
232+
### .Net PdfTemplating (Full blown) Sample Implementation & .NET Client:
233+
A full blown implementation of `Razor Templating + ApacheFOP.Serverless` is available in my [PdfTemplating.XslFO project here](https://github.com/cajuncoding/PdfTemplating.XslFO).
234+
235+
#### .NET Client
236+
The `PdfTemplating.XslFO` project also provides ready-to-use .NET Client for `ApacheFOP.Serverless` that is readily availalbe in Nuget: [PdfTemplating.XslFO.Render.ApacheFOP.Serverless](https://www.nuget.org/packages/PdfTemplating.XslFO.Render.ApacheFOP.Serverless/)
232237

233238
It illustrates the use of both Xslt and/or Razor templates from ASP.Net MVC to render PDF Binary reports dynamically from queries to the [Open Movie Database API](http://www.omdbapi.com/). And it has now been enhanced to also illustrate the use of _ApacehFOP.Serverless_ microservice for rendering instead of the embedded legacy FO.Net implementation.
234239

0 commit comments

Comments
 (0)