Confusion about Controllers, Routes & Responses

Hello again,

I am back from yesterday’s session and I want to address dome of your direct questions.

Generally, this is hard to answer as I do not know the kind of app you have in mind. For the beginning, I see however only a few typical use cases, that can be described.

Description Example Route Controller Response Remarks
Serve HTML page Entrypoint for app FrontendRoute or routes Controller TemplateResponse
Serve public HTML page Public sharing for anonymous access FrontendRoute or routes Controller PublicTemplateResponse
Data transmission Send data between backend and frontend ApiRoute or ocs OCSController DataResponse opinionated preference
File transmission Send images between backend and frontend FrontendRoute or routes Controller FileResponse or whatever suits best
Data transmission Send data between backend and frontend FrontendRoute or routes Controller DataResponse or JSONResponse as a fallback
Data sharing Allow data to be accessed from foreign websites ApiRoute or ocs OCSController DataResponse Enable CORS (but understand the implications!)
File providing Access files from foreign website FrontendRoute or routes ApiController as needed Implement security as needed

Mainly you have to separate OCS from non-OCS. So, either route & controller are bothe OCS or neither is.

I would say to prefer OCS over non-OCS as there are some more options with OCS related to security. This makes live easier. The argument about consistent API, I would say, is not too pressing. You (as app dev) can define how stable a certain endpoint is.
If you want to provide a stable API, you could define a subset of your endpoints as stable, nevertheless.

I think there might be some checks but it could be that if you mix OCS with non-OCS, your routes might simply be not found/reachable. I’d say give it a try and see what happens.

PublicPage is just a security configuration. It means anyone can access the route, you do not need to be logged in.
PublicTemplateResponse is a Response, that renders a HTML page in the public style without navigation bar to all apps.

I think this should be clear after the last message, mostly.

URL is controlled by the corresponding route. The data format is controlled by the question of OCS/non-OCS and the Reponse object returned from the controller.

All endpoints are CSRF-protected by default. You could disable this using #[NoCSRFRequired]. But you shoud not do this. Instead work correctly with CSRF.

  • In the frontend, you can use the session CSRF token e.g. by using the @ nextcloud/axios package that handles CSRF for you. I heard that classical fetch would work as well but I would have to think it through.
  • If you have an OCS route, you just need to provide the OCS-APIRequest: true header to satisfy CSRF checks. Nice for apps etc. [1]

[1]: Remark: Since a recent version of NC released, also normal routes allow the OCS-APIRequest: true header. It sounds sort of strange but, hey…

The usage of CORS is easier with ApiController or OCSController as the (pre-flight) header handling is mostly included with them. You have to register the route for the pre-flight(s) nonetheless, though.

The #[CORS] attribute on the controller methods enables the CORS handling. Just be warned not to use it without thinking.

It is a misunderstanding. It just means a normal route based on the index.php file where you can configure the response freely.

As DataReposonse is automatically converted to JSON AFAIK, it is convenient as you can simply switch between OCS and non-OCS by just switching the controller base class and the routes’ attributes/settings in routes.php.

There is no recommended way. In the cookbook app (where I refactored the API quite some time ago), I have a documentation for devs [1, 2]. I have a prefix /webapp for internal API requests and /app for external ones. I do not like it that way as it doubles the work needed to maintain the app (both internal and external APIs need care).

I will migrate to a common OCS-based API in the long-term. Then, I can merge internal and external without a problem there. The point is that also in the internal API I do want stability once the app is out. So, I can still define e.g. /api/v1 for the first version and if I have breaking changes go to /api/v2.

That depends. The API reference is the condensed documentation. Although there have been enhancements recently, I still tend to look at the server code directly. For more complex descriptions, it might be better to go with the documentation as it is more feature rich (like real tables, cross-links, chapters/sections, …).

OCS ist not necessarily more stable. It depends on how you communicate stuff to fellow devs. You can happily use OCS internally. REST endpoints (non-OCS) can be perfectly stable (see cookbook).

I would say, the documentation tells you already quite some stuff. This is intended if your app should share stuff to the public. This can be either completely anonymously (PublicShareControlelr) or with a password (AuthPublichShareController). This again defines the styling of the page (and the fact that the user should type password).

One shows plain data (binary data in PHP) and the other returns the content of a file in the NC instance.

The DownloadResponse is a helper class that you should not use. It renders no content to the client.

3 Likes