| Properties | ||
| wwwroot | ||
| CiteLynq.WebSample.csproj | ||
| Program.cs | ||
| README.md | ||
CiteLynq Web Sample
A sample ASP.NET Core web application demonstrating how to use the CiteLynq API to search for verified citations across multiple authoritative sources.
Features
✅ ASP.NET Core 9.0 minimal API ✅ Static file hosting with wwwroot ✅ Proxy endpoints to hide API keys from client ✅ Clean, modern UI with gradient design ✅ Search across multiple data sources ✅ Display formatted citations (APA, MLA, Bluebook) ✅ Filter by source type (ArXiv, PubMed, CourtListener, etc.) ✅ Responsive design ✅ Local storage for API key persistence
Quick Start
1. Get an API Key
- Visit https://citelynq.com/app/api-keys
- Create a new API key
- Copy the key (starts with
cl_)
2. Run the Application
cd /repos/CiteFlow/samples/CiteLynq.WebSample
dotnet run
The application will start on http://localhost:5100
3. Use the Application
- Open your browser to
http://localhost:5100 - Enter your API key
- Enter a search query (e.g., "climate change")
- Click "Search"
Project Structure
CiteLynq.WebSample/
├── Program.cs # ASP.NET Core minimal API
├── CiteLynq.WebSample.csproj # Project file
├── Properties/
│ └── launchSettings.json # Launch configuration
└── wwwroot/
└── index.html # Single-page application
How It Works
Backend (Program.cs)
The backend provides proxy endpoints to securely call the CiteLynq API:
-
GET /api/search - Proxies search requests
- Accepts: query parameters (q, sourceType, page, pageSize)
- Headers: X-API-Key
- Returns: Search results from CiteLynq API
-
GET /api/articles/{id} - Proxies article detail requests
- Accepts: article ID as path parameter
- Headers: X-API-Key
- Returns: Article details from CiteLynq API
Why use a proxy?
- Hides your API key from client-side code
- Prevents CORS issues
- Adds an abstraction layer for future enhancements
- Enables server-side caching if needed
Frontend (wwwroot/index.html)
The frontend is a self-contained single-page application:
- API Key Storage: Saves API key in localStorage
- Search Interface: Query input and source filter
- Results Display: Shows citations with metadata
- Responsive Design: Works on desktop and mobile
API Endpoints
Search Citations
GET /api/search?q=climate%20change&sourceType=ArXiv&page=1&pageSize=20
X-API-Key: cl_your-api-key-here
Response:
{
"data": {
"results": [
{
"id": "arxiv-2301.12345",
"sourceType": "ArXiv",
"title": "Climate Change Research",
"authors": ["Dr. Jane Smith"],
"abstract": "...",
"publishedDate": "2023-01-15",
"url": "https://arxiv.org/abs/2301.12345",
"citations": {
"apa": "Smith, J. (2023)...",
"mla": "Smith, Jane...",
"chicago": "..."
}
}
],
"totalCount": 145
}
}
Get Article Details
GET /api/articles/arxiv-2301.12345
X-API-Key: cl_your-api-key-here
Configuration
Change API Base URL
Edit Program.cs line 24 to point to a different API:
const string API_BASE_URL = "https://citelynq.com/api";
// Or for local development:
// const string API_BASE_URL = "http://localhost:5000/api";
Change Port
Edit Properties/launchSettings.json:
{
"profiles": {
"http": {
"applicationUrl": "http://localhost:5100"
}
}
}
Development
Prerequisites
- .NET 9.0 SDK
- Visual Studio 2022 / VS Code / Rider
Build
dotnet build
Run
dotnet run
Publish
dotnet publish -c Release -o ./publish
Customization
Add More Endpoints
Add new proxy endpoints in Program.cs:
app.MapGet("/api/sources", async (HttpContext context, IHttpClientFactory httpClientFactory) =>
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
var httpClient = httpClientFactory.CreateClient();
var httpRequest = new HttpRequestMessage(HttpMethod.Get, $"{API_BASE_URL}/sources");
httpRequest.Headers.Add("X-API-Key", apiKey);
var response = await httpClient.SendAsync(httpRequest);
return Results.Content(await response.Content.ReadAsStringAsync(), "application/json");
});
Customize UI
Edit wwwroot/index.html:
/* Change color scheme */
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
Add Pagination
Add pagination controls in the HTML:
function displayResults(data) {
// ... existing code ...
if (data.totalPages > 1) {
html += `<div class="pagination">
<button onclick="loadPage(${data.currentPage - 1})">Previous</button>
<span>Page ${data.currentPage} of ${data.totalPages}</span>
<button onclick="loadPage(${data.currentPage + 1})">Next</button>
</div>`;
}
}
Security Notes
⚠️ Important:
- API Key Protection: The proxy pattern keeps API keys server-side
- CORS: Configured for development (allow all origins). Restrict in production.
- Input Validation: Always validate user input
- HTTPS: Use HTTPS in production environments
Troubleshooting
Port Already in Use
Change the port in Properties/launchSettings.json
CORS Errors
The application includes CORS middleware for development. For production, configure specific origins:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins("https://yourdomain.com")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
API Key Not Working
- Verify the key starts with
cl_ - Check the key is active in your account
- Ensure the key has available credits
Learn More
- CiteLynq API Docs: https://citelynq.com/docs
- Get API Key: https://citelynq.com/app/api-keys
- ASP.NET Core: https://docs.microsoft.com/aspnet/core
License
This sample is provided as-is for demonstration purposes.