Een frontend bouwen voordat de API klaar is: zonder Brittle Fixtures (Nederlands (Dutch))

Een frontend bouwen voordat de API klaar is: zonder Brittle Fixtures

Saturday, 13 December 2025

//

15 minute read

Inleiding

Hoe vaak bent u geblokkeerd wachten tot backend API's klaar zijn? Of besteed uren met het onderhouden van broze spotgegevens die wordt oud het moment eisen veranderen?

Enter mostlylucid.mockllmapi - een production-ready ASP.NET Core mocking platform dat gebruik maakt van Large Language Models om realistische, contextueel bewuste API antwoorden te genereren op de vlieg. In plaats van het onderhouden van JSON armaturen, krijg je intelligente mocks die zich aanpassen aan uw verzoeken en onthouden staat over gesprekken.

Wat het ondersteunt: Elk protocol dat je nodig hebt - REST, GraphQL, gRPC, SignalR, Server-Sent Events, en OpenAPI. In tegenstelling tot statische armaturen, reacties worden dynamisch gegenereerd op basis van uw verzoek context, waardoor multi-stap workflows en complexe testscenario's triviaal.

NuGet NuGet GitHub release Licentie: Unlicense

Drie manieren om het te gebruiken

U kunt veelallucid.mockllmapi op drie manieren gebruiken, afhankelijk van hoe geïsoleerd u wilt dat uw dev-omgeving is:

  1. ASP.NET Core NuGet pakket - Toevoegen aan uw bestaande projecten
  2. Standalone CLI-tool - Cross-platform uitvoerbaar (downloaden van releases)
  3. Dockercontainer - Nul installatie vereist

The Killer Feature: Context Memory

Volledige gids: API Contexts Documentatie

Traditionele spot API's hebben een fatale fout: elk verzoek is onafhankelijk. Haal een gebruiker met ID 42, dan halen hun bestellingen, en je krijgt orders voor gebruiker ID 99. Geen consistentie.

API-contexten Los dit op met gedeeld geheugen over gerelateerde verzoeken:

// Request 1: Get a user
// Note: 'context' is a simple query parameter - no cookies or sessions needed
fetch('/api/users/123?context=checkout-session')
// Response: { id: 42, name: "Alice Smith", email: "[email protected]" }

// Request 2: Get orders (same context parameter)
fetch('/api/orders?userId=42&context=checkout-session')
// Response: { userId: 42, customerName: "Alice Smith", items: [...] }
// Perfect! Same user, consistent data

De LLM ziet eerdere verzoeken in dezelfde context en genereert consistente gegevens. Dit is de game-changer voor multi-step workflows.

Functies:

Levenscyclus:

  • Automatisch verlopen na 15 minuten inactiviteit (configureerbaar)
  • Elke aanvraag ververst de timer

Gedrag:

  • Intelligente extractie van ALLE velden uit reacties

Veiligheid:

  • Zero memory lekken - contexten reinigen zichzelf

Use Cases:

  • Perfect voor CI/CD - geen toestand tussen runs

Snel starten

Optie 1: Pakket NuGet

dotnet add package mostlylucid.mockllmapi
// Program.cs
builder.Services.AddLLMockApi(builder.Configuration);
app.MapLLMockApi("/api/mock");

Optie 2: CLI-gereedschap

# Download from https://github.com/scottgal/LLMApi/releases
llmock serve --port 5000

Optie 3: Docker

Volledige gids: Docker Implementatiegids

git clone https://github.com/scottgal/LLMApi.git
cd LLMApi
docker compose up -d

Vereisten: LLM Backend

Je hebt het nodig. één van: Ollama, OpenAI, of LM Studio:

# Recommended: Ollama with ministral-3:3b (ultra-fast, accurate JSON generation)
ollama pull ministral-3:3b

Zie Ollama Modellengids voor alle modelaanbevelingen en vergelijkingen.

Probeer het onmiddellijk

Eenmaal uitgevoerd, doe uw eerste verzoek:

curl http://localhost:5000/api/mock/users
# Response: [{"id": 1, "name": "Alice Johnson", "email": "[email protected]"}, ...]

Dat is het! Je hebt nu een werkende spot API die realistische data genereert op aanvraag.

