4

A client can call the following REST api URI to send an enquiry

POST /v1/businesses/{business_name}/enquiries

The enquiry can then be viewed through the following call:

GET /v1/businesses/{business_name}/enquiries/{enquiry_id}

When a new enquiry is posted, the business is informed via email. The email includes a link to the enquiry. The issue I have is that the API will add the following link to email:

http://api.com/v1/businesses/{business_name}/enquiries/{enquiry_id}

When a user clicks the link in the email, they will be incorrectly taken to the API resource instead of the client page. So I need the email to contain the following link:

http://client.com/dashboard/{business_name}/enquiries/{enquiry_id}

Noted: Above client URL is an example. Clients can implement their own routing however they want, a single page client app URL could also be used. The point is, the client URL must be exposed in the email, not the API URL.

I'm not quite sure how to get client URLs into the email.

One option would be to provide a client URL in the original POST request. Problem with this is that the client won't know the URL to use until after the POST, at which point the email has already been added to the queue.

Another option is to pull out the queueing of emails from the API and make the clients responsible for it. I don't really like this idea as client implementers will not be too happy that they purchased the API, only to then find out they then have to decide when to queue emails.

  • Just prefix every link with the current domain? What is the exact issue you are having? I expect you have a general method which generates an url which should make it an easy fix? – Luc Franken Jan 30 '15 at 6:40
  • No idea which language we use but for example in PHP you could use: php.net/manual/en/reserved.variables.server.php which gives you the domain, for example: $restUrl = 'https://' . $_SERVER['SERVER_NAME'] . '/v1/orders/1234'; – Luc Franken Jan 30 '15 at 8:40
  • Yes take it out the request as it is generally slow. Search for something like a queue, enough solutions for that. Or send out an event which can be taken by the email process. About your urls: Did you read about HATEOS? You then deliver the urls to your client so it does not need to generate them which is easier to upgrade and to build a client for. – Luc Franken Jan 30 '15 at 9:56
  • I think you should improve the quality of your question to get a complete answer. At the moment you insert an order into your database you also can know the url to it. You can even store it with the order in the database if you cannot generate it later so there should be no issue. If there is an issue it should be good to expand the question with enough details. – Luc Franken Jan 30 '15 at 10:09
1
+50

For a simple solution that doesn't require you to change the links in the emails, you could have the relevant part of your API respond to requests from user agents in a way that makes sense to an end user.

Have your API respond to requests with an accept header containing text/html by redirecting them to a remote resource specified by the business. Allow the businesses to set up the redirect path (with some simple token replacement) through another part of the API.

If the business hasn't set up a redirect path, serve up an HTML page containing the content of the enquiry instead of redirecting the request.

Of course, this only needs to be done for the part of the API that's linked to in the emails.

This approach has the advantage of businesses being able to change the redirect path at any time, and if a customer clicks on a link in an old email, they will get sent to the new remote resource. This also allows you to do click tracking if you want to.


Here's an example of how it might work:

  • Your client "Business A" wants to show enquiries on their own dashboard, so they set up a redirect path by making a request: PUT /v1/businesses/business_a/enquirypath, containing {"path":"http://business_a.com/dashboard/enquiries/{id}"}.

  • Your client "Business B" doesn't have their own dashboard, so they don't set up a redirect path.

  • You send out emails on behalf of businesses A and B. The emails link to the same resources that your API uses.

  • An end user clicks the link in the email from Business B. Your server sees that HTML content is being requested (rather than JSON/XML). Business B has not indicated that requests should be redirected, so the API simply serves up the enquiry in user-friendly HTML form, like the user agent requested.

  • An end user clicks the link in the email from Business A. Your server sees that HTML content is being requested again. Business A has indicated that enquiry requests should be redirected to their own server, so your API redirects the request to the path they specified.

  • Sounds good. How could I implement? Maybe API URI is /v1/email/businesses/{business_name}/enquiries/{enquiry_id}. This link is added to email. Clicking the link does take a user to the API, but API looks up the client preferences and then redirects accordingly? It then just means the client has to setup all their preferences in advance, or maybe just provide a domain and then defaults are applied? – Gaz_Edge Feb 2 '15 at 9:53
  • How are you going to redirect to a path specific to each email? Either you need to communicate the request I'd, or the client's redirect will be the same for everyone. – asthasr Feb 2 '15 at 12:10
  • Yes, but that's exactly the same that I told you to do in my answer. It just relocates it from being in the email to being in a redirect. – asthasr Feb 2 '15 at 13:16
  • @syrion having the API respond to requests for HTML content in an appropriate way and forwarding on to a remote resource is entirely different from the approach you describe in your answer, IMO. The only similarity is having the client (business) configure a redirect path, which seems unavoidable. I assume the downvote was yours. I find your answer to be rambling and of low quality, and I think the method I describe here is cleaner, so I will downvote yours also. – Hey Feb 2 '15 at 18:44
  • @Hey: The problem in the original question is, "How do you include the [partner's] URL in an email?" My question answers that by explaining how to generate a URL based on the partner's settings. Your answer simply says to redirect from the API endpoint to that URL; you still have to generate a URL, the same as if you were putting it in an email. It does not solve the problem stated in the question, but changes the location where it occurs. – asthasr Feb 2 '15 at 19:11
2

