Serving files in API response

Not applicable

I have an internal API returns a list of files in an array.

{
	"id": "123",
	"attachments": [
		"https://my-private-domain.com/SomeImage.png",
		"https://my-private-domain.com/SomeSpreadsheet.xlsx",
		"https://my-private-domain.com/Somedocument.docx"
	]
}

I'm creating a proxy for this API and need the users to be able to access the files via the API in a response that may look like this.

{
	"id": "123",
	"attachments": [
		"https://my-organization.apigee.net/123/SomeImage.png",
		"https://my-organization.apigee.net/123/SomeSpreadsheet.xlsx",
		"https://my-organization.apigee.net/123/Somedocument.docx"
	]
}

When the client accesses the link, they should be able to download the file.

We use Apigee in cloud and don't have apigee BaaS or access to any other filestore. Our API code on apigee is all javascript.

I think need to dynamically get the file into my API response payload and serve it to the client.

Is this possible? How do I approach the solution?

Solved Solved
0 4 1,336
1 ACCEPTED SOLUTION

You can solve this problem by writing a javascript function in the response flow.

This javascript policy would inspect the attachments array in the response and and translate "https://my-private-domain.com" into "https://my-organization.apigee.net/123"

Basically, your code would be something like (pseudo code - may not compile)

var targetJSONResponse = JSON.parse(context.getVariable("response.content"));

var re = new RegExp('https://my-private-domain.com/');
var originalRequestDomain = "https://"+context.getVariable('ORIGINAL_REQUEST_DOMAIN);

var transformedAttachments = []

targetJSONResponse.attachments.forEach(function transformAttachmentLink(attachmentLink){

transformedAttachments.push(attachmentLink.replace(re, originalRequestDomain+"/123"));

});

targetJSONResponse.attachments =  transformedAttachments

In the above Javascript, you can figure out the target domain by capturing the host request header in the Proxy Endpoint pre-flow and putting it into a context variable named ORIGINAL_REQUEST_DOMAIN.

You still have to solve for:

  • Error handling
    • Target Response is not JSON (server is down)
    • Target Response does not have the "attachment" key - Broken traversal
  • Your Private Domain and Organization URL's will vary by environment,- You can store these values in the environment context.

I would highly recommend that you try to avoid any URI path translations (if you can) between the proxy and the target endpoints. In your example, you seem to be translating paths as well

Target Path: https://my-private-domain.com/SomeImage.png
Proxy Path: https://my-organization.apigee.net/123/SomeImage.png

As you will notice , in addition to doing a domain translation, you also have to somehow inject "123".If "123" is static and doesn't change , no issues. If "123" is dynamic, you will have to engineer the intelligence to keep additional mappings.

View solution in original post

4 REPLIES 4

You can solve this problem by writing a javascript function in the response flow.

This javascript policy would inspect the attachments array in the response and and translate "https://my-private-domain.com" into "https://my-organization.apigee.net/123"

Basically, your code would be something like (pseudo code - may not compile)

var targetJSONResponse = JSON.parse(context.getVariable("response.content"));

var re = new RegExp('https://my-private-domain.com/');
var originalRequestDomain = "https://"+context.getVariable('ORIGINAL_REQUEST_DOMAIN);

var transformedAttachments = []

targetJSONResponse.attachments.forEach(function transformAttachmentLink(attachmentLink){

transformedAttachments.push(attachmentLink.replace(re, originalRequestDomain+"/123"));

});

targetJSONResponse.attachments =  transformedAttachments

In the above Javascript, you can figure out the target domain by capturing the host request header in the Proxy Endpoint pre-flow and putting it into a context variable named ORIGINAL_REQUEST_DOMAIN.

You still have to solve for:

  • Error handling
    • Target Response is not JSON (server is down)
    • Target Response does not have the "attachment" key - Broken traversal
  • Your Private Domain and Organization URL's will vary by environment,- You can store these values in the environment context.

I would highly recommend that you try to avoid any URI path translations (if you can) between the proxy and the target endpoints. In your example, you seem to be translating paths as well

Target Path: https://my-private-domain.com/SomeImage.png
Proxy Path: https://my-organization.apigee.net/123/SomeImage.png

As you will notice , in addition to doing a domain translation, you also have to somehow inject "123".If "123" is static and doesn't change , no issues. If "123" is dynamic, you will have to engineer the intelligence to keep additional mappings.

Thank you so much.

I'm not sure if I understand this so I'm explaining my interpretation.

A call to the proxy is made to get attachments

GET https://my-organization.apigee.net/123/attachments 

which will return (after translation)

{
	"id": "123",
	"attachments": [
		"https://my-organization.apigee.net/123/SomeImage.png",
		"https://my-organization.apigee.net/123/SomeSpreadsheet.xlsx",
		"https://my-organization.apigee.net/123/Somedocument.docx"
	]
}

The subsequent call from the client will be

GET https://my-organization.apigee.net/123/SomeSpreadsheet.xlsx 

For this to work, I'll have to intercept this request and make a call to the target URL https://my-private-domain.com/SomeSpreadsheet.xlsx

The target response will be the spreadsheet and if I don't change anything in the response , the client will get the file.

Is that correct?

Almost correct.

You don't have to "intercept" the call to https://my-organization.apigee.net/123/SomeSpreadsheet.xlsx

You will write a proxy endpoint (just like any other proxy endpoint) to handle the call at https://my-organization.apigee.net/123/SomeSpreadsheet.xlsx

When the call is made at the above URL , you will reach your target endpoint to render the spreadsheet.

I would recommend that you give some thought to organizing your URL's(proxy base path, resource path), so they can be pattern driven/convention driven.

Oh yes. I should create a proxy endpoint. Appreciate you taking the time to help. Your point about organizing the endpoint structure is noted too.