Real Example: Zoeken op mostlylucid.net

Hier is de werkelijke zoekcode van deze blog - Dit is ongewijzigde productie frontend code, geen aanpassingen nodig voor de spot:

// typeahead.js from mostlylucid.net
export function typeahead() {
    return {
        query: '',
        results: [],
        search() {
            fetch(`/api/search/${encodeURIComponent(this.query)}`)
                .then(response => response.json())
                .then(data => { this.results = data; });
        }
    }
}

Mock it:

# Using CLI
llmock serve --port 5000

# Query returns contextual results
curl http://localhost:5000/api/search/markdown
# LLM generates blog posts about Markdown

curl http://localhost:5000/api/search/docker
# LLM generates blog posts about Docker

Elke reactie is uniek en realistisch, aan te passen aan de vraag.

Vormcontrole: Definieer uw schema

Naast het genereren van willekeurige gegevens, heb je vaak nauwkeurige controle over de JSON-structuur nodig. Met Shape control kun je de LLM precies vertellen welke structuur je moet genereren - de meest krachtige functie voor frontend ontwikkeling.

Basisvorm

# Without shape - random structure
curl http://localhost:5000/api/mock/users
# Response: { "userId": 1, "fullName": "Alice" }

# With shape - you control it
curl "http://localhost:5000/api/mock/users" \
  -H 'X-Response-Shape: {"id":0,"name":"string","email":"string"}'
# Response: { "id": 1, "name": "Alice", "email": "[email protected]" }

Drie manieren om vorm te specificeren:

  1. Zoekparameter - ?shape={...}
  2. HTTP-header - X-Response-Shape: {...} (aanbevolen)
  3. Verzoeksinstantie - {"shape": {...}}

Nested Shape

const shape = {
  company: {
    id: 0,
    name: "string",
    employees: [{
      id: 0,
      firstName: "string",
      department: { id: 0, name: "string" },
      projects: [{ id: 0, title: "string" }]
    }]
  }
};

fetch('/api/mock/company', {
  headers: { 'X-Response-Shape': JSON.stringify(shape) }
});

TypeScript-uitlijning

interface User {
  id: number;
  name: string;
  email: string;
}

const USER_SHAPE: Partial<User> = { id: 0, name: "", email: "" };

// Shape becomes your type definition AND mock schema!

Multi-stap workflows met Context

Laten we nu vormcontrole combineren met API-contexten om complexe, multi-step workflows te verwerken. Herinner je je de context geheugen functie van eerder? Hier is hoe het schijnt in real-world asynchrone operaties.

Dit voorbeeld van veelallucid.net's vertaaldienst laat zien hoe de LLM staat in een volledige async workflow:

# Step 1: Start translation
curl -X POST http://localhost:5000/api/translate/start?context=translate-session \
  -d '{"language": "es", "markdown": "# Hello World"}'
# Response: { "taskId": "abc-123", "status": "processing" }

# Step 2: Check status (LLM remembers the task)
curl http://localhost:5000/api/translate/status/abc-123?context=translate-session
# Response: { "taskId": "abc-123", "status": "complete" }

# Step 3: Get result (same taskId!)
curl http://localhost:5000/api/translate/result/abc-123?context=translate-session
# Response: { "taskId": "abc-123", "translatedText": "# Hola Mundo" }

Merk op hoe taskId is consistent over alle verzoeken. Context maakt dit mogelijk.

Voorbij REST: Alle protocollen

Tot nu toe hebben we ons gericht op REST, maar moderne toepassingen hebben meer nodig. Of u nu bouwt met GraphQL, het implementeren van real-time functies met SignalR, of werken met gRPC-services, meestallucid.mockllmapi heeft u behandeld.

Ondersteunde protocollen:

  • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    • GraphQL
  • GRPC (gRPC)
  • SignaalR
  • Server-verzonden gebeurtenissen (SSE)
  • OpenAPI / Swagger

GraphQL

Gids: GraphQL-sectie

curl -X POST http://localhost:5000/api/mock/graphql \
  -d '{"query": "{ users { id name email } }"}'

De query IS de vorm - geen aparte schema nodig.