How is the enquiry_id in the "client URL" (that points to a partner's site) generated? If it always matches the enquiry ID that is being used for the URLs you control, then you can simply require that the partners provide a URL template for you to use when setting up an integration with their system. When you generate the email, use the provided URL template to generate the partner URL.

By contrast, if the URL is completely generated by the partner, you need to add a step prior to sending the email: a call to the partner's API in order to determine the URL.

Whichever way, there is behavior that is necessary from both your application and the partner's application: they must provide a way for you to generate an URL for yourself (in which case you bear the responsibility for generating the URL and sending it), or they must provide a way for you to ask them to generate a URL (in which case you bear the responsibility for the API call and inserting the URL in the email).

This is a very typical integration scenario, by the way.

You may also consider whether the URL generation is different on a per-partner basis. If you are partnered with four companies, two might use standard URL templating while the other two require customized integrations to determine an URL. On an architectural level, this means that you will need to accommodate flexibility in this subystem:

  1. Time to send an email.
  2. Which partner is this email using?
  3. How do I generate an URL for this partner?
  4. Generate the URL.
  5. Include the URL in the email.
  6. Send the email.

A common approach to this would be to have an URLGeneratorFactory that returns a class implementing the interface URLGenerator; the identity of the partner determines which specific implementation is used.

I have written an example to clarify this answer.

  • really confused by your answer. Can you use the same terminology throughout e.g. 'client' and 'API' instead of 'you', 'they', 'application', 'partner'... – Gaz_Edge Feb 1 '15 at 16:03
  • These are very standard industry terms. "You" is taken to mean your team or your company; thus "URLs you control" means URLs that point to your application (where application means the code that you're asking a question about). "Client" is a bad term, because it has a specific meaning in API terms; I have changed that to "partner" throughout, and it refers to the other company (whose emails you are sending). – asthasr Feb 1 '15 at 16:43
  • its still very confusing. You seem to be suggesting that my API calls some client API? Is that right? When i say 'client' i mean the code that calls the REST API. Example could be some single page AngularJS app. So these clients are not some business partner I've teamed up with. They are browser side clients. – Gaz_Edge Feb 1 '15 at 17:18
  • Who is the entity which owns this URL in your original question? => http://client.com/dashboard/{business_name}/enquiries/{enquiry_id} – asthasr Feb 1 '15 at 18:13
  • @Gaz_Edge, I have added an example to the answer. – asthasr Feb 1 '15 at 21:46
2

Terms:

USER = end user of your client
CLIENT = your client
API = your server

Your example urls:

POST /v1/public/{business_name}/enquiries GET /v1/businesses/{business_name}/enquiries/{enquiry_id}

Don't do access control in your urls. One resource one url is most simple for your customers to understand.

Also:

A client can call the following REST api URI to allow an unauthenticated user

The fact that the end user is unauthenticated does not mean the client is unauthenticated.

So let's say that your enquiry gets posted:

USER sends post to: client.com/some/custom/path/enquiries
CLIENT receives the post post
CLIENT authenticates to the API
CLIENT sends post data to your API
  OR CLIENT sends post data + path to your API (path could be: client.com/some/custom/path/enqueries/{id} as an url template)
API receives the post
  IF no url is supplied lookup the client url in the database)
API inserts in database
API returns to CLIENT: {success: 1, url: 'http://api.com/enquiries/123'}
  OR API returns to CLIENT: {success: 1, url: 'http://api.com/enquiries/123', clientUrl: 'http://client.com/enqueries/123'}
CLIENT RECEIVES the response
CLIENT sends response back to USER ("Thanks for your enquiry" OR "You did not fill out a required field")
API adds e-mail to the queue, it knows the url from the post OR from the settings in the database for this client. 

This way you can also customise the e-mails more because they can contain a logo, business name of your client etcetera.

EDIT Good to see the question improved!

After reading your question again here you seem to get stuck:

One option would be to provide a client URL in the original POST request. Problem with this is that the client won't know the URL to use until after the POST, at which point the email has already been added to the queue.

I thought this maybe needs a bit more clarification.

First rule in your business case is:

You want to send a link via e-mail to the client domain. Only the client knows the domain.

That explicitly requires the the client let's the API know the domain, otherwise it cannot perform the send e-mail action. Agree on that?

I am not sure whether you are known with URL templates, an example is this:

https://client.com/some/custom/path/enqueries/{id}

Example here: https://github.com/mikekelly/hal_specification/blob/master/hal_specification.md#applicationhaljson

So the client does not give you the full URL but a template which you parse in your API. You agree upfront on the variables which can be used.

That means you have 2 options:

  1. Client sends you the domain upfront. For example at the moments:

    • When the client signs up for your API service You can do this via your registration form or configuration panel for example.
    • When the client logs in
    • Just in a separate request
  2. Client sends you the domain with the request.

    JSON { urlTemplate: 'https://client.com/some/custom/path/enqueries/{id}', enquery: { name: 'test', } }

You have to accept that the client needs to let you know the url if it's custom. You cannot magically find it.

You have multiple options to receive it, just select what's best for you.

  • cool, so what kind of direction are you following? Are you going for setup for the client or use some request headers? – Luc Franken Feb 2 '15 at 11:32
  • I'm not 100% sure on your question, can you rephrase? – Gaz_Edge Feb 2 '15 at 12:47
  • I was interested in whether you are going to require your clients to do a setup/registration for your API where they enter the desired urls or that you are going to get the info from request itself? – Luc Franken Feb 2 '15 at 14:26
  • I think i will make the client send it with each request. Seems more RESTful providing everything in one stateless request. Its also easier to inform clients of any resource which may now require a template email URI by returning a validation error if they don't provide one in the request. – Gaz_Edge Feb 2 '15 at 21:41
  • Yes sounds very reasonable. It's not unRESTfull to do it in the login procedure but still it sounds like a good choice. Also I think developers like it because it gives more control. You can also send out a validation error when it's in config but it less obvious clearly. – Luc Franken Feb 3 '15 at 6:58

protected by gnat Feb 2 '15 at 8:04

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.