Skip to main content

create-tutorial

Scaffold a new Membrane API Gateway tutorial in the api-gateway repo — the numbered self-teaching YAML under distribution/tutorials/<category>/, its support files and README links, and the matching auto-discovered integration test. Use whenever the user asks to create, add, write, or scaffold a tutorial (or a tutorial step), even if they only describe the gateway behavior they want to teach and don't say the word "skill" or name the files.

Quellinformationen

Repository
membrane/api-gateway
Letzte Quellaktivität
9. September 2026 um 10:53
Erkannte Sprache von SKILL.md
Englisch
Sterne
645
Forks
182

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
create-tutorial
description
Scaffold a new Membrane API Gateway tutorial in the api-gateway repo — the numbered self-teaching YAML under distribution/tutorials/<category>/, its support files and README links, and the matching auto-discovered integration test. Use whenever the user asks to create, add, write, or scaffold a tutorial (or a tutorial step), even if they only describe the gateway behavior they want to teach and don't say the word "skill" or name the files.
# Create a Tutorial In this repo a tutorial is usually a **runnable, self-teaching YAML config**. The leading comment block of the file is the lesson; the config below it is the working example the reader runs. A complete tutorial therefore has three parts, and they must stay in sync: 1. **The numbered YAML** in `distribution/tutorials/<category>/` — the lesson plus the config. 2. **Category support files** — `membrane.sh`, `membrane.cmd`, a `README.md` (and `run-docker.*` where the category offers Docker), so the reader can actually start it. 3. **An integration test** under `distribution/src/test/java/com/predic8/membrane/tutorials/…` so the tutorial can't silently rot. These tests unzip the built distribution and start Membrane against the tutorial's YAML, so a broken example fails CI. A tutorial step can also be a **plain `.md` file** — use this when the step needs no local Membrane config (e.g. a curl-only walkthrough against a hosted API). A `.md` step gets no integration test; it just lives alongside the numbered YAMLs and is linked from the README. Work through the steps below in order. The reader of a tutorial follows the file top-to-bottom with no other docs open, so the single most important thing is that the YAML teaches itself. ## Step 1 — Choose the category and filename Categories live under `distribution/tutorials/`: `getting-started`, `json`, `xml`, `advanced`, `transformation`, `security`, `jwt`, `api-keys`, `oauth2`, `soap`, `soap-rest-converter`, `wsdl-to-openapi`, `orchestration`, `sse`, `mcp`, `llm-gateway`. Pick the one that fits; only create a new category if nothing fits (see "New category" at the end). Files are numbered `NN-Title.yaml` (e.g. `10-PathParameters.yaml`). The number sets reading order. List the directory and pick the next gap — convention leaves room between numbers (10, 20, 30…) so steps can be inserted later. Match the existing `PascalCase`-with-hyphens title style. ## Step 2 — Write the YAML (the lesson lives here) Open a sibling file in the same category and mirror its shape. Every tutorial YAML has the same skeleton: ```yaml # yaml-language-server: $schema=https://www.membrane-api.io/v7.2.4.json # # Tutorial: <Human Readable Name> # # <One sentence on what this teaches.> # # 1.) Start Membrane: # ./membrane.sh -c NN-Title.yaml # # 2.) Call the API: # curl localhost:2000/... # # <Expected output — paste it verbatim.> # # 3.) Continue with file NN-Next.yaml # the next step in the chain, if any api: port: 2000 ... ``` Hold to these conventions — they're what makes the set feel like one coherent course: - **Pin the schema line** to whatever sibling files use (grep one: `grep -m1 schema= distribution/tutorials/<category>/*.yaml`). It tracks the current release version, so don't invent a number. - **Keep the comment block short.** Steps are a command and its expected output — nothing more. Don't explain what the config does; the reader can see the config. Don't repeat information the `name:` field already provides. - **No section-header comments** above each `api:` block. The `name:` field describes the API. - **Inline comments only for the non-obvious WHY** — a surprising built-in, a hidden constraint. Never comment what the interceptor name already says. - **Keep the config minimal and focused** on the one concept the step teaches. Tutorials favor clarity over completeness; richer setups belong under `distribution/examples/`. - **Port 2000** is the house convention for tutorial listeners unless the lesson needs more. - Use `return: status: 200` not `return: {}`. - If this file continues a chain, end the previous file's comment block with a "Continue with file NN-Title.yaml" pointer to the new one. ## Step 3 — Make the category runnable The reader runs `./membrane.sh -c <file>` from the category directory, so that directory needs the launcher scripts and a README. - If `membrane.sh` / `membrane.cmd` are missing from the category dir, copy them verbatim from a sibling category — they are identical generic launchers that walk up to find `MEMBRANE_HOME`. - Copy `run-docker.sh` / `run-docker.cmd` only if the category documents a Docker workflow. - **`README.md`**: the category README points at the first file in the chain ("open [NN-First.yaml](NN-First.yaml) and follow the instructions there"). If you added the first file of a new category, write this README modeled on a sibling's. ## Step 4 — Write the integration test (don't skip this) Without a test the example will drift out of sync with the code and break unnoticed — that's the whole reason these tests exist. The harness starts Membrane from the **built distribution** with your YAML and lets you assert against the live gateway. Test package mirrors the category but with **underscores**: dir `getting-started` → package `com.predic8.membrane.tutorials.getting_started`. The `ExampleTests` `@Suite` selects the whole `com.predic8.membrane.tutorials` package, so a test placed correctly is **auto-discovered — no registration needed.** Each category has an `Abstract<Category>TutorialTest` that fixes `getTutorialDir()` (this is where the hyphen dir name is restored). Your concrete test extends it, names the YAML, and asserts: ```java /* <copy the Apache 2.0 license header verbatim from a sibling test — keep its year> */ package com.predic8.membrane.tutorials.<category_with_underscores>; import org.junit.jupiter.api.Test; import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.containsString; public class <Name>TutorialTest extends Abstract<Category>TutorialTest { @Override protected String getTutorialYaml() { return "NN-Title.yaml"; } @Test void <whatItVerifies>() { // @formatter:off given() .when() .get("http://localhost:2000/...") .then() .statusCode(200) .body(containsString("...")); // @formatter:on } } ``` Notes: - Copy the license header from an existing sibling test rather than retyping it, so the year and wording match the repo. - Assert the **observable behavior the YAML comments promise** in Step 2 — if the lesson says "you should see Customer: 7", assert exactly that. The test is the executable form of the lesson. - If you created a brand-new category, also create its `Abstract<Category>TutorialTest` modeled on an existing one — it just returns the hyphenated dir name from `getTutorialDir()`. - **Sub-categories** (e.g. `llm-gateway/google`) need their own abstract base returning the full relative path (`llm-gateway/google`), not just the top-level category abstract. Model on `AbstractAiTutorialTest` / `AbstractGoogleTutorialTest` in `distribution/src/test/java/com/predic8/membrane/tutorials/`. - **`.md` steps** have no integration test — skip this step for them. ## Step 5 — Verify Run the test through the existing `run-example-test` skill. Pass `-b` so the distribution is rebuilt first: the tutorial YAML ships **inside** `distribution/target/*.zip`, and the tests run from the unzipped distribution, so an un-rebuilt run would test the old YAML (or none). ```bash .claude/skills/run-example-test/run-example-test.sh -b <Name>TutorialTest ``` A green run means the example actually starts and behaves as the lesson claims. ## Common pitfalls ### Template JSON auto-quoting When a `template` interceptor has `contentType: application/json`, the engine **automatically adds quotes** around every `${...}` interpolation. Writing `"${expr}"` produces `""value""` and breaks JSON. Always write interpolations **unquoted**: ```yaml - template: contentType: application/json src: | { "sub": ${user()}, "aud": "demo-resource" } ``` String literals that are not interpolated keep their quotes as normal. ### Built-in functions in Groovy templates Prefer the built-ins over raw property access: - `user()` — authenticated username (from `basicAuthentication` security scheme) - `scopes()` — list of granted scopes - `hasScope("read")` — boolean scope check Avoid the verbose `${property.'membrane.security.schemes'[0].username}` — use `${user()}` instead. ## New category (only when nothing fits) 1. `distribution/tutorials/<new-category>/` with the first `NN-*.yaml`, `membrane.sh`, `membrane.cmd`, and a `README.md`. 2. Add a section linking the new category in `distribution/tutorials/README.md`. 3. Create `com.predic8.membrane.tutorials.<new_category>.Abstract<NewCategory>TutorialTest` extending `AbstractMembraneTutorialTest`, returning the hyphenated dir from `getTutorialDir()`. 4. Add concrete tests as in Step 4. ## Checklist - [ ] `NN-Title.yaml` (or `.md` for curl-only steps) created with schema line, short numbered comment block, minimal config - [ ] Comment block: steps = command + expected output only; no prose repeating the config - [ ] No section-header comments above `api:` blocks; `name:` describes them - [ ] `return: status: 200` used (not `return: {}`) - [ ] Template interpolations unquoted when `contentType: application/json` - [ ] Previous file in the chain points to it ("Continue with…"), if applicable - [ ] Category has `membrane.sh`, `membrane.cmd`, `README.md` (and `run-docker.*` if used) - [ ] `<Name>TutorialTest` in the underscore package, extends the category abstract base, has the license header - [ ] Sub-category has its own abstract base returning the full relative path - [ ] `.md` steps have no integration test - [ ] Assertions match the behavior the YAML comments promise - [ ] `run-example-test.sh -b <Name>TutorialTest` is green
Auf GitHub ansehen