Skip to content
This repository was archived by the owner on Feb 9, 2026. It is now read-only.

Commit 0ab10cf

Browse files
add CREATE_WS_TOKEN.md for ws token creation instructions, update README.md to reference new document, and implement getDomainUrl function in server for dynamic domain handling
1 parent 3bd9d8a commit 0ab10cf

5 files changed

Lines changed: 77 additions & 5 deletions

File tree

CREATE_WS_TOKEN.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## How to create a ws token
2+
3+
First you need to be an admin and create an external service. name it `openapi-server`. only allow certain authenticated users to create ws tokens.
4+
5+
![](https://share.cleanshot.com/XnVxtRhT+)
6+
7+
then you need to choose the authenticated users.
8+
9+
![](https://share.cleanshot.com/Q589YH5X+)
10+
11+
then you need to add allowed functions to the external service.
12+
13+
![](https://share.cleanshot.com/4Zl6v0wz+)
14+
15+
Then you need to create a ws token for the external service. you should turn off the `valid until` option.
16+
17+
![](https://share.cleanshot.com/GR1DMQDB+)

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ USERS=admin:admin,teacher:teacher
4242

4343
you should start your local moodle server before running the test.
4444

45-
you can also connect to a remote moodle server by setting the `MOODLE_BASE_URL` and `MOODLE_WSTOKEN` environment variables.
45+
you can also connect to a remote moodle server by setting the `MOODLE_BASE_URL` environment variables.
46+
47+
> [!NOTE]
48+
> you need to create a ws token for the external service. see [CREATE_WS_TOKEN.md](./CREATE_WS_TOKEN.md) for more details.
49+
> However, you don't need to set the `MOODLE_WSTOKEN` environment variable to run the docker image.
4650
4751
```bash
4852
git pull
@@ -58,21 +62,19 @@ pnpm run build:docker
5862
# run the docker image
5963
docker run \
6064
-e MOODLE_BASE_URL=https://your.moodle.url \
61-
-e MOODLE_WSTOKEN=yourtoken \
6265
-e USERS=admin:admin,teacher:teacher \
6366
-p 3000:3000 \
6467
moodle-openapi-server
6568
```
6669

6770
for example
6871

72+
6973
```
7074
docker run \
7175
-e MOODLE_BASE_URL=https://learn.twu.ca \
72-
-e MOODLE_WSTOKEN=0aa2a744e8ccb6c0a9453f432d3659dc \
7376
-e USERS=admin:admin,teacher:teacher \
7477
-p 3000:3000 \
75-
-p 6277:6277 \
7678
moodle-openapi-server
7779
```
7880

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "moodle-openapi-server",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "Moddle OpenAPI server",
55
"private": true,
66
"type": "module",

src/get-domain-url.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* get the domain url from the request
3+
*/
4+
export function getDomainUrl(
5+
request: Request,
6+
options?: {
7+
/**
8+
* base on the env, you can provide different default host
9+
*/
10+
defaultHost?: string;
11+
/**
12+
* if the host is localhost, by default it will be http, you can override it here
13+
*/
14+
protocol?: string;
15+
},
16+
) {
17+
const host =
18+
request.headers.get("X-Forwarded-Host") ??
19+
request.headers.get("Host") ??
20+
options?.defaultHost;
21+
22+
if (!host) {
23+
throw new Error("Host is required");
24+
}
25+
26+
const protocol =
27+
options?.protocol ?? (host.includes("localhost") ? "http" : "https");
28+
29+
return `${protocol}://${host}`;
30+
}

src/server.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import { HTTPException } from "hono/http-exception";
1414
import { basicAuth } from "hono/basic-auth";
1515
import { parseUsers } from "./parse-users";
1616
import { html } from "hono/html";
17+
import { getDomainUrl } from "./get-domain-url";
1718

1819
type Variables = {
1920
moodleServer: MoodleServer;
21+
domainUrl: string;
2022
};
2123

2224
const baseURL = process.env.MOODLE_BASE_URL;
@@ -62,6 +64,14 @@ const app = new Hono<{ Variables: Variables }>();
6264
app.use(cors());
6365
app.use(logger());
6466

67+
app.use(async (c, next) => {
68+
const domainUrl = getDomainUrl(c.req.raw, {
69+
defaultHost: "localhost:3000",
70+
});
71+
c.set("domainUrl", domainUrl);
72+
await next();
73+
});
74+
6575
// Apply middleware to all /api routes
6676
app.use("/api/*", moodleAuth);
6777

@@ -200,23 +210,36 @@ app.get("/meta", async (c) => {
200210
// swagger 2.0 docs
201211
app.get("/docs/swagger/:id", (c) => {
202212
const id = c.req.param("id");
213+
const domainUrl = c.get("domainUrl");
203214
const swaggerDocs = swagger2.filter(Boolean);
204215
const doc = swaggerDocs[Number(id)];
205216
if (!doc) {
206217
return c.json({ error: true, message: "Invalid id" }, { status: 400 });
207218
}
219+
// we need to update the basePath in the swagger doc
220+
doc.host = domainUrl;
221+
208222
return c.json(doc, { status: 200 });
209223
});
210224

211225
app.get("/docs/openapi_3_1/:id{.+\\.json}", (c) => {
212226
const id = c.req.param("id");
227+
const domainUrl = c.get("domainUrl");
213228
// remove the .json from the id
214229
const idWithoutJson = id.replace(".json", "");
215230
const openapi31Docs = [openapi31, usecaseOpenapi].filter(Boolean);
216231
const doc = openapi31Docs[Number(idWithoutJson)];
217232
if (!doc) {
218233
return c.json({ error: true, message: "Invalid id" }, { status: 400 });
219234
}
235+
236+
// we need to update the servers in the openapi doc
237+
doc.servers = [
238+
{
239+
url: `${domainUrl}/api`,
240+
description: "Moodle webservice API",
241+
},
242+
];
220243
return c.json(doc, { status: 200 });
221244
});
222245

0 commit comments

Comments
 (0)