DotNet Framework version is here NetCore Framework version is here
- (01) HttpApi is a convinent framework to provide data by http, It is the upgrating replacement for WebAPI.
- (02) HttpApi can export class function to http interface, eg.
http://.../HttpApi/TypeName/Method?p1=x&p2=x
- (03) HttpApi can export page's method to http interface, eg.
http://.../Page1.aspx/GetData?page=1&rows=2&sort=abc&order=desc
http://.../Handler1.ashx/GetData?page=1&rows=2&sort=abc&order=desc
- (04) HttpApi can auto create client javascript.
http://.../HttpApi/TypeName/js
- (05) HttpApi can auto create api list page, api test page. eg.
HttpApi/TypeName/api
HttpApi/TypeName/apis
HttpApi/TypeName/Method$
- (06) Caching: You can assign api result caching duration. And client can refresh cache by '_refresh=true' parameter.
- (07) Auth: IP, Method, LoginStatus, UserName, UserRole, Token, and custom logic.
- (08) Capsule: return standard APIResult object to client.
- (09) Output configuration: You can config output format, such as enum, datetime, long number, error.
- (10) Server site and client can assign api output data format, such as text, xml, json, file, image, base64image.
- (11) Support nullable and default parameter.
- (12) Support traffic control, see HttpApiAttribute.AuthTraffic
- (13) Support upload file, see HttpApiAttribute.PostFile
http://github.com/surfsky
Nuget: install-package App.HttpApi
Nuget: install-package App.HttpApiCore
Skip to step 3 if use nuget to install httpapi.
(1) Import App.HttpApi.dll
(2) Config
netframework version
<configSections>
<section name="httpApi" type="App.HttpApi.HttpApiConfig, App.HttpApi"/>
</configSections>
<httpApi
formatEnum="Text"
formatIndented="Indented"
formatDateTime="yyyy-MM-dd"
formatLongNumber="Int64,UInt64,Decimal"
formatLowCamel="false"
errorResponse="APIResult"
typePrefix="App."
wrap="false"
language="en"
/>
<system.webServer>
<modules>
<add name="HttpApiModule" type="App.HttpApi.HttpApiModule" />
</modules>
</system.webServer>
net core version
app.UseHttpApi(o => // ÆôÓÃ HttpApi
{
o.TypePrefix = "App.API.";
o.FormatEnum = EnumFomatting.Int;
});
(3) Modify method, add [HttpApi] Attribute
namespace App
{
public class Demo
{
[HttpApi("HelloWorld")]
public static string HelloWorld(string info)
{
System.Threading.Thread.Sleep(200);
return string.Format("Hello world! {0} {1}", info, DateTime.Now);
}
}
}
(4) Ok, Client can call this api by url:
http://...../HttpApi/Demo/HelloWorld?info=x
or test:
http://...../HttpApi/Demo/HelloWorld$
Web.Config
<configSections>
<section name="httpApi" type="App.HttpApi.HttpApiConfig, App.HttpApi"/>
</configSections>
<httpApi
formatEnum="Text" // Decide how to export Enum: Text | Int
formatIndented="Indented" // Decide whether to beautify json output by and space indent and line break
formatDateTime="yyyy-MM-dd" // Decide how to export DateTime
formatLowCamel="false" // Decide whether to use low camel for property name
formatLongNumber="Int64,Decimal" // Decide which number type to string, to avoiding javascript number precision error
errorResponse="APIResult" // Decide error output when catch exception: APIResult | HttpError
typePrefix="App." // Url abbr support. eg. Raw url /HttpAPI/App.Base/Demo can change to the short path: /HttpApi/Base/Demo
language="en" // Culture support: en, zh-CN
/>
<script src="http://.../HttpApi/Demo/js"></script>
You can add [Script] attrubute to class, to control the js content:
[Script(CacheDuration =0, ClassName ="Demo", NameSpace ="App")]
http://..../HttpApi/Demo/api
http://..../HttpApi/Demo/HelloWorld$
You can add [History] attribute, to display api modify history. You can add [Param] attribute, to display api parameter infomation.
[History("2016-11-01", "SURFSKY", "modify A")]
public class Demo
{
[HttpApi("HelloWorld", CacheSeconds=10)]
[Param("info", "information")]
public static string HelloWorld(string info)
{
....
}
}
[HttpApi("Output system time", CacheSeconds=30)]
public DateTime GetTime()
{
return System.DateTime.Now;
}
The api result will cache 30 seconds:
/HttpAPI/Common/GetTime
Add _refresh parameter if you want to refresh cache right now. It's useful when testing:
/HttpAPI/Common/GetTime?_refresh=true
Server site
[HttpApi("...", Type = ResponseType.JSON)]
[HttpApi("...", Type = ResponseType.XML)]
[HttpApi("...", Type = ResponseType.Text)]
[HttpApi("...", Type = ResponseType.Html)]
[HttpApi("...", Type = ResponseType.Javascript)]
[HttpApi("...", Type = ResponseType.Image)]
[HttpApi("...", Type = ResponseType.ImageBase64)]
[HttpApi("...", Type = ResponseType.TextFile,)]
[HttpApi("...", Type = ResponseType.BinaryFile)]
Client side
http://...../HttpApi/Demo/HelloWorld?_type=xml
<APIResult>
<Result>True</Result>
<Info>»ñÈ¡³É¹¦</Info>
<CreateDt>2019-07-16 10:26:30</CreateDt>
<Data>Hello world!</Data>
<Extra/>
</APIResult>
- Use Https to transport api data, to avoiding be listenned and modified.
- Full open api: This kinds of api is only use in inner trusted system environment.
- Fixed Token protected api: This kind of token is fixed string, such as appid.
- Dynamic token protected api: Token is created by appid + appsecret + timestamp.
- Need Login api: such as GetMyOrder.
- Other limit: IP, Frequence, Action.
[HttpApi("...", AuthVerbs="Get,Post")] // check visit verb
[HttpApi("...", AuthLogin=true)] // check user login status
[HttpApi("...", AuthUsers="A,B")] // check user name
[HttpApi("...", AuthRoles="A,B")] // check user role
[HttpApi("...", AuthIP=true)] // check visit IP
[HttpApi("...", AuthToken=true)] // check token
[HttpApi("...", AuthTraffic=1)] // check traffic for: 1 times per second
[HttpApi("Login")]
public string Login()
{
AuthHelper.Login("Admin", new string[] { "Admins" }, DateTime.Now.AddDays(1));
System.Threading.Thread.Sleep(200);
return "Login success ";
}
[HttpApi("Sign out")]
public string Logout()
{
AuthHelper.Logout();
System.Threading.Thread.Sleep(200);
return "Sign ok";
}
[HttpApi("User must login", AuthLogin=true)]
public string LimitLogin()
{
System.Threading.Thread.Sleep(200);
return "OK(Logined) ";
}
[HttpApi("User must be admin or kevin", AuthUsers = "Admin,Kevin")]
public string LimitUser()
{
System.Threading.Thread.Sleep(200);
return "OK(Limit Admin,Kevin) ";
}
[HttpApi("Use must has 'admins' role", AuthRoles = "Admins")]
public string LimitRole()
{
System.Threading.Thread.Sleep(200);
return "OK(Limit Admins) ";
}
You can check token and ip in custom way, eg.
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
// HttpApi custom auth
HttpApiConfig.Instance.OnAuth += (ctx, method, attr, token) =>
{
if (attr.AuthIP && !CheckIP(ip))
throw new HttpApiException("This ip is forbidden", 401);
if (attr.AuthToken && !CheckToken(token))
throw new HttpApiException("Please check token", 401);
if (attr.Log)
Logger.Log(...);
// Other auth logic, such as visit frequence.
// Throw HttpApiException if auth fail.
};
}
}
HttpApi supports traffic control.
To enable this capability, just set HttpApiAttribute.AuthTraffic=n
(n means visit times per second).
The engine will count and detect the visit ip and url.
If the traffic is too heavy, the engine will abort the connection
for a long time (Setted in HttpApiConfig.Instance.BanMinutes).
This capability is offen openned for login api to protect website security.
[HttpApi("User login", AuthTraffic=1)]
public string Login()
{
AuthHelper.Login("Admin", new string[] { "Admins" }, DateTime.Now.AddDays(1));
System.Threading.Thread.Sleep(200);
return "Login success";
}
If you refresh the login api page too quickly, you will see the unreachable page error for a long time.
HttpApi supports upload file. To enable this capability, just set HttpApiAttribute.PostFile=true, the engine will auto create test page with a file input field.
[HttpApi("UploadFile", PostFile=true)]
public APIResult Up(string filePath, string fileName)
{
...
if (HttpContext.Current.Request.Files.Count == 0)
return new APIResult(false, "File doesn't exist", 11);
Asp.Request.Files[0].SaveAs(path);
return new APIResult(true, url);
}
HttpApi support uniform api result format to simply client calling.
[HttpApi("Ouput system datetime")]
public APIResult GetTime()
{
return new APIResult(true, "OK", System.DateTime.Now);
}
Then the output maybe
{
Result: true,
Info: "OK",
CreateDt: "2019-07-16 10:24:14",
Data: '2019-01-01',
Extra: {...}
}
public string Description { get; set; }
public string Example { get; set; }
public string Remark { get; set; }
public string MimeType { get; set; }
public string FileName { get; set; }
public bool Wrap { get; set; } = false;
public ApiStatus Status { get; set; }
public bool PostFile {get; set;}
[HttpApi("Json Wrapper", Wrap = true)]
public static object TestWrap()
{
return new { h = "3", a = "1", b = "2", c = "3" };
}
[HttpApi("Default paramter", Status = ApiStatus.Delete, AuthVerbs ="GET")]
public static object TestDefaultParameter(string p1, string p2="a")
{
return new { p1 = p1, p2 = p2};
}
[HttpApi("Exception Test")]
public static object TestError()
{
int n = 0;
int m = 1 / n;
return true;
}
[HttpApi("Auth verb", AuthVerbs ="Post")]
public static string TestVerbs()
{
return HttpContext.Current.Request.HttpMethod;
}
[HttpApi("Return enum")]
public static Sex TestEnum()
{
return Sex.Male;
}
//---------------------------------------------
// Other basic data type
//---------------------------------------------
[HttpApi("plist file", CacheSeconds = 30, MimeType="text/plist", FileName="app.plist")]
public string GetFile(string info)
{
System.Threading.Thread.Sleep(200);
return string.Format("This is plist file demo! {0} {1}", info, DateTime.Now);
}
[HttpApi("date time", CacheSeconds=30)]
public DateTime GetTime()
{
return System.DateTime.Now;
}
[HttpApi("DataTable")]
public DataTable GetDataTable()
{
DataTable dt = new DataTable("test");
dt.Columns.Add("column1");
dt.Columns.Add("column2");
dt.Rows.Add("a1", "b1");
dt.Rows.Add("a2", "b2");
return dt;
}
[HttpApi("DataRow")]
public DataRow GetDataRow()
{
DataTable dt = new DataTable("test");
dt.Columns.Add("column1");
dt.Columns.Add("column2");
dt.Rows.Add("a1", "b1");
dt.Rows.Add("a2", "b2");
return dt.Rows[0];
}
[HttpApi("Dictionary")]
public IDictionary GetDictionary()
{
var dict = new Dictionary<int, Person>();
dict.Add(0, new Person() { Name = "Marry" });
dict.Add(1, new Person() { Name = "Cherry" });
return dict;
}
[HttpApi("Image", CacheSeconds=60)]
public Image GetImage(string text)
{
Bitmap bmp = new Bitmap(200, 200);
Graphics g = Graphics.FromImage(bmp);
g.DrawString(
text,
new Font("Arial", 16, FontStyle.Bold),
new SolidBrush(Color.FromArgb(255, 206, 97)),
new PointF(5, 5)
);
return bmp;
}
//---------------------------------------------
// Class
//---------------------------------------------
[HttpApi("father:{Name:'Kevin', Birth:'1979-12-01', Sex:0};")]
public Person CreateGirl(Person father)
{
return new Person()
{
Name = father.Name + "'s dear daughter",
Birth = System.DateTime.Now,
Sex = Sex.Female,
Father = father
};
}
[HttpApi("null")]
public static Person CreateNull()
{
return null;
}
[HttpApi("Output class object")]
public static Person GetPerson()
{
return new Person() { Name = "Cherry" };
}
[HttpApi("Output Xml", Type=ResponseType.XML)]
public static Person GetPersonXml()
{
return new Person() { Name = "Cherry" };
}
[HttpApi("Output class, and wrap with APIResult", Wrap =true)]
public static Person GetPersonDataResult()
{
return new Person() { Name = "Kevin" };
}
[HttpApi("Output APIResult")]
public static APIResult GetPersons()
{
var persons = new List<Person>(){
new Person(){ Name="Kevin", Sex=Sex.Male, Birth=new DateTime(2000, 01, 01)},
new Person(){ Name="Cherry", Sex=Sex.Female, Birth=new DateTime(2010, 01, 01)}
};
return new APIResult(true, "", persons);
}
- Basic motivation: (1) Simplify api coding for http server; (2) Auto create client calling javascript
- And more complex functions, such as auth, security, caching, format, exception, uniform api result, etc.
- WebAPI has many limits: http://blog.csdn.net/leeyue_1982/article/details/51305950
- So I create this project, and maintain it for so many years.
- Long time connect
- XML format control: property/field, indent, case...
Chinese readme file is here
Buy me a coffee if you like this framework, thank you.