From 9ba8da4c0fb407280b65e048fd889d22eed7e647 Mon Sep 17 00:00:00 2001
From: Pavel Vostretsov
Date: Thu, 11 Jan 2024 13:52:19 +0500
Subject: [PATCH] simplify api generator
---
.../output/api/NotesApi.ts | 8 ++--
.../output/api/UserApi.ts | 12 ++---
.../output/api/WeatherForecastApi.ts | 12 ++---
.../output/apiBase/ApiBase.ts | 48 ++++---------------
.../ApiController/ApiBaseLocation.cs | 9 ++++
.../ApiControllerTypeBuildingContext.cs | 17 +++----
.../ApiController/DefaultApiCustomization.cs | 29 +++++------
.../ApiController/IApiCustomization.cs | 3 +-
.../ApiController/KnownTypeNames.cs | 2 +
9 files changed, 61 insertions(+), 79 deletions(-)
create mode 100644 TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiBaseLocation.cs
diff --git a/AspNetCoreExample.Generator/output/api/NotesApi.ts b/AspNetCoreExample.Generator/output/api/NotesApi.ts
index db65a53..8810a8f 100644
--- a/AspNetCoreExample.Generator/output/api/NotesApi.ts
+++ b/AspNetCoreExample.Generator/output/api/NotesApi.ts
@@ -2,16 +2,16 @@
// TypeScriptContractGenerator's generated content
import { Guid } from './../DataTypes/Guid';
import { BlogEntry } from './../DataTypes/BlogEntry';
-import { ApiBase } from './../ApiBase/ApiBase';
+import { request } from './../ApiBase/ApiBase';
import { url } from './../ApiBase/ApiBase';
-export class NotesApi extends ApiBase implements INotesApi {
+export class NotesApi implements INotesApi {
addEntry(userId: Guid, entry: BlogEntry): Promise {
- return this.makePostRequest(url`/v1/user/${userId}/blog`, entry);
+ return request('POST', url`/v1/user/${userId}/blog`, entry);
}
addEntries(userId: Guid, entries: BlogEntry[]): Promise {
- return this.makePostRequest(url`/v1/user/${userId}/blog/batch`, entries);
+ return request('POST', url`/v1/user/${userId}/blog/batch`, entries);
}
};
diff --git a/AspNetCoreExample.Generator/output/api/UserApi.ts b/AspNetCoreExample.Generator/output/api/UserApi.ts
index b62c2b2..60c2054 100644
--- a/AspNetCoreExample.Generator/output/api/UserApi.ts
+++ b/AspNetCoreExample.Generator/output/api/UserApi.ts
@@ -2,24 +2,24 @@
// TypeScriptContractGenerator's generated content
import { User } from './../DataTypes/User';
import { Guid } from './../DataTypes/Guid';
-import { ApiBase } from './../ApiBase/ApiBase';
+import { request } from './../ApiBase/ApiBase';
import { url } from './../ApiBase/ApiBase';
-export class UserApi extends ApiBase implements IUserApi {
+export class UserApi implements IUserApi {
createUser(user: User): Promise {
- return this.makePostRequest(url`/v1/users`, user);
+ return request('POST', url`/v1/users`, user);
}
deleteUser(userId: Guid): Promise {
- return this.makeDeleteRequest(url`/v1/users/${userId}`);
+ return request('DELETE', url`/v1/users/${userId}`);
}
getUser(userId: Guid): Promise {
- return this.makeGetRequest(url`/v1/users/${userId}`);
+ return request('GET', url`/v1/users/${userId}`);
}
searchUsers(name: string): Promise {
- return this.makeGetRequest(url`/v1/users?name=${name}`);
+ return request('GET', url`/v1/users?name=${name}`);
}
};
diff --git a/AspNetCoreExample.Generator/output/api/WeatherForecastApi.ts b/AspNetCoreExample.Generator/output/api/WeatherForecastApi.ts
index f7caa54..2f1a2ee 100644
--- a/AspNetCoreExample.Generator/output/api/WeatherForecastApi.ts
+++ b/AspNetCoreExample.Generator/output/api/WeatherForecastApi.ts
@@ -2,20 +2,20 @@
// TypeScriptContractGenerator's generated content
import { WeatherForecast } from './../DataTypes/WeatherForecast';
import { Guid } from './../DataTypes/Guid';
-import { ApiBase } from './../ApiBase/ApiBase';
+import { request } from './../ApiBase/ApiBase';
import { url } from './../ApiBase/ApiBase';
-export class WeatherForecastApi extends ApiBase implements IWeatherForecastApi {
+export class WeatherForecastApi implements IWeatherForecastApi {
get(): Promise {
- return this.makeGetRequest(url`/WeatherForecast`);
+ return request('GET', url`/WeatherForecast`);
}
update(city: string, forecast: WeatherForecast): Promise {
- return this.makePostRequest(url`/WeatherForecast/Update/${city}`, forecast);
+ return request('POST', url`/WeatherForecast/Update/${city}`, forecast);
}
reset(seed: number): Promise {
- return this.makePostRequest(url`/Reset?seed=${seed}`);
+ return request('POST', url`/Reset?seed=${seed}`);
}
urlForDownload(city: string): string {
@@ -27,7 +27,7 @@ export class WeatherForecastApi extends ApiBase implements IWeatherForecastApi {
}
newGuid(): Promise {
- return this.makeGetRequest(url`/WeatherForecast/none`);
+ return request('GET', url`/WeatherForecast/none`);
}
};
diff --git a/AspNetCoreExample.Generator/output/apiBase/ApiBase.ts b/AspNetCoreExample.Generator/output/apiBase/ApiBase.ts
index 74a9f03..f858aa1 100644
--- a/AspNetCoreExample.Generator/output/apiBase/ApiBase.ts
+++ b/AspNetCoreExample.Generator/output/apiBase/ApiBase.ts
@@ -2,44 +2,14 @@
export const url = String.raw;
-export class ApiBase {
- public async makeGetRequest(url: string, body?: any): Promise {
- const response = await fetch(url, {
- method: "GET",
- });
- return await response.json();
- }
-
- public async makePostRequest(url: string, body?: any): Promise {
- const response = await fetch(url, {
- method: "POST",
- body: body && JSON.stringify(body),
- });
- const textResult = await response.text();
- if (textResult !== "") {
- return JSON.parse(textResult);
- }
- }
-
- public async makePutRequest(url: string, body?: any): Promise {
- const response = await fetch(url, {
- method: "PUT",
- body: body && JSON.stringify(body),
- });
- const textResult = await response.text();
- if (textResult !== "") {
- return JSON.parse(textResult);
- }
- }
+export const request = async (method: string, url: string, body?: any): Promise => {
+ const response = await fetch(url, {
+ method: method,
+ body: body && JSON.stringify(body),
+ });
- public async makeDeleteRequest(url: string, body?: any): Promise {
- const response = await fetch(url, {
- method: "DELETE",
- body: body && JSON.stringify(body),
- });
- const textResult = await response.text();
- if (textResult !== "") {
- return JSON.parse(textResult);
- }
+ const textResult = await response.text();
+ if (textResult !== "") {
+ return JSON.parse(textResult);
}
-}
+}
\ No newline at end of file
diff --git a/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiBaseLocation.cs b/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiBaseLocation.cs
new file mode 100644
index 0000000..d917581
--- /dev/null
+++ b/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiBaseLocation.cs
@@ -0,0 +1,9 @@
+namespace SkbKontur.TypeScript.ContractGenerator.TypeBuilders.ApiController
+{
+ public class ApiBaseLocation
+ {
+ public string RequestMethodName { get; set; }
+ public string UrlTagName { get; set; }
+ public string Location { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiControllerTypeBuildingContext.cs b/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiControllerTypeBuildingContext.cs
index ab1d326..4d6eec1 100644
--- a/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiControllerTypeBuildingContext.cs
+++ b/TypeScript.ContractGenerator/TypeBuilders/ApiController/ApiControllerTypeBuildingContext.cs
@@ -23,10 +23,8 @@ public override void Initialize(ITypeGenerator typeGenerator)
BuildAndImportType = t => typeGenerator.BuildAndImportType(Unit, t);
var baseApi = ApiCustomization.GetApiBase(Type);
- var urlTag = ApiCustomization.GetUrlTag(Type);
-
- Unit.AddSymbolImport(baseApi.Name, baseApi.Location);
- Unit.AddSymbolImport(urlTag.Name, urlTag.Location);
+ Unit.AddSymbolImport(baseApi.RequestMethodName, baseApi.Location);
+ Unit.AddSymbolImport(baseApi.UrlTagName, baseApi.Location);
var apiName = ApiCustomization.GetApiClassName(Type);
var interfaceName = ApiCustomization.GetApiInterfaceName(Type);
@@ -37,7 +35,6 @@ public override void Initialize(ITypeGenerator typeGenerator)
var apiClassDefinition = new TypeScriptClassDefinition
{
- BaseClass = new TypeScriptTypeReference(baseApi.Name),
ImplementedInterfaces = new TypeScriptType[] {new TypeScriptTypeReference(interfaceName)},
};
@@ -102,13 +99,17 @@ protected virtual TypeScriptReturnStatement CreateCall(IMethodInfo methodInfo)
return new TypeScriptReturnStatement(routeExpression);
}
+ var requestMethodName = ApiCustomization.GetApiBase(methodInfo.DeclaringType!).RequestMethodName;
+ var verb = ApiCustomization.GetMethodVerb(methodInfo);
+ var requestExpression = new TypeScriptVariableReference(requestMethodName);
+ var methodExpression = (TypeScriptExpression)new TypeScriptStringLiteral(verb);
var bodyExpression = ApiCustomization.GetMethodBodyExpression(methodInfo);
var arguments = bodyExpression == null
- ? new[] {routeExpression}
- : new[] {routeExpression, bodyExpression};
+ ? new[] {methodExpression, routeExpression}
+ : new[] {methodExpression, routeExpression, bodyExpression};
return new TypeScriptReturnStatement(
- new TypeScriptMethodCallExpression(new TypeScriptThisReference(), ApiCustomization.GetMethodVerb(methodInfo), arguments)
+ new TypeScriptFunctionCallExpression(requestExpression, arguments)
);
}
diff --git a/TypeScript.ContractGenerator/TypeBuilders/ApiController/DefaultApiCustomization.cs b/TypeScript.ContractGenerator/TypeBuilders/ApiController/DefaultApiCustomization.cs
index 2a00366..1f3f1df 100644
--- a/TypeScript.ContractGenerator/TypeBuilders/ApiController/DefaultApiCustomization.cs
+++ b/TypeScript.ContractGenerator/TypeBuilders/ApiController/DefaultApiCustomization.cs
@@ -16,15 +16,10 @@ namespace SkbKontur.TypeScript.ContractGenerator.TypeBuilders.ApiController
{
public class DefaultApiCustomization : IApiCustomization
{
- public virtual TypeLocation GetApiBase(ITypeInfo type) => new TypeLocation
+ public virtual ApiBaseLocation GetApiBase(ITypeInfo type) => new ApiBaseLocation
{
- Name = "ApiBase",
- Location = "ApiBase/ApiBase",
- };
-
- public virtual TypeLocation GetUrlTag(ITypeInfo type) => new TypeLocation
- {
- Name = "url",
+ RequestMethodName = "request",
+ UrlTagName = "url",
Location = "ApiBase/ApiBase",
};
@@ -47,7 +42,7 @@ public virtual IParameterInfo[] GetMethodParameters(IMethodInfo methodInfo) =>
public virtual bool IsUrlMethod(IMethodInfo methodInfo)
{
- return GetMethodVerb(methodInfo) == "makeGetRequest" && ResolveReturnType(methodInfo.ReturnType).Equals(TypeInfo.From(typeof(void)));
+ return GetMethodVerb(methodInfo) == "GET" && ResolveReturnType(methodInfo.ReturnType).Equals(TypeInfo.From(typeof(void)));
}
public virtual bool IsAsyncMethod(IMethodInfo methodInfo) => false;
@@ -57,19 +52,25 @@ public virtual string GetMethodVerb(IMethodInfo methodInfo)
var attributes = methodInfo.GetAttributes(inherit : false);
if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpGet)))
- return "makeGetRequest";
+ return "GET";
if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpPost)))
- return "makePostRequest";
+ return "POST";
if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpPut)))
- return "makePutRequest";
+ return "PUT";
if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpDelete)))
- return "makeDeleteRequest";
+ return "DELETE";
if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpPatch)))
- return "makePatchRequest";
+ return "PATCH";
+
+ if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpHead)))
+ return "HEAD";
+
+ if (attributes.Any(x => x.HasName(KnownTypeNames.Attributes.HttpOptions)))
+ return "OPTIONS";
throw new NotSupportedException($"Unresolved http verb for method {methodInfo.Name} at controller {methodInfo.DeclaringType?.Name}");
}
diff --git a/TypeScript.ContractGenerator/TypeBuilders/ApiController/IApiCustomization.cs b/TypeScript.ContractGenerator/TypeBuilders/ApiController/IApiCustomization.cs
index 541a3e0..fbead3d 100644
--- a/TypeScript.ContractGenerator/TypeBuilders/ApiController/IApiCustomization.cs
+++ b/TypeScript.ContractGenerator/TypeBuilders/ApiController/IApiCustomization.cs
@@ -7,8 +7,7 @@ namespace SkbKontur.TypeScript.ContractGenerator.TypeBuilders.ApiController
{
public interface IApiCustomization
{
- public TypeLocation GetApiBase(ITypeInfo type);
- public TypeLocation GetUrlTag(ITypeInfo type);
+ public ApiBaseLocation GetApiBase(ITypeInfo type);
string GetApiClassName(ITypeInfo type);
string GetApiInterfaceName(ITypeInfo type);
diff --git a/TypeScript.ContractGenerator/TypeBuilders/ApiController/KnownTypeNames.cs b/TypeScript.ContractGenerator/TypeBuilders/ApiController/KnownTypeNames.cs
index fb2a994..3f70c59 100644
--- a/TypeScript.ContractGenerator/TypeBuilders/ApiController/KnownTypeNames.cs
+++ b/TypeScript.ContractGenerator/TypeBuilders/ApiController/KnownTypeNames.cs
@@ -26,6 +26,8 @@ public static class Attributes
public const string HttpPut = "HttpPut";
public const string HttpPatch = "HttpPatch";
public const string HttpDelete = "HttpDelete";
+ public const string HttpHead = "HttpHead";
+ public const string HttpOptions = "HttpOptions";
public const string FromBody = "FromBody";
}
}