Bygga ett gränssnitt innan API:et är klart: Utan Brittle Fixtures (Svenska (Swedish))

Bygga ett gränssnitt innan API:et är klart: Utan Brittle Fixtures

Saturday, 13 December 2025

//

14 minute read

Inledning

Hur många gånger har du blockerats i väntan på att backend API:er ska vara redo? Eller spenderat timmar med att underhålla spröda mock data som blir gamla momentet krav förändras?

Ange mostlylucid.mockllmapi - en produktionsklar ASP.NET Core mocking plattform som använder stora språkmodeller för att generera realistiska, kontextuellt medvetna API-svar i farten. Istället för att underhålla JSON fixturer, får du intelligenta mocks som anpassar sig till dina önskemål och komma ihåg tillstånd över samtal.

Vad den stöder: Varje protokoll du behöver - REST, GraphQL, gRPC, SignalR, Server-Sent Händelser, och OpenAPI. Till skillnad från statiska fixturer genereras svar dynamiskt baserat på din begäran sammanhang, vilket gör flera steg arbetsflöden och komplexa testscenarier triviala.

Projektlänkar

Hämta Hämta Släpp GitHub Licens: Olicensierad

Tre sätt att använda den

Du kan använda mestadels lucid.mockllmapi på tre sätt, beroende på hur isolerad du vill att din dev miljö ska vara:

  1. Paketet ASP.NET Core NuGet - Lägg till i dina befintliga projekt
  2. Fristående CLI-verktyg - Plattformsoberoende körbar (nedladdning från utsläpp)
  3. Dockningsbehållare - Noll installation krävs

Mördarfunktionen: Sammanhangsminne

Fullständig vägledning: Dokumentation av API- sammanhang

Traditionella prototyp API:er har en dödlig brist: varje begäran är oberoende. Få en användare med ID 42, sedan hämta sina beställningar, och du får beställningar för användar-ID 99. Ingen konsekvens.

API- sammanhang lösa detta med delat minne över relaterade förfrågningar:

// 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

LLM ser tidigare förfrågningar i samma sammanhang och genererar konsekventa uppgifter. Detta är spelväxlaren för arbetsflöden i flera steg.

Kännetecken:

Livscykel:

  • Automatisk utgång efter 15 minuters inaktivitet (konfigurerbar)
  • Varje begäran uppdaterar timern

Beteende:

  • Intelligent utvinning av ALLA fält från svar

Säkerhet:

  • Noll minnesläckage - sammanhang städa upp

Användningsfall:

  • Perfekt för CI/CD - inget tillstånd mellan körningar

Snabbstart

Alternativ 1: NuGet-paket

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

Alternativ 2: CLI-verktyg

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

Alternativ 3: Docker

Fullständig vägledning: Handbok för dockning

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

Förkunskapskrav: LLM- gränssnitt

Du behöver ett av: Ollama, OpenAI eller LM Studio:

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

Se också Ollama Modellguide för alla modellrekommendationer och jämförelser.

Försök genast

När du kör, gör din första begäran:

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

Nu har du en fungerande modell API som genererar realistiska data på begäran.

Verkligt exempel: Sök från mestadels lucid.net

Här är den faktiska sökkoden från den här bloggen - Detta är oförändrat produktionsgränssnittskod, inga anpassningar som behövs för hånet:

// 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; });
        }
    }
}

Lägg av.

# 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

Varje svar är unikt och realistiskt, anpassa sig till frågan.

Formkontroll: Definiera ditt schema

Förutom att bara generera slumpmässiga data, du behöver ofta exakt kontroll över JSON struktur. Formkontroll kan du berätta LLM exakt vilken struktur att generera - den mest kraftfulla funktionen för frontend utveckling.

Grundläggande form

# 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]" }

Tre sätt att ange form:

  1. Fråga parameter - ?shape={...}
  2. HTTP- huvud - X-Response-Shape: {...} (rekommenderas)
  3. Begärande organ {"shape": {...}}

