@@ 0,0 1,245 @@
+---
+title: 'LinkTaco API (GraphQL)'
+description: 'Using the LinkTaco API (GraphQL)'
+---
+
+LinkTaco offers an API for our services via [GraphQL](https://graphql.org).
+This page documents the traits our GraphQL API.
+
+# Attribution
+
+Our GraphQL setup is heavily based on the [SourceHut][srht] GraphQL services.
+As such this document is a modified version of the [original SourceHut
+document][srht og].
+
+[srht]: https://sourcehut.org "SourceHut"
+[srht og]: https://man.sr.ht/graphql.md "SourceHut GraphQL"
+
+# API Info
+
+The API is accessed via the location `https://api.linktaco.com`.
+
+All requests must be sent as a POST request the `/query` endpoint.
+
+# GraphQL playground
+
+LinkTaco offers a "playground" where you can run GraphQL queries to test
+and learn about the system. The canonical reference for each GraphQL schema is
+also available in the playground.
+
+**NOTICE**: The GraphQL playground is wired up to your *production* data. Any
+queries you perform will affect your real data!
+
+- [GraphQL Playground](https://linktaco.com/graphql)
+
+# Authentication strategies
+
+GraphQL authentication is based on OAuth 2.0 and is compatible with
+[RFC 6749][RFC 6749]. Detailed documentation on our OAuth 2.0 implementation is
+available in the [oauth documentation][oauth].
+
+[RFC 6749]: https://tools.ietf.org/html/rfc6749
+[oauth]: oauth.md
+
+In short, there are two primary modes of authentication:
+
+- Personal access tokens
+- OAuth Bearer tokens
+
+The former is suited to users who are writing their own scripts, CLI programs
+with no web component, and so on. Personal access tokens are available from
+[linktaco.com/oauth2/personal](https://linktaco.com/oauth2/personal).
+
+The latter is useful for third-parties who wish to provide a streamlined
+authentication process. You should first register for an OAuth 2.0 client at
+[linktaco.com/oauth2/clients](https://linktaco.com/oauth2/clients). For
+details, consult [RFC 6749][RFC 6749] and the [meta.sr.ht documentation][meta
+oauth].
+
+In either case, once a token is obtained, it is used by setting the
+`Authorization` header to `Bearer <token>`, e.g.
+`Authorization: Bearer AI+ym2EAAAAAAAAIc2lyY21wd26a8JLR48pyNs2ImxWYjgi9YVGxssyt5qk4YyV7BhHXAg`
+
+## Access scopes
+
+It is possible (and strongly encouraged) for the user to limit the scope of
+access that is provided by an authentication token. The access scopes supported
+by LinkTaco, and the required scopes to utilize each resolver, are
+documented in the [GraphQL schema][gql schema].
+
+[gql schema]: https://git.code.netlandish.com/~netlandish/links/tree/master/item/api/graph/schema.graphqls "GraphQL Schema"
+
+They can also be requested programmatically by fetching the following URL:
+
+https://api.linktaco.com/query/api-scopes.json
+
+The following scopes are available for use:
+
+- PROFILE
+- LINKS
+- LISTS
+- SHORTS
+- ORGS
+- DOMAINS
+- BILLING
+- ANALYTICS
+- QRCODES
+
+The access kind is either `RO` or `RW`; respectively referring to read-only or
+read/write access to that scope. If no access kind is provided with the scope
+the API will assume `RO` (read-only).
+
+Example: `PROFILE:RO LINKS:RW ANALYTICS:RO`
+
+More detailed information on using access scopes is available in the [OAuth2
+documentation][oauth].
+
+# Performing GraphQL Queries
+
+The GraphQL API accept queries at `/query`. To perform your query,
+submit a JSON payload to this endpoint as an HTTP POST request with the
+following schema:
+
+```json
+{
+ "query": "your GraphQL query...",
+ "variables": {
+ "foo": "bar"
+ }
+}
+```
+
+The `variables` field is optional, if your query requires no variables. A simple
+query which is supported on all APIs is:
+
+```json
+{
+ "query": "{ version { major, minor, patch } }"
+}
+```
+
+Your request shall have the `Content-Type` set to `application/json`.
+
+## Requesting with cURL
+
+Here is a simple request:
+
+```sh
+oauth_token=your oauth token
+curl \
+ --oauth2-bearer "$oauth_token" \
+ -H 'Content-Type: application/json' \
+ -d '{"query": "{ version { major, minor, patch } }"}' \
+ https://api.linktaco.com/query
+```
+
+Obtain a personal access token from
+[linktaco.com/oauth2/personal](https://linktaco.com/oauth2/personal). See
+[Authentication strategies](#authentication-strategies) for details.
+
+## Uploading files
+
+Some GraphQL resolvers accept file uploads, via the `Upload` type. Our
+implementation is compatible with the [GraphQL multipart request
+specification](https://github.com/jaydenseric/graphql-multipart-request-spec).
+
+# Query complexity limits
+
+To limit abuse, we calculate the complexity of your query before executing it,
+and apply an upper limit. As a general rule of thumb, the complexity is
+a function of how many resources your request implicates.
+
+Each field adds 1 to your complexity, unless it represents a relationship
+— in which case it is multiplied by the number of results you request.
+The total complexity of your request is capped to 200 by default.
+
+Additionally, the total time spent processing your request is capped to 3
+seconds by default, though more time is permitted for resolvers handling file
+uploads.
+
+## Cursors
+
+The number of results returned from a cursored resolver is limited to a certain
+cap, and is used to spread your work out over several requests. Consider this
+example:
+
+```
+query {
+ getFeed {
+ result {
+ title
+ url
+ description
+ author
+ orgSlug
+ createdOn
+ tags {
+ name
+ slug
+ }
+ pageInfo {
+ cursor
+ hasPrevPage
+ hasNextPage
+ }
+ }
+ }
+}
+```
+
+The `cursor` field returns an opaque string which can be used to return
+additional results, or `null` if there are none. The following request returns
+another page:
+
+```
+query GetFeed($after: Cursor, $before: Cursor) {
+ getFeed(input: {after: $after, before: $before}) {
+ result {
+ title
+ url
+ description
+ author
+ orgSlug
+ createdOn
+ tags {
+ name
+ slug
+ }
+ pageInfo {
+ cursor
+ hasPrevPage
+ hasNextPage
+ }
+ }
+ }
+}
+```
+
+You may perform repeated GraphQL queries to obtain all results. The default
+limit for results returned from a single request is 40. Some resolvers accept a
+`Limit` value on the specific "Input" parameter which allows you to request a
+different number of results — be aware of the complexity limits while
+tuning this number.
+
+# API stability guarantees
+
+The `version` resolver provides API versioning information which is compatible
+with [semantic versioning](https://semver.org). The *major* version increments
+when the API is changed in a backwards-incompatible way; *minor* when new
+features are added, and *patch* when bugs are fixed. Changes presumed to be
+backwards-compatible include:
+
+- Adding new types
+- Adding new resolvers
+- Adding new fields to existing types
+- Adding new members to enums
+- Adding new optional parameters to existing resolvers
+- Adding new optional fields to existing input types
+
+The special version `0.0.0` indicates an API which is still undergoing its
+initial design work, and provides no stability guarantees whatsoever.
+
+An additional field is provided by the `version` resolver: `deprecationDate`.
+The field, If not null, indicates the date at which a major
+version increment is planned. Interested parties may want to monitor this value
+and incorporate it into their planning.
@@ 12,6 12,11 @@ description: 'Documentation for the software and usage of LinkTaco'
- [Import / Export Data](import-export.md)
- [Custom Domains](custom-domains.md)
+# API / GraphQL
+
+- [OAuth 2 Implementation](oauth.md)
+- [GraphQL API](graphql.md)
+
# Technical / Development
* [How to Build](build.md)