gRPC

Volledige gids: gRPC-ondersteuning

# Upload .proto file
curl -X POST http://localhost:5116/api/grpc-protos \
  --data-binary "@user_service.proto"

# Call via JSON or binary Protobuf
curl -X POST http://localhost:5116/api/grpc/userservice/UserService/GetUser \
  -d '{"user_id": 123}'

SignalR Real-Time

Gids: SignalR Demo Guide

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/hub/mock")
    .build();

connection.on("DataUpdate", (message) => {
    console.log(message.data); // Live generated data
});

await connection.start();
await connection.invoke("SubscribeToContext", "stock-prices");

Perfect voor dashboard prototyping.

Server-verzonden gebeurtenissen (SSE)

Gids: SSE Streaming-modi

const eventSource = new EventSource('/api/mock/stream/users');
eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log('Token:', data.chunk); // Progressive generation
};

OpenAPI / Swagger

Volledige gids: OpenAPI-functies

# CLI: Load any OpenAPI spec
llmock serve --spec https://petstore3.swagger.io/api/v3/openapi.json

# All endpoints become live mocks automatically
curl http://localhost:5000/petstore/pet/123

Plugable Tools: Meng echte & Mock-gegevens

Volledige gids: Hulpmiddelen & acties

Soms heb je een hybride aanpak nodig - echte gegevens van de productie gecombineerd met gegenereerde spotgegevens. Met het pluggable tools systeem kun je echte API's bellen tijdens de mock-generatie, waarbij je ongelooflijk realistische testscenario's maakt.

{
  "Tools": [{
    "Name": "getUserData",
    "Type": "http",
    "HttpConfig": {
      "Endpoint": "https://api.production.com/users/{userId}",
      "Headers": { "Authorization": "Bearer ${PROD_API_KEY}" }
    }
  }]
}
curl "http://localhost:5000/api/mock/orders?useTool=getUserData&userId=123"

De mock haalt REAL gebruikersgegevens op, dan genereert de LLM bestellingen die deze gebruiken. Uiterst nuttig voor realistische testen met hybride mock/real workflows.

ASP.NET Kernintegratie

Als je bouwt met ASP.NET Core, integratie is naadloos. De schoonheid van deze aanpak is nulcodewijzigingen naar uw diensten - u gewoon configureren HttpClient te wijzen op de spot tijdens de ontwikkeling en op de echte API in de productie.

// Real code from mostlylucid.net
builder.Services.AddHttpClient<IMarkdownTranslatorService, MarkdownTranslatorService>(
    client => {
        var baseUrl = builder.Configuration["TranslationService:BaseUrl"]
            ?? "http://localhost:5000";  // Mock during dev
        client.BaseAddress = new Uri(baseUrl);
    }
);

appsettings.Development.json:

{
  "TranslationService": {
    "BaseUrl": "http://localhost:5000"  // Mock
  }
}

appsets.Productie.json:

{
  "TranslationService": {
    "BaseUrl": "https://api.production.com"  // Real
  }
}

Dit patroon werkt voor elke HttpClient in uw applicatie - vertaaldiensten, betaalgateways, externe API's, noem maar op.

Wanneer moet u dit gebruiken?

Voordat we duiken in geavanceerde functies, laten we duidelijk over wanneer deze tool zinvol is voor uw workflow.

Perfect voor:

  • Frontend-ontwikkeling voor backend bestaat - Stop met blokkeren van backend teams
  • Multi-stap workflow testen - Context geheugen behandelt complexe scenario's
  • API-prototyping - Experimenteren met responsvormen voordat u committen
  • Offline ontwikkeling - Werk zonder netwerk afhankelijkheden
  • Fout bij het testen van scenario's - Simuleer storingen zonder de productie te breken
  • CI/CD-pijpleidingen - Geen externe afhankelijkheden betekent snellere, betrouwbaarder builds

Niet ideaal voor:

  • Productieomgevingen - Dit is een ontwikkel- en testinstrument
  • Deterministische testgegevens - Gebruik armaturen wanneer u exacte reproduceerbaarheid nodig heeft
  • Testen van contracten - Altijd valideren tegen echte API's voor productiecontracten

