9

What are the conventions for providing publicly accessible URLs for resources that are managed via a single page application? I think this is an architectural design question, but I anticipate developing an SPA in AngularJS, in case that matters. I'm new to SPAs.

The user will create, view, and modify resources (e.g. server-based objects) of various sorts via an SPA. These same resources will also be accessible to the general public via permalink URLs. I'm fine with the SPA displaying a resource for visitors upon visiting the resource's permalink URL.

I can only think of these two approaches:

  1. Place all resources at http://example.com/resourcetype/resourceID, implementing RESTful APIs here (varying the HTTP method).
  2. Place all permalinks at http://example.com/resourcetype/resourceID and have the SPA hit http://example.com/api/resourcetype/resourceID.

(It doesn't seem reasonable to have permalinks under /api. By "permalink", I just mean the public not-logged-in URL for a resource.)

I would prefer that a user who navigates to a resource via an SPA arrive at a shareable URL, because a user wanting to share that page is going to first think to share its URL, not to first find a link to the permalink page. This suggests employing the first approach, but the second approach is better for versioning APIs via URLs such as /api/v1, /api/v2, etc.

It would be ideal to avoid hashes in the URLs. I understand that I can use HTML5 mode in AngularJS to hide them in browsers that support the mode. This would also require server-side support, and I have seen the solution that rewrites deep links as links to SPA access URLs.

I'd like to know what people are actually doing and whether people find themselves limiting the use of SPAs in practice. Thanks for your help!

Joe Lapp
  • 2,435
  • 3
  • 30
  • 42
  • This page asking whether AngularJS is just for SPAs is informative. It mentions providing different AngularJS clients for different site resources. http://stackoverflow.com/questions/15231251/is-angularjs-just-for-single-page-applications-spas – Joe Lapp May 07 '16 at 02:41
  • Here's a helpful discussion on when an SPA helps and when it doesn't. https://news.ycombinator.com/item?id=9879685 – Joe Lapp May 07 '16 at 02:43

2 Answers2

4

At our office, we use both resourceIds as well as slugs. Any shareable resource will have a slug property that is generated by a property of the resource model. For example, anyone who writes an Article for our SPA must give the Article a title. That title is validated by the server on save to ensure that there are no other articles containing the same title. If the title is unique, a slug is generated for that resource and saved to our DB, otherwise the server responds with an error message stating that the title is not unique.

Then in our state declarations when a user visits http://example/articles/article-slug, we query our API for an article matching the article-slug and return 404 if no article is found.

        .state('app.articles.article', {
            url: '/:slug',
            views: {
                articles: {
                    templateUrl: tpl + 'views/frontend/articles.article.html',
                    controller: 'ArticleCtrl',
                    resolve: {
                      article: ['$stateParams', function ($stateParams) {
                            var slug = $stateParams.slug;
                            // query API for slug
                      }]
                    }
                }
            }
        })
SuperVeetz
  • 2,128
  • 3
  • 24
  • 37
  • Interesting. So when your SPA generates a new resource, it creates a permalink based on a slug that is not addressed relative to a path component for a resource type? Does that mean each resource has two access points? Would both be publicly shareable? – Joe Lapp May 07 '16 at 01:12
  • You've given me an idea, although this idea could have been your intent. I might be able to alleviate the varying permalink problem by only using slugs and never using IDs that are specific to resource types. One base URL would be the single access point to all objects, and users navigating to an object would arrive at this permalink URL even from the SPA. (Except this seems like my option 1, with the SPA on the domain root and no indication of the API version in the URL.) – Joe Lapp May 07 '16 at 01:16
1

This is a well understood, but massively under-communicated weakness of all SPAs. To support permalinks (and dynamic URLs) in our Vue application, we use web server URL rewriting. We create an Apache rewrite rule that listens for specific known/reserved permalinks or dynamic URL patterns and rewrites the request to the ONLY viable endpoint for an SPA (i.e./index.hml) with a custom query string parameter referencing the desired resource.

For example:

RewriteEngine On
RewriteRule ^somemodule/(.*?)$ /?somemodule=$1 [R=301,L]

The rule above listens for a request URL like mywebsite.com/somemodule/32 and rewrites it to mywebsite.com/{index.html}?somemodule=32

Our Vue app uses a "middleware" component that inspects ALL requests, looking for our reserved query string parameter matching ?somemodule=x. When it encounters this, it INTERNALLY routes the request to the proper component/module.

Dealing with permalinks and dynamic URLs in SPA's is a serious hassle. Hopefully the approach above provides some additional food for thought.

rmirabelle
  • 6,268
  • 7
  • 45
  • 42
  • 1
    Yikes. I can see that this would do it. I may have posted this question 5.5 years ago, but I will shortly be facing the issue again, so your response is timely. Thank you so much! – Joe Lapp Dec 23 '21 at 02:31