Services and Resources
Services and resources are the heart of Siesta.
Services
A Service
represents an API, that is, a set of related resources which tend to share common rules about request and response structure, authentication, and other conventions.
Create a single Service
instance for each API your app uses:
let myAPI = Service(baseURL: "https://api.example.com") // global var
You don’t necessarily need to make it a singleton as in this example, but don’t just instantiate Service
willy-nilly. Make sure there’s one instance that all the interested parties share. Much of the benefit of Siesta comes from the fact that all code using the same RESTful resource is working with the same object, and receives the same notifications. That happens within the context of one Service
instance.
Although it’s not strictly necessary, it can be pleasant to subclass Service
to add convenience accessors for commonly used resources:
class MyAPI: Service {
init() {
super.init(baseURL: "https://api.example.com")
}
var profile: Resource { return resource("/profile") }
var items: Resource { return resource("/items") }
func item(id: String) -> Resource {
return items.child(id)
}
}
let myAPI = MyAPI()
Note the use of computed properties instead of read-only (let
) properties. This lets the service discard resources not currently in use if memory gets low.
Getting Resources
A Resource
is a local cache of a RESTful resource. It holds a representation of the the resource’s data, plus information about the status of network requests related to it.
Retrieve resources from a service by providing paths relative to the service’s base URL:
myAPI.resource("/profile")
myAPI.resource("/items/123")
The leading slashes are optional, but help clarify.
You can navigate from a resource to a related resources:
// The following all return the same resource:
myAPI.resource("/items/123/detail")
myAPI.resource("/items").child("123").child("detail")
myAPI.resource("/items").child("123/detail")
myAPI.resource("/items").relative("./123/detail")
myAPI.resource("/items/456").relative("./123/detail")
myAPI.resource("/items/456/detail").relative("../123/detail")
myAPI.resource("/doodads/etc").relative("/items/123/detail")
The child(_:)
method appends path components, while relative(_:)
uses full relative URL resolution rules (like href
in a web page).
For more details, see the API docs for child(_:)
and relative(_:)
, and the related specs.
The Golden Rule of Resources
Within the context of a
Service
instance, at any given time there is at most oneResource
object for a given URL.
This is true no matter how you navigate to a resource, no matter whether you retain it or re-request it, no matter what — just as long as the resource came (directly or indirectly) from the same Service
instance.
Ephemerality
Note that the rule is “at most one.” If memory is low and no code references a particular resource, a service may choose to discard it and recreate it later if needed. This is transparent to client code; as long as you retain a reference to a resource, you will always keep getting only that reference. However, it does mean that resource objects are ephemeral, created and recreated on demand.
Uniqueness
Note that “URL” includes the whole URL: protocol, host, path, and query string. It does not include headers, however. Different query strings? Different resources. http
vs https
? Different resources. Different Authentication
headers? Same resource. This means it’s up to you to wipe resource content when a user logs out.
Next: Resource State