Nu je weet waar het past, laten we de geavanceerde mogelijkheden verkennen.

Geavanceerde functies

Deze functies zijn optioneel - u kunt een enorme waarde krijgen van de basics alleen. Maar als je productie-grade realisme op schaal nodig hebt, deze tools zijn hier.

Meerdere LLM-backends

Gids: Meerdere LLM-backends

# Fast for dev
curl http://localhost:5000/api/mock/users

# High quality for demos
curl "http://localhost:5000/api/mock/users?backend=quality"

# Cloud AI for production-like
curl "http://localhost:5000/api/mock/users?backend=openai"

Reate limiting Simulatie

Gids: Berekenen van de limiet & Chargering

Test hoe uw app omgaat met tarieflimieten:

{
  "EnableRateLimiting": true,
  "RateLimitDelayRange": "500-2000"
}

Foutsimulatie

# Test 429 rate limiting
curl "http://localhost:5000/api/mock/users?error=429&errorMessage=Rate%20limit%20exceeded"

# Test 503 unavailable
curl "http://localhost:5000/api/mock/users?error=503"

Ondersteunt alle 4xx en 5xx codes.

Response Caching

# Generate and cache 10 variants
curl "http://localhost:5000/api/mock/users?shape={\"$cache\":10,\"id\":0,\"name\":\"string\"}"

Latere verzoeken krijgen direct gecached antwoorden.

Testhulpbronnen: meestal lucid.mockllmapi.test

Pakket: meestal lucid.mockllmapi.testing

Alle bovenstaande functies zijn geweldig voor ontwikkeling, maar hoe zit het met geautomatiseerde testen? De begeleider test pakket biedt een vloeiend API dat integratie testen een wind maakt - configureren mock gedrag declaratively en laat HttpClient Doe de rest.

Installatie

dotnet add package mostlylucid.mockllmapi.Testing

Basisgebruik

using mostlylucid.mockllmapi.Testing;

// Create a client with a single endpoint configuration
var client = HttpClientExtensions.CreateMockLlmClient(
    baseAddress: "http://localhost:5116",
    pathPattern: "/users",
    configure: endpoint => endpoint
        .WithShape(new { id = 0, name = "", email = "" })
        .WithCache(5)
);

// Make requests - configuration is automatically applied
var response = await client.GetAsync("/users");
var users = await response.Content.ReadFromJsonAsync<User[]>();

Meerdere eindpunten

var client = HttpClientExtensions.CreateMockLlmClient(
    "http://localhost:5116",
    configure: handler => handler
        .ForEndpoint("/users", config => config
            .WithShape(new { id = 0, name = "", email = "" })
            .WithCache(10))
        .ForEndpoint("/posts", config => config
            .WithShape(new { id = 0, title = "", content = "", authorId = 0 })
            .WithCache(20))
        .ForEndpoint("/error", config => config
            .WithError(404, "Resource not found"))
);

// Each endpoint automatically uses its configuration
var usersResponse = await client.GetAsync("/users");
var postsResponse = await client.GetAsync("/posts");
var errorResponse = await client.GetAsync("/error"); // Returns 404

Configuratie-opties

Vormconfiguratie:

// Using anonymous objects
.WithShape(new { id = 0, name = "", active = true })

// Using JSON strings
.WithShape("{ \"id\": 0, \"name\": \"\", \"tags\": [] }")

// Complex nested structures
.WithShape(new
{
    user = new { id = 0, name = "" },
    posts = new[] { new { id = 0, title = "" } }
})

Foutsimulatie:

// Simple error
.WithError(404)

// With custom message
.WithError(404, "User not found")

// With details
.WithError(422, "Validation failed", "Email address is invalid")

Streaming:

// Enable streaming with token-by-token output
.WithStreaming()
.WithSseMode("LlmTokens")

// Stream complete objects
.WithStreaming()
.WithSseMode("CompleteObjects")

// Stream array items individually
.WithStreaming()
.WithSseMode("ArrayItems")

Afhankelijkheidsinjectie

Getypte client:

services.AddMockLlmHttpClient<IUserApiClient>(
    baseApiPath: "/api/mock",
    configure: handler => handler
        .ForEndpoint("/users", config => config
            .WithShape(new { id = 0, name = "", email = "" }))
);

Genoemde client:

services.AddMockLlmHttpClient(
    name: "MockApi",
    baseApiPath: "/api/mock",
    configure: handler => handler
        .ForEndpoint("/data", config => config
            .WithShape(new { value = 0 }))
);

// Usage
var client = httpClientFactory.CreateClient("MockApi");

Voorbeeld van integratietest

[Fact]
public async Task Should_Handle_User_Creation()
{
    // Arrange
    var client = HttpClientExtensions.CreateMockLlmClient(
        "http://localhost:5116",
        "/users",
        config => config
            .WithMethod("POST")
            .WithShape(new { id = 0, name = "", email = "", createdAt = "" })
    );

    // Act
    var newUser = new { name = "John Doe", email = "[email protected]" };
    var response = await client.PostAsJsonAsync("/users", newUser);

    // Assert
    response.EnsureSuccessStatusCode();
    var created = await response.Content.ReadFromJsonAsync<User>();
    Assert.NotNull(created);
    Assert.NotEqual(0, created.Id);
}

[Fact]
public async Task Should_Handle_Not_Found_Error()
{
    // Arrange
    var client = HttpClientExtensions.CreateMockLlmClient(
        "http://localhost:5116",
        "/users/999",
        config => config.WithError(404, "User not found")
    );

    // Act
    var response = await client.GetAsync("/users/999");

    // Assert
    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

Hoe het werkt

De MockLlmHttpHandler is a DelegatingHandler dat:

  1. Onderbreekt uitgaande HTTP-verzoeken
  2. Komt overeen met verzoeken tegen geconfigureerde eindpunt patronen
  3. Injecteert mock-configuratie via queryparameters en HTTP-headers
  4. Stuurt het gewijzigde verzoek door naar de eigenlijke LLM API

Dit stelt u in staat om een echte HttpClient in uw testen terwijl het gemakkelijk controleren van bespot API gedrag zonder het wijzigen van uw toepassingscode.

Beste praktijken & tips

Na het werken met deze tool over meerdere projecten, hier zijn de patronen die het beste werken:

  1. Gebruik altijd contexten voor workflows - Zorgt voor consistente ID's en gegevens over meerdere stappen
  2. Gebruiksvorm voor typeveiligheid - Laat het overeenkomen met uw TypeScript interfaces
  3. Meng echte en bespotte gegevens met tools - Het beste van beide werelden.
  4. Kies het juiste model (zie Ollama Modellengids voor volledige details:
    • AANGEVOEGD VOOR DEV: ministral-3:3b (3B params, 32K context) - Moordenaar voor Json! Ultrasnelle, zeer nauwkeurige, minimale RAM
    • Productieachtig: llama3 (8B params, 8K context) - Beste balans van kwaliteit en prestaties
    • Hoge kwaliteit: mistral-nemo (12B params, 128K context) - Complexe schema's en enorme datasets
    • Hulpbron-beperkt: gemma3:4b of phi3 - Lichtere alternatieven

Volledige documentatie

Conclusie

Frontend ontwikkeling hoeft niet te wachten op backend API's. mostlylucid.mockllmapi geeft u:

  • Contextgeheugen - Consistente, stateful data over multi-step workflows
  • Vormregeling - Nauwkeurige schema definities die overeenkomen met uw types
  • Universele protocolondersteuning - REST, GraphQL, gRPC, SignalR, SSE, OpenAPI
  • Hybride tests - Meng echte productiegegevens met gegenereerde spots
  • Nul onderhoud - Geen JSON-armaturen om bij te werken wanneer de vereisten veranderen
  • Testprogramma's - Vloeiende API voor integratietests

Het verschil tussen dit en traditionele bespotting? Uw frontend werkt tegen realistische, contextueel bewuste data vanaf de eerste dag. Geen "het werkte met spotgegevens maar mislukte met echte data" verrassingen.

Of u nu een eenvoudige blog of een complexe enterprise applicatie bouwt, u zult sneller itereren, grondiger testen en met vertrouwen verzenden.

Klaar om te beginnen?

docker compose up -d

Geen backend nodig.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.