1
0
Fork 0

feat(markdown): Work on backend docs

This commit is contained in:
joostdecock 2022-11-19 18:10:35 +01:00
parent 6c2cb71f51
commit 4edfe29726
17 changed files with 1196 additions and 347 deletions

View file

@ -1,314 +0,0 @@
---
title: API Keys
---
Documentation for the REST API endpoints to create, read, or remove API keys.
<Tip>
The FreeSewing backend REST API supports authentication both with JSON Web
Tokens (JWT) as with API keys (KEY). This describes the endpoints that deal
with creating, reading, and removing API keys. For authentication details,
refer to [the section on authenticating to the
API](/reference/backend/api#authentication).
</Tip>
## Create a new API key
Create a new API key. The API key will belong to the user who is authenticated
when making the call. Supported for both JWT and KEY authentication.
<Note compact>
The response to this API call is the only time the secret will be
revealed.
</Note>
### Endpoints
| Method | Path | Description | Auth |
| ------ | ---- | ----------- | ---- |
| <Method post /> | `/apikey/jwt` | Create a new API key | _jwt_ |
| <Method post /> | `/apikey/key` | Create a new API key | _key_ |
### Parameters
<Tabs tabs="Request, Response">
<Tab>
| Where | Variable | Type | Description |
| ----- | ------------- | -------- | ----------- |
| _body_ | `name` | `string` | Create a new API key. Endpoint for JWT authentication |
| _body_ | `level` | `number` | A privilege level from 0 to 8. |
| _body_ | `expiresIn` | `number` | body | The number of seconds until this key expires. |
</Tab>
<Tab>
Returns HTTP status code <StatusCode status="201"/> on success, <StatusCode status="400"/> if
the request is malformed, and <StatusCode status="500"/> on server error.
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | `created` on success, and `error` on error |
| `apikey.key` | `string` | The API key |
| `apikey.secret` | `string` | The API secret |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
</Tab>
</Tabs>
### Example
<Tabs tabs="Request, Response">
<Tab>
```js
const apiKey = axios.post(
'https://backend.freesewing.org/apikey/jwt',
{
name: 'My first API key',
level: 2, // Read only
expiresIn: 3600, // One hour
},
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
</Tab>
<Tab>
```json
{
result: 'success',
apikey: {
key: '7ea12968-7758-40b6-8c73-75cc99be762b',
secret: '503d7adbdb3ec18ab27adfcd895d8b47a8d6bc8307d548500fbf9c05a5a8820e',
level: 3,
expiresAt: '2022-11-06T15:57:30.190Z',
name: 'My first API key',
userId: 61
}
}
```
</Tab>
</Tabs>
## Read an API key
Reads an existing API key. Note that the API secret can only be retrieved at
the moment the API key is created.
<Note compact>
You need the `admin` role to read API keys of other users
</Note>
### Endpoints
| Method | Path | Description | Auth |
| ------ | ---- | ----------- | ---- |
| <Method get /> | `/apikey/:id/jwt` | Reads an API key | _jwt_ |
| <Method get /> | `/apikey/:id/key` | Reads an API key | _key_ |
### Parameters
<Tabs tabs="Request, Response">
<Tab>
| Where | Variable | Type | Description |
| ----- | ----------- | -------- | ----------- |
| _url_ | `:id` | `string` | The `key` field of the API key |
</Tab>
<Tab>
Returns HTTP status code <StatusCode status="200"/> on success, <StatusCode status="400"/> if
the request is malformed, <StatusCode status="404"/> if the key is not found,
and <StatusCode status="500"/> on server error.
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | `success` on success, and `error` on error |
| `apikey.key` | `string` | The API key |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
</Tab>
</Tabs>
### Example
<Tabs tabs="Request, Response">
<Tab>
```js
const keyInfo = axios.get(
'https://backend.freesewing.org/apikey/7ea12968-7758-40b6-8c73-75cc99be762b/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
</Tab>
<Tab>
```json
{
result: 'success',
apikey: {
key: '7ea12968-7758-40b6-8c73-75cc99be762b',
level: 3,
expiresAt: '2022-11-06T15:57:30.190Z',
name: 'My first API key',
userId: 61
}
}
```
</Tab>
</Tabs>
## Read the current API key
Reads the API key with which the current request was authenticated.
### Endpoints
| Method | Path | Description | Auth |
| ------ | ---- | ----------- | ---- |
| <Method get /> | `/whoami/key` | Reads the current API key | _key_ |
### Parameters
<Tabs tabs="Request, Response">
<Tab>
<Note compact>This endpoint takes no parameters</Note>
</Tab>
<Tab>
Returns status code `200` on success, `400` on if the request is malformed,
`404` if the key is not found, and `500` on server error.
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | `success` on success, and `error` on error |
| `apikey.key` | `string` | The API key |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
</Tab>
</Tabs>
### Example
<Tabs tabs="Request, Response">
<Tab>
```js
const keyInfo = axios.get(
'https://backend.freesewing.org/whoami/key',
{
auth: {
username: apikey.key,
password: apikey.secret,
}
}
)
```
</Tab>
<Tab>
```json
{
result: 'success',
apikey: {
key: '7ea12968-7758-40b6-8c73-75cc99be762b',
level: 3,
expiresAt: '2022-11-06T15:57:30.190Z',
name: 'My first API key',
userId: 61
}
}
```
</Tab>
</Tabs>
## Remove an API key
Removes an existing API key.
<Note compact>
You need the `admin` role to remove API keys of other users
</Note>
### Endpoints
| Method | Path | Description | Auth |
| ------ | ---- | ----------- | ---- |
| <Method delete /> | `/apikey/:id/jwt` | Removes an API key | _jwt_ |
| <Method delete /> | `/apikey/:id/key` | Removes an API key | _key_ |
### Parameters
<Tabs tabs="Request, Response">
<Tab>
| Where | Variable | Type | Description |
| ----- | ----------- | -------- | ----------- |
| _url_ | `:id` | `string` | The `key` field of the API key |
</Tab>
<Tab>
Returns HTTP status code <StatusCode status="204"/> on success, <StatusCode status="400"/> if
the request is malformed, <StatusCode status="404"/> if the key is not found,
and <StatusCode status="500"/> on server error.
</Tab>
</Tabs>
### Example
<Tabs tabs="Request, Response">
<Tab>
```js
const keyInfo = axios.get(
'https://backend.freesewing.org/apikey/7ea12968-7758-40b6-8c73-75cc99be762b/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
</Tab>
<Tab>
<Note compact>Status code <StatusCode status="204"/> (no content) does not come with a body</Note>
</Tab>
</Tabs>
## Notes
The following is good to keep in mind when working with API keys:
### This is not the authentication documentation
The FreeSewing backend REST API supports authentication both with JSON Web
Tokens (JWT) as with API keys (KEY).
This describes the endpoints that deal with creating, reading, and removing API
keys. For authentication details, refer to [the section on authenticating to
the API](/reference/backend/api#authentication).
### API keys are immutable
Once created, API keys cannot be updated.
You should remove them and re-create a new one if you want to make change.
### API keys have an expiry
API keys have an expiry date. The maximum validity for an API key is 1 year.
### API keys have a permission level
API keys have a permission level. You can never create an API key with a higher
permission level than your own permission level.
### Circumstances that will trigger your API keys to be revoked
As a precaution, all your API keys will be revoked when:
- Your role is downgraded to a role with fewer privileges
- Your account is (b)locked
- You revoke your consent for FreeSewing to process your data
<Note>
This is not an exhaustive list. For example, if we find your use of our API to
be excessive, we might also revoke your API keys to shield us from the
financial impact of your use of our API.
</Note>

View file

@ -0,0 +1,97 @@
---
title: Create an API key
---
Creates a new API key. An API key can be used to authenticate against the
backend API.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to create an API key
## Endpoints
Creating a new API key is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method post /> | `/apikeys/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method post /> | `/apikeys/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request body
| Property | Type | Description |
| ----------: | :------- | :---------- |
| `name` | `string` | A name for the API key |
| `level` | `number` | A privilege level from 0 to 8. |
| `expiresIn` | `number` | The number of seconds until the API key expires |
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
<Warning>
##### Make sure to save the secret
The response body is the only time the API key's secret will be revealed.
</Warning>
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | Either `success` or `error` |
| `error` | `string` | Will give info on the nature of the error. Only set if an error occured. |
| `apikey.key` | `string` | The API key |
| `apikey.secret` | `string` | The API secret |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
## Example request
```js
const apiKey = axios.post(
'https://backend.freesewing.org/apikeys/jwt',
{
name: 'My first API key',
level: 2, // Read only
expiresIn: 3600, // One hour
},
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"apikey": {
"key": "7ea12968-7758-40b6-8c73-75cc99be762b",
"secret": "503d7adbdb3ec18ab27adfcd895d8b47a8d6bc8307d548500fbf9c05a5a8820e",
"level": 3,
"expiresAt": "2022-11-06T15:57:30.190Z",
"name": "My first API key",
"userId": 61
}
}
```

View file

@ -0,0 +1,58 @@
---
title: Delete an API key
---
Deletes an existing API key.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to delete an API key
## Endpoints
Deleting an API key is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method delete /> | `/apikeys/:id/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method delete /> | `/apikeys/:id/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the API key you wish to remove.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="204"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
## Example request
```js
await axios.delete(
'https://backend.freesewing.org/apikeys/7ea12968-7758-40b6-8c73-75cc99be762b/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```204.json
```
<Note>
These endpoints return status code <StatusCode status="204"/> (no content) on
success, with no response body.
</Note>

View file

@ -0,0 +1,53 @@
---
title: API Keys
---
API keys are a way to authenticate to the API with basic authentication.
They are intended to be used when interacting with the API in an automated
way such as from a script or a CI/CD pipeline.
They are an alternative to JSON Web Tokens (JWT) which is typically used
to authenticate users in a browser session.
The FreeSewing backend REST API supports authentication both with JSON Web
Tokens (JWT) as with API keys (KEY). This describes the endpoints that deal
with creating, reading, and removing API keys. For authentication details,
refer to [the section on
authenticating](/reference/backend/api#authentication).
## Endpoints
<ReadMore />
## Notes
The following is good to keep in mind when working with API keys:
### API keys are immutable
Once created, API keys cannot be updated.
You should remove them and re-create a new one if you want to make a change.
### API keys have an expiry
API keys have an expiry date. The maximum validity for an API key is 1 year.
### API keys have a permission level
API keys have a permission level. You can never create an API key with a higher
permission level than your own permission level.
### Circumstances that will trigger your API keys to be revoked
As a precaution, all your API keys will be revoked when:
- Your role is downgraded to a role with fewer privileges
- Your account is (b)locked
- You revoke your consent for FreeSewing to process your data
<Note>
This is not an exhaustive list. For example, if we find your use of our API to
be excessive, we might also revoke your API keys to shield us from the
financial impact of your use of our API.
</Note>

View file

@ -0,0 +1,81 @@
---
title: Read an API key
---
Reads an existing API key. Note that the API secret can only be retrieved at
the moment the API key is created.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to read an API key
## Endpoints
Reading an API key is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method get /> | `/apikeys/:id/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method get /> | `/apikeys/:id/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the API key you wish to remove.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="404"/> | API key not found |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | `success` on success, and `error` on error |
| `error` | `string` | Will give info on the nature of the error. Only set if an error occured. |
| `apikey.key` | `string` | The API key |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
## Example request
```js
const keyInfo = await axios.get(
'https://backend.freesewing.org/apikeys/7ea12968-7758-40b6-8c73-75cc99be762b/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"apikey": {
"key": "7ea12968-7758-40b6-8c73-75cc99be762b",
"level": 3,
"expiresAt": "2022-11-06T15:57:30.190Z",
"name": "My first API key",
"userId": 61
}
}
```

View file

@ -0,0 +1,73 @@
---
title: Read the current API key
---
Reads the current API key used to authenticate the request.
For obvious reasons, this endpoint is only available with API key authentication.
However, there's an equivalent endpoint for JWT authentication.
## Access control
- [Permission level](/reference/backend/api/rbac) `0` or higher is required to read the current API key
## Endpoints
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method get /> | `/whoami/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | `string` | `success` on success, and `error` on error |
| `error` | `string` | Will give info on the nature of the error. Only set if an error occured. |
| `apikey.key` | `string` | The API key |
| `apikey.level` | `number` | The privilege level of the API key |
| `apikey.expiresAt` | `string` | A string representation of the moment the API key expires |
| `apikey.name` | `string` | The name of the API key |
| `apikey.userId` | `number` | The ID of the user who created the API key |
## Example request
```js
const keyInfo = await axios.get(
'https://backend.freesewing.org/whoami/key',
{
auth: {
username: apikey.key,
password: apikey.secret,
}
}
)
```
## Example response
```200.json
{
"result": "success",
"apikey": {
"key": "7ea12968-7758-40b6-8c73-75cc99be762b",
"level": 3,
"expiresAt": "2022-11-06T15:57:30.190Z",
"name": "My first API key",
"userId": 61
}
}

View file

@ -0,0 +1,64 @@
---
title: Authentication
---
The FreeSewing backend API requires authentication for all but a handfull of
endpoints.
The API supports two different types of authentication:
| Type | Name | Description |
| ---- | ---- | ----------- |
| [JSON Web Tokens](#jwt-authentication) | `jwt` | This is typically used to authenticate humans in a browser session. |
| [API Keys](#key-authentication) | `key` | This is typically used to interact with the API in an automated way. Like in a script, a CI/CD context, a serverless runner, and so on. |
While the API supports both, they are not supported on the same endpoint.
Instead, add the authentication type you want to use as the final part of
endpoint:
- `/some/endpoint/jwt` : Authenticate with a JSON Web Token
- `/some/endpoint/key` : Authenticate with an API key and secret
## `jwt` authentication
The use of JSON Web Tokens ([jwt](https://jwt.io)) is typically used in a
browser context where we want to establish a *session*.
To get a token, you must first authenticate at the [`/login`](/reference/backend/api/user/login) endpoint.
You will receive a JSON Web Token (jwt) as part of the response.
In subsequent API calls, you must then include this token in the
`Authorization` header prefixed by `Bearer `. Like his:
```js
const account = await axios.get(
`https://backend.freesewing.org/account/jwt`,
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## `key` authentication
The combination of API key & secret serves as a username & password for [HTTP
basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).
<Note>
In basic authentication, the password is sent
unencrypted. To guard against this, this API should only be served over a
connection that is encrypted with TLS. (a url starting with `https://`).
</Note>
Sending a username and password with a request like this is supported
pretty much everywhere. In addition, there is no need to establish a session
first, so this make the entire transation stateless.
Below is an example using curl:
```sh
curl -u api-key-here:api-secret-here \
https://backend.freesewing.org/account/key
```

View file

@ -1,6 +1,5 @@
--- ---
title: Backend REST API title: REST API
linktitle: REST API
--- ---
This is the reference documentation for the FreeSewing backend REST API. This is the reference documentation for the FreeSewing backend REST API.

View file

@ -0,0 +1,110 @@
---
title: Clone a Pattern
---
Create a new Pattern by cloning an existing one.
## Access control
The [Permission level](/reference/backend/api/rbac) required to clone a
Pattern depends on:
- Whether the Pattern is `public`
- Who created the Pattern
The details are outlined in the table below:
| | Public Patterns | Non-Public Patterns |
| ---------------: | :-------------: | :-----------------: |
| **Your own** | `0` or higher | `4` or higher |
| **Other user's** | `0` or higher | `5` or higher |
## Endpoints
Creating a new API key is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method post /> | `/patterns/:id/clone/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method post /> | `/patterns/:id/clone/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the Pattern you wish to remove.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | String | Either `success` or `error` |
| `error` | String | Will give info on the nature of the error. Only set if an error occured. |
| `pattern.id` | Number | The ID of the Pattern |
| `pattern.createdAt` | String | Date string indicating the moment the pattern was created |
| `pattern.data` | Object | Any additional data that was stored with Pattern data |
| `pattern.design` | String | The name of the design of which this Pattern is an instance |
| `pattern.img` | String | The URL to the image stored with this Pattern |
| `pattern.name` | String | The name of the Pattern |
| `pattern.notes` | String | The notes stored with the Pattern |
| `pattern.personId` | Number | The ID of the Person for whom the Pattern was created |
| `pattern.public` | Boolean| Indicates whether the Pattern is publicly accessible or not |
| `pattern.settings` | Object | The settings used to (re-)create the Pattern |
| `pattern.userId` | Number | The ID of the user who created the Pattern |
| `pattern.updatedAt` | String | Date string indicating the last time the pattern was updated |
## Example request
```js
const apiKey = axios.post(
'https://backend.freesewing.org/patterns/10/clone/jwt',
null,
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"pattern": {
"id": 19,
"createdAt": "2022-11-19T16:29:33.346Z",
"data": {
"some": "value"
},
"design": "aaron",
"img": "https://cdn.sanity.io/images/hl5bw8cj/production/a1565c8c6c70cfe7ea0fdf5c65501cd885adbe78-200x187.png",
"name": "Just a test",
"notes": "These are my notes",
"personId": 17,
"public": true,
"settings": {
"sa": 5
},
"userId": 10,
"updatedAt": "2022-11-19T16:29:33.346Z"
}
}
```

View file

@ -0,0 +1,121 @@
---
title: Create a Pattern
---
Creates a new Pattern. This is typically used when users choose to save a pattern.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to create a Pattern
## Endpoints
Creating a new Pattern is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method post /> | `/patterns/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method post /> | `/patterns/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request body
The request body is a JSON object with the following properties:
| Property | Type | Description |
| ----------: | :------- | :---------- |
| `data` | `object` | Any additional data to store with the pattern |
| `design` | `string` | The name of the design this Pattern is an instance of |
| `img` | `object` | An image [data-uri][duri] to store with this Pattern |
| `name` | `string` | A name for the Pattern |
| `notes` | `string` | User notes for the pattern |
| `person` | `object` | The ID of the person to associate with this pattern |
| `settings` | `object` | The settings object to (re-)create the Pattern |
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | String | Either `success` or `error` |
| `error` | String | Will give info on the nature of the error. Only set if an error occured. |
| `pattern.id` | Number | The ID of the Pattern |
| `pattern.createdAt` | String | Date string indicating the moment the pattern was created |
| `pattern.data` | Object | Any additional data that was stored with Pattern data |
| `pattern.design` | String | The name of the design of which this Pattern is an instance |
| `pattern.img` | String | The URL to the image stored with this Pattern |
| `pattern.name` | String | The name of the Pattern |
| `pattern.notes` | String | The notes stored with the Pattern |
| `pattern.personId` | Number | The ID of the Person for whom the Pattern was created |
| `pattern.public` | Boolean| Indicates whether the Pattern is publicly accessible or not |
| `pattern.settings` | Object | The settings used to (re-)create the Pattern |
| `pattern.userId` | Number | The ID of the user who created the Pattern |
| `pattern.updatedAt` | String | Date string indicating the last time the pattern was updated |
## Example request
```js
const pattern = await axios.post(
'https://backend.freesewing.org/patterns/jwt',
{
data: {
some: 'value',
}
design: "aaron",
img: "data:image/png;base64,iVBORw0KGgoAAAANSUhEU...truncated",
name: "Just a test",
notes: "These are my notes",
person: 17,
public: true,
settings: {
sa: 5,
},
},
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"pattern": {
"id": 10,
"createdAt": "2022-11-19T16:29:33.346Z",
"data": {
"some": "value"
},
"design": "aaron",
"img": "https://cdn.sanity.io/images/hl5bw8cj/production/a1565c8c6c70cfe7ea0fdf5c65501cd885adbe78-200x187.png",
"name": "Just a test",
"notes": "These are my notes",
"personId": 17,
"public": true,
"settings": {
"sa": 5
},
"userId": 10,
"updatedAt": "2022-11-19T16:29:35.023Z"
}
}
```
[duri]: https://en.wikipedia.org/wiki/Data_URI_scheme

View file

@ -0,0 +1,59 @@
---
title: Delete a Pattern
---
Deletes an existing Pattern.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to delete a Pattern
- [Permission level](/reference/backend/api/rbac) `8` is required to delete **another user's** Pattern
## Endpoints
Deleting a Pattern is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method delete /> | `/patterns/:id/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method delete /> | `/patterns/:id/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the Pattern you wish to remove.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="204"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
## Example request
```js
await axios.delete(
'https://backend.freesewing.org/patterns/10/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```204.json
```
<Note>
These endpoints return status code <StatusCode status="204"/> (no content) on
success, with no response body.
</Note>

View file

@ -0,0 +1,34 @@
---
title: Patterns
---
Patterns hold information on and settings for a user's patterns.
## Endpoints
<ReadMore />
## Notes
### The `design` property should hold the design
The `design` property should hold the name of the FreeSewing design.
For example, `aaron`.
### The `notes` vs `data` properties
Both the `data` and `notes` properties can hold additional information about
the pattern.
Keep in mind that:
- The `notes` property is intended to be used by the user to add notes about
their pattern. It will only accept data of type `string`.
- The `data` property is intended to allow frontend developers to store
additional data about the pattern. It wil only accept data of type `object`.
### The `settings` property should hold the pattern settings
The `settings` property should hold [a settings object](/reference/settings)
that can be passed to [the Pattern
constructor](/reference/api/pattern#creating-a-pattern).

View file

@ -0,0 +1,109 @@
---
title: Read a Pattern
---
Reads an existing Pattern.
## Access control
The [Permission level](/reference/backend/api/rbac) required to read a
Pattern depends on:
- Whether the Pattern is `public`
- Who created the Pattern
The details are outlined in the table below:
| | Public Patterns | Non-Public Patterns |
| ---------------: | :-------------: | :-----------------: |
| **Your own** | `0` or higher | `4` or higher |
| **Other user's** | `0` or higher | `5` or higher |
## Endpoints
Reading a Pattern is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method get /> | `/patterns/:id/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method get /> | `/patterns/:id/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the Pattern you wish to read.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="404"/> | API key not found |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | String | Either `success` or `error` |
| `error` | String | Will give info on the nature of the error. Only set if an error occured. |
| `pattern.id` | Number | The ID of the Pattern |
| `pattern.createdAt` | String | Date string indicating the moment the pattern was created |
| `pattern.data` | Object | Any additional data that was stored with Pattern data |
| `pattern.design` | String | The name of the design of which this Pattern is an instance |
| `pattern.img` | String | The URL to the image stored with this Pattern |
| `pattern.name` | String | The name of the Pattern |
| `pattern.notes` | String | The notes stored with the Pattern |
| `pattern.personId` | Number | The ID of the Person for whom the Pattern was created |
| `pattern.public` | Boolean| Indicates whether the Pattern is publicly accessible or not |
| `pattern.settings` | Object | The settings used to (re-)create the Pattern |
| `pattern.userId` | Number | The ID of the user who created the Pattern |
| `pattern.updatedAt` | String | Date string indicating the last time the pattern was updated |
## Example request
```js
const pattern = await axios.get(
'https://backend.freesewing.org/patterns/10/jwt',
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"pattern": {
"id": 10,
"createdAt": "2022-11-19T16:29:33.346Z",
"data": {
"some": "value"
},
"design": "aaron",
"img": "https://cdn.sanity.io/images/hl5bw8cj/production/a1565c8c6c70cfe7ea0fdf5c65501cd885adbe78-200x187.png",
"name": "Just a test",
"notes": "These are my notes",
"personId": 17,
"public": true,
"settings": {
"sa": 5
},
"userId": 10,
"updatedAt": "2022-11-19T16:29:35.023Z"
}
}
```

View file

@ -0,0 +1,119 @@
---
title: Update a Pattern
---
Updates an existing Pattern.
This is typically used when users choose to save/overwrite a pattern.
## Access control
- [Permission level](/reference/backend/api/rbac) `4` or higher is required to update a Pattern
- [Permission level](/reference/backend/api/rbac) `8` is required to update **another user's** Pattern
## Endpoints
Updating an existing Pattern is possible via these endpoints:
| Method | Path | Authentication |
| --------: | :--- | :------------- |
| <Method put /> | `/patterns/:id/jwt` | [JSON Web Token](/reference/backend/api/authentication#jwt-authentication) |
| <Method put /> | `/patterns/:id/key` | [API Key & Secret](/reference/backend/api/authentication#key-authentication) |
## Request url
The url should contain the ID of the Pattern you wish to remove.
It replaces the `:id` placeholder in the [endpoints listed above](#endpoints).
## Request body
| Property | Type | Description |
| ----------: | :------- | :---------- |
| `data` | `object` | Any additional data to store with the pattern |
| `design` | `string` | The name of the design this Pattern is an instance of |
| `img` | `object` | An image [data-uri][duri] to store with this Pattern |
| `name` | `string` | A name for the Pattern |
| `notes` | `string` | User notes for the pattern |
| `person` | `object` | The ID of the person to associate with this pattern |
| `settings` | `object` | The settings object to (re-)create the Pattern |
## Response status codes
Possible status codes for these endpoints are:
| Status code | Description |
| ----------: | :---------- |
| <StatusCode status="200"/> | success |
| <StatusCode status="400"/> | the request was malformed |
| <StatusCode status="401"/> | the request lacks authentication |
| <StatusCode status="403"/> | authentication failed |
| <StatusCode status="500"/> | server error |
<Note>
If the status code is not <StatusCode status="200" /> the `error` property
in the response body should indicate the nature of the problem.
</Note>
## Response body
| Value | Type | Description |
| ------------------- | -------- | ----------- |
| `result` | String | Either `success` or `error` |
| `error` | String | Will give info on the nature of the error. Only set if an error occured. |
| `pattern.id` | Number | The ID of the Pattern |
| `pattern.createdAt` | String | Date string indicating the moment the pattern was created |
| `pattern.data` | Object | Any additional data that was stored with Pattern data |
| `pattern.design` | String | The name of the design of which this Pattern is an instance |
| `pattern.img` | String | The URL to the image stored with this Pattern |
| `pattern.name` | String | The name of the Pattern |
| `pattern.notes` | String | The notes stored with the Pattern |
| `pattern.personId` | Number | The ID of the Person for whom the Pattern was created |
| `pattern.public` | Boolean| Indicates whether the Pattern is publicly accessible or not |
| `pattern.settings` | Object | The settings used to (re-)create the Pattern |
| `pattern.userId` | Number | The ID of the user who created the Pattern |
| `pattern.updatedAt` | String | Date string indicating the last time the pattern was updated |
## Example request
```js
const udpate = await axios.put(
'https://backend.freesewing.org/patterns/10/jwt',
{
data: {
some: 'new value',
}
public: false,
},
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
```
## Example response
```200.json
{
"result": "success",
"pattern": {
"id": 10,
"createdAt": "2022-11-19T16:29:33.346Z",
"data": {
"some": "new value"
},
"design": "aaron",
"img": "https://cdn.sanity.io/images/hl5bw8cj/production/a1565c8c6c70cfe7ea0fdf5c65501cd885adbe78-200x187.png",
"name": "Just a test",
"notes": "These are my notes",
"personId": 17,
"public": false,
"settings": {
"sa": 5
},
"userId": 10,
"updatedAt": "2022-11-19T16:43:39.223Z"
}
}
```
[duri]: https://en.wikipedia.org/wiki/Data_URI_scheme

View file

@ -0,0 +1,42 @@
---
title: Access control
---
The backend API implements role-based access control (RBAC). Each
user has a role and that role determines what they can and cannot do.
## Roles vs levels
In practice, the different user roles map to a permission level between
`0` and `8`.
The available roles and their privilege levels are:
- **user**: `4`
- **bughunter**: `5`
- **support**: `6`
- **admin**: `8`
We offer more fine-grained control over the permission level when
authenticating with API keys. When you create an API key, you can choose any
permissing level that is equal or lower than your own role's permission level.
This allows you to -- for example -- generate an API key that only have read
access to your data.
## Permission levels
The table below lists the priviledge of all levels as well as their
corresponding <small><small><b>`role`</b></small></small>
| Level | Abilities | <small><small>`user`</small></small> | <small><small>`bughunter`</small></small> | <small><small>`support`</small></small> | <small><small>`admin`</small></small> |
| --: | -- | :--: | :--: | :--: | :--: |
| `0` | authenticate | ✅ | ✅ | ✅ | ✅ |
| `1` | **read** measurements and patterns | ✅ | ✅ | ✅ | ✅ |
| `2` | **read all** account data | ✅ | ✅ | ✅ | ✅ |
| `3` | **write** measurements or patterns | ✅ | ✅ | ✅ | ✅ |
| `4` | **write all** account data | ✅ | ✅ | ✅ | ✅ |
| `5` | **read** measurements or patterns of **other users** | ❌ | ✅ | ✅ | ✅ |
| `6` | **read all** account data of **other users** | ❌ | ❌ | ✅ | ✅ |
| `7` | **write** account data of **other users** through **specific support methods** | ❌ | ❌ | ✅ | ✅ |
| `8` | impersonate other users, **full write access** | ❌ | ❌ | ❌ | ✅ |

View file

@ -0,0 +1,167 @@
---
title: Database schema
---
The database schema for the backend is available in the [prisma.schema][prisma]
file in our monorepo. For your convenience, we're replicated the info below.
<Note>
In the tables below, the following symbols are used:
- 🔑 : Field holds the primary key
- 🗝️ : Field holds a foreign key
- ❄️ : Field must be unique
- ⚡ : Field is indexed
- 🔐 : Field is encrypted
- 🧂 : Field is salted & hashed
</Note>
## Table Apikey
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| | `createdAt` | DateTime | `now()` |
| | `expiresAt` | DateTime | |
| 🔑 | `id` | String (UUID) | `uuid()` |
| | `level` | Int | `0` |
| | `name` | String | |
| 🧂 | `secret` | String(ified JSON) | |
| 🗝️ | `userId` | Int | |
```json
{
"createdAt": 1668448465659,
"expiresAt": 1668448525632,
"id": "5122738c-2e44-4165-a9db-2f0b6ba4fbaf",
"level": 4,
"name": "Test API key",
"secret": "{\"type\":\"v3\",\"hash\":\"a88747549512991836332813ccc82abba652bf5835dfa0a5a8177e2ddacf1f2d0f6340a6c36c0e816cf7a9976847bb14010c658703d4fa1bc4a0f3bdf3f187c2\",\"salt\":\"9eba4d132010a534a54d76fa9a6083eb\"}",
"userId": 10
}
```
## Table Confirmation
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| | `createdAt` | DateTime | `now()` |
| 🔐 | `data` | String(ified JSON) | |
| 🔑 | `id` | String (UUID) | `uuid()` |
| | `type` | String | |
| 🗝️ | `userId` | Int | |
```json
{
"createdAt": 1668447926731,
"data": "{\"iv\":\"01a57e75817327cc99b08c5fabdf4c89\",\"ct\":\"03b89a100a67dd85898a313fd832c720700f4b3a800aa715a6bbbe66a4f2ab01f02215e995b0983b609ef8606912546fb27b63ea5436c5bbacd73cb9363024e8339d5f25899c3a7172b66991aed3e9a6c8dda850bea0d40c84f630f0f9f76b80052810639ee6f62a97ac9e45cab3c05abd768ff6ca22b8b4255993dc76023c948f80ee208e6455c28097402f63fe26afeab8d082e12bef760320ce3a5d2ea123\"}",
"id": "2319e09e-ffe0-4781-9add-46d73a57bb34",
"type": "signup",
"userId": 9
}
```
## Table Subscriber
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| | `createdAt` | DateTime | `now()` |
| 🔐 | `data` | String(ified JSON) | |
| ❄️ | `ehash` | String | |
| 🔐 | `email` | String(ified JSON) | |
| 🔑 | `id` | String (UUID) | `uuid()` |
| | `updatedAt` | DateTime | |
<Fixme>Include example</Fixme>
## Table User
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| 🔐 | `bio` | String(ified JSON) | |
| | `consent` | Int | |
| | `control` | Int | |
| | `createdAt` | DateTime | `now()` |
| ❄️ | `ehash` | String | |
| 🔐 | `email` | String(ified JSON) | |
| 🔐 | `github` | String(ified JSON) | |
| 🔑 | `id` | Int | |
| ⚡ | `ihash` | String | |
| 🔐 | `img` | String(ified JSON) | |
| | `imperial` | Boolean | `false` |
| 🔐 | `initial` | String(ified JSON) | |
| | `language` | String | `en` |
| | `lastLogin` | DateTime | |
| ❄️ | `lusername` | String | |
| | `newsletter`| Boolean | `false` |
| 🧂 | `password` | String(ified JSON) | |
| | `patron` | Int | `0` |
| | `role` | String | `user` |
| | `status` | Int | `0` |
| | `updatedAt` | DateTime | |
| | `username` | String | |
```json
{
"bio": "{\"iv\":\"92bc05493831ccd92c522a7c1395058d\",\"ct\":\"5a520bf84a1e194c87e294f1e28c6100\"}",
"consent": 1,
"control": 1,
"createdAt": 1668447881259,
"ehash": "57c20ec1135355d378145a994bc26ce1f1720e382474116cafbd5f4c3fb676c3",
"email": "{\"iv\":\"b48d8e4769e359cec69f53629c5ad4ce\",\"ct\":\"57211cdeb0c1d5641aae953b10058e8ad94604df8183a3f5c99517620858674696e1e988ccf8e527f132095c2f303a12\"}",
"github": "{\"iv\":\"42ab19245da9a4d35d5b5ea66c5897a9\",\"ct\":\"7b3b39bf1811e46e887d81222e99251d\"}",
"id": 7,
"ihash": "57c20ec1135355d378145a994bc26ce1f1720e382474116cafbd5f4c3fb676c3",
"img": "{\"iv\":\"2757b3674a4adb71a535d5d37e923469\",\"ct\":\"e80750ff6bfa7f8c1694558a73673c8714948d67425c5cf01848be8decd612ef8d3129b34c4140f665a5ad7919f32616\"}",
"imperial": 0,
"initial": "{\"iv\":\"b48d8e4769e359cec69f53629c5ad4ce\",\"ct\":\"57211cdeb0c1d5641aae953b10058e8ad94604df8183a3f5c99517620858674696e1e988ccf8e527f132095c2f303a12\"}",
"language": "en",
"lastLogin": 1668447881273,
"lusername": "user-7",
"newsletter": 0,
"password": "{\"type\":\"v3\",\"hash\":\"bc5b64b1932a5d4a053777011a61a244e07edfe78eaa52beb56d08bf0ec3f8d8946e8749c872db5a03d5720e53b8da1d6df3ee12d96443d107c01dd2392e2848\",\"salt\":\"648d1218a93ded40ad42cc5bed603bcf\"}",
"patron": 0,
"role": "user",
"status": 1,
"updatedAt": 1668447881274,
"username": "user-7"
}
```
## Table Pattern
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| 🔑 | `id` | Int | |
| | `createdAt` | DateTime | `now()` |
| 🔐 | `data` | String(ified JSON) | |
| | `design` | String | |
| 🔐 | `img` | String(ified JSON) | |
| 🔐 | `name` | String(ified JSON) | |
| 🔐 | `notes` | String(ified JSON) | |
| 🗝️ | `personId` | Int | |
| | `public` | Boolean | `false` |
| 🔐 | `settings` | String(ified JSON) | |
| 🗝️ | `userId` | Int | |
| | `updatedAt` | DateTime | |
<Fixme>Include example</Fixme>
## Table Person
| | Field | Type | Default |
| -: | :---------- | :------- | :------ |
| 🔑 | `id` | Int | |
| | `createdAt` | DateTime | `now()` |
| 🔐 | `img` | String(ified JSON) | |
| | `imperial` | Boolean | `false` |
| 🔐 | `measies` | String(ified JSON) | |
| 🔐 | `name` | String(ified JSON) | |
| 🔐 | `notes` | String(ified JSON) | |
| 🗝️ | `userId` | Int | |
| | `public` | Boolean | `false` |
| | `updatedAt` | DateTime | |
<Fixme>Include example</Fixme>
[prisma]: https://github.com/freesewing/freesewing/blob/develop/sites/backend/prisma/schema.prisma

View file

@ -1,5 +1,5 @@
--- ---
title: FreeSewing backend title: FreeSewing Backend
--- ---
The FreeSewing backend handles all user data. Prior to version 3 of FreeSewing, The FreeSewing backend handles all user data. Prior to version 3 of FreeSewing,
@ -14,37 +14,14 @@ environments and so on.
In other words, we no longer merely provide our own frontend, you can now also In other words, we no longer merely provide our own frontend, you can now also
use our backend as a service to build your own projects. use our backend as a service to build your own projects.
## Changes for developers ## Under the hood
We've made a number of changes to make it easier for external developers and The FreeSewing backend is written in [NodeJS](https://nodejs.org/en/) on top of
contributors to work with our backend. [Express](https://expressjs.com/). It uses [Prisma](https://www.prisma.io/) to
interface with a [Sqlite database](https://www.sqlite.org/) database,
### Authentication with JWT and API keys [Sanity](https://www.sanity.io/) to store images, [AWS SES](
https://aws.amazon.com/ses/) to send out emails, and
Before version 3, the backend only supported authentication via JSON Web [pino](https://github.com/pinojs/pino) for logging.
Tokens. That's fine for a browser session, but not very handy if you want to
talk to the API directly.
Since version 3, we support authentication with API keys. Furthermore, we
allow any FreeSewing user to generate their own API keys.
In other words, if you want to connect to our backend API, you don't need to
ask us. You can generate your own API key and start right away.
### Sqlite instead of MongoDB
Our backend used to use MongoDB for storage. Since version 3, we've moved to
Sqlite which is a file-based database making local development a breeze since
you don't need to run a local database server.
### Sanity instead of local storage
We now use Sanity and the Sanity API to stored images for users (avatars for
user accounts and people). Furthermore, we also generate PDFs in the browser
now so we also don't need storage for that.
As a result, our backend does not need any storage, only access to the Sqlite
file. This also makes it easier to work with the backend as a developer.
## Use, don't abuse ## Use, don't abuse