pages(),
blogPosts(), faqItems(), fetchskiMedia() and so on. A call is one line.
- The default site
- Another site
- Injected
Attract::blogPosts() reaches the site FETCHSKI_ATTRACT_SITE names.Arguments
Named and typed
listBlogs(perPage: 20, search: 'launch'). Your editor completes them.A body is arguments too
updateTestimonial(id: $id, quote: 'Great service', rating: 5): no model to build.null is not sent
A
PATCH changes only what you name, so nothing else is touched.Laravel's own values
Carbon or a string for a date, a PHP enum or its value,
$request->file() for a file.Answers
Answers are readonly objects with properties, never getters.What each type becomes
What each type becomes
A field the site always sends is non-nullable. Lists are
Collections. Date-times and Unix times are
CarbonImmutable. Nested objects are their own classes, under Fetchski\AttractCmsLaravel\Data.Enums stay open
Enums stay open
A known value is a PHP enum case; a value a newer site adds stays its string, so an older SDK never
breaks on it.
Answered, not required to write
Answered, not required to write
Some models are both an answer and a body. A field the site always sends (a testimonial’s
slug,
visibility, archived) is non-null when it answers, yet stays an optional argument when you write:
updateTestimonial(id: $id, quote: '…') leaves the others alone.Every answer is checked
Every answer is checked
Against its type, before your code sees it. A value of the wrong type is an error naming the field,
never coerced.
Whole lists, missing documents, jobs
…All()returns aLazyCollectionthat fetches a page at a time as you iterate: see Paging.find…()sits beside eachget…(): only a 404 becomesnull.- A job’s
wait()needs the job route, which only the management key reaches: on an API key it throwsSiteConfigurationErrornaming the job id.
What an API key reaches
- Content
- Feature routes
- Drafts and publishing
- Never
Every content type, with that type’s scopes:
content:<type>:read lists and reads the published
documents, :write creates and changes drafts (and reads them), :publish takes them live, and
:delete deletes. Pages, the media libraries and Site settings (global:*) included. Each
method’s reference page names its scope under Access; Required scopes lists them
all.Ids
A document’s id names its locale and mode:<document id>:<locale>:<mode>.
A create answers the id of its mode
Published by default (
…:en:published); aposMode: 'draft' makes only a draft (…:en:draft).Reads take either id
Or the bare document id.
Deleting takes the draft id
It removes both copies. The draft id is the published id with the last part changed.
Uploads
Pass the file the request brought, as it is. It goes under the name it was uploaded with, as the site reads a file’s type from its extension:uploadAttachment() needs the write scope of a media type (content:images:write,
content:files:write or content:videos:write).UploadedFile, a path or an SplFileObject all can; a
one-pass stream is sent unsigned, or refused when the key’s api_signing mode signs writes.
A signed upload signs its SHA-256. A multipart body isn’t signed byte for byte: the request declares the
hex SHA-256 of the exact body in
X-Fetchski-Content-SHA256 and signs that digest in the body’s place. The
site checks the signature before it reads the upload, then the bytes against the digest, and stores nothing
that doesn’t match. The SDKs do this for you; Signing requests shows it by hand.Timeouts
Slow routes set their own
Each FetchskiAI route, and the blog import with images, carries its own timeout: the site’s
600-second cap per AI call plus 15 seconds. You never pass one per call.
The larger one wins
The client’s timeout (15 seconds by default) covers every other route. Raise it, and every call gets
at least that long.
.env
A route without a method
Every route the site documents has a method, butrequest() calls any route exactly as the methods do:
the key, its signature, retries, the timeout and the same errors. It returns the decoded JSON.
Next: working with results
Ids, counts and the fields you want, in one line.