Inhägnad form

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) }
});

Inställning av typskript

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!

Flerstegsarbetsflöden med sammanhang

Nu kombinerar vi formkontroll med API-kontexter för att hantera komplexa arbetsflöden i flera steg. Kom ihåg den sammanhangsbaserade minnesfunktionen från tidigare? Så här skiner den i asynkrona operationer i verkligheten.

Detta exempel från mestadelslucid.net översättningstjänst visar hur LLM upprätthåller tillstånd över ett komplett async arbetsflöde:

# 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" }

Lägg märke till hur taskId är konsekvent över alla förfrågningar. Sammanhang gör detta möjligt.

Bortom REST: Alla protokoll

Hittills har vi fokuserat på REST, men moderna applikationer behöver mer. Oavsett om du bygger med GraphQL, implementera realtidsfunktioner med SignalR, eller arbeta med gRPC-tjänster, mestadels lucid.mockllmapi har du täckt.

Protokoll som stöds:

  • TIDSFRÄMJANDE VERKSAMHET
  • (se figur 1 i denna bilaga)
  • på gRPC-nivå,
  • till SignalR
  • på Server-Sent-händelser (SSE)
  • på OpenAPI / Swagger

DiagramQL

Handbok: DiagramQL-avsnitt

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

Frågan är formen - inget separat schema behövs.

gRPC

Fullständig vägledning: Stöd för gRPC

# 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 i realtid

Handbok: SignalR- demoguide

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");

Perfekt för prototypning av instrumentbrädan.

Server-Sent-händelser (SSE)

Handbok: SSE Strömmande lägen

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

Fullständig vägledning: OpenAPI- funktioner

# 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

Pluggerbara verktyg: Blanda Real & Mock data

Fullständig vägledning: Verktyg och åtgärder

Ibland behöver du en hybrid metod - verkliga data från produktion i kombination med genererade prototypdata. Det pluggable verktygssystemet kan du kalla faktiska API:er under prototypgenerering, skapa otroligt realistiska testscenarier.

{
  "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"

Den mock hämtar REAL användardata, sedan LLM genererar order med hjälp av den. Extremt användbart för realistiska tester med hybrida mock/reala arbetsflöden.

ASP.NET:s kärnintegration

Om du bygger med ASP.NET Core, integration är sömlös. Skönheten i detta tillvägagångssätt är Nollkodsändringar till dina tjänster - du konfigurerar helt enkelt HttpClient att peka på hånet under utvecklingen och på det verkliga API i produktionen.

// 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);
    }
);

Tillämpningar.Utveckling.json:

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

appsettings.Production.json:

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

Detta mönster fungerar för alla HttpClient i din ansökan - översättningstjänster, betalningsgateways, externa API:er, du namnger det.

När du ska använda detta

Innan vi dyker in i avancerade funktioner, låt oss vara tydliga om när detta verktyg är vettigt för ditt arbetsflöde.

Perfekt för:

  • Utveckling av gränssnittet innan gränssnittet finns - Sluta blockera backend-team
  • Test av arbetsflöde i flera steg - Sammanhangsminne hanterar komplexa scenarier
  • Prototypning av API - Experimentera med responsformer innan du begår
  • Utveckling offline - Arbeta utan nätverksberoenden
  • Feltest av scenario - Simulera fel utan att bryta produktionen
  • Rörledningar för CI/CD - Inga externa beroenden innebär snabbare, mer tillförlitliga byggen

Inte idealisk för:

  • Produktionsmiljöer - Detta är ett utvecklings- och testverktyg
  • Deterministiska testdata - Använd fixturer när du behöver exakt reproducerbarhet
  • Avtalsprövning - Alltid validera mot verkliga API:er för produktionskontrakt

Nu när du vet var den passar, låt oss utforska de avancerade förmågorna.

Avancerade funktioner

Dessa funktioner är valfria - du kan få enormt värde enbart från grunderna. Men när du behöver produktionsgrad realism i skala, dessa verktyg är här.

Flera LLM- gränssnitt

Handbok: Flera LLM- gränssnitt

# 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"

Hastighetsbegränsningssimulering

Handbok: Gradera begränsning och spärrning

Testa hur din app hanterar hastighetsgränser:

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

Felsimulering

# 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"

Stöder alla 4xx och 5xx koder.

Caching för svar

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

Efterföljande förfrågningar får omedelbart cachade svar.

Testverktyg: mestadels lucid.mockllmapi.Testning

Paketet: mest lucid.mockllmapi.Testning

Alla funktioner ovan är bra för utveckling, men hur om automatiserad testning? Den följeslagare testning paket ger en flytande API som gör integration tester en bris - konfigurera hån beteende deklarativt och låt HttpClient Gör resten.

Anläggning

dotnet add package mostlylucid.mockllmapi.Testing

Grundläggande användning

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[]>();

Flera slutpunkter

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

Inställningsalternativ

Inställning av form:

// 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 = "" } }
})

Felsimulering:

// Simple error
.WithError(404)

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

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

Strömma:

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

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

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

Beroende injektion

Skriven klient:

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

Namngiven klient:

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

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

Exempel på integrationstest

[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);
}

Hur den fungerar

och MockLlmHttpHandler är en DelegatingHandler där

  1. Avbryter utgående HTTP- förfrågningar
  2. Matchar förfrågningar mot inställda endpoint-mönster
  3. Injicerar mock-konfiguration via frågeparametrar och HTTP-huvuden
  4. Vidarebefordrar den ändrade begäran till den faktiska mock LLM API

Detta gör att du kan använda en riktig HttpClient i dina tester samtidigt lätt kontrollera mock API beteende utan att ändra din programkod.

Bästa praxis och tips

Efter att ha arbetat med detta verktyg över flera projekt, här är de mönster som fungerar bäst:

  1. Använd alltid sammanhang för arbetsflöden - Säkerställer konsekventa ID och data i flera steg
  2. Använd form för typsäkerhet - Få det att matcha dina TypeScript-gränssnitt
  3. Blanda verkliga och mock data med verktyg - Bäst av båda världarna
  4. Välj rätt modell (se Ollama Modellguide För fullständiga uppgifter:
    • REKOMMENDATIONER FÖR DEV: ministral-3:3b (3B-paramer, 32K-sammanhang) KILLER för JSON! Ultrasnabbt, mycket exakt, minimalt RAM-minne
    • Tillverkning likformigt: llama3 (8B params, 8K sammanhang) - Bästa balans av kvalitet och prestanda
    • Hög kvalitet: mistral-nemo (12B params, 128K sammanhang) - komplexa scheman och massiva datauppsättningar
    • Resursbegränsad: gemma3:4b eller phi3 - Lättare alternativ

Fullständig dokumentation

Slutsatser

Frontend utveckling behöver inte vänta på gränssnitt API:er. mostlylucid.mockllmapi ger dig:

  • Sammanhangsminne - Konsekvent, stateful data över flera steg arbetsflöden
  • Styrning av form - Exakta schema definitioner som matchar dina typer
  • Stöd för allmänna protokoll - REST, GraphQL, gRPC, SignalR, SSE, OpenAPI
  • Hybridprovning - Blanda verkliga produktionsdata med genererade modeller
  • Noll underhåll - Inga JSON fixturer att uppdatera när kraven ändras
  • Testverktyg - Fluent API för integrationstest

Skillnaden mellan detta och traditionell hån? Din frontend arbetar mot realistiska, kontextuellt medvetna data från dag ett. Inte mer "det fungerade med mock data men misslyckades med verkliga data" överraskningar.

Oavsett om du bygger en enkel blogg eller en komplex företagsprogram, kommer du att iterera snabbare, testa mer noggrant, och skeppa med tillförsikt.

Är du redo att sätta igång?

docker compose up -d

Det behövs inget gränssnitt.

Finding related posts...
logo

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