Giter Club home page Giter Club logo

hyprlinkr's Introduction

Hyprlinkr

Hyprlinkr is a small and very focused helper library for the ASP.NET Web API. It does one thing only: it creates URIs according to the application's route configuration in a type-safe manner.

As of version 2 it works with ASP.NET Web 2. Look for version 1 for compatibility with ASP.NET Web API 1.

Example

Imagine that you're using the standard route configuration created by the Visual Studio project template:

name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }

In that case, you can create an URI to a the resource handled by the FooController.GetById Action Method like this:

var uri = linker.GetUri<FooController>(r => r.GetById(1337));

This will create a URI like this:

http://localhost/api/foo/1337

assuming that the current host is http://localhost. Creating a RouteLinker instance

The RouteLinker class has two constructor overloads:

public RouteLinker(HttpRequestMessage request)

public RouteLinker(HttpRequestMessage request, IRouteDispatcher dispatcher)

In both cases it requires an instance of the HttpRequestMessage class, which is provided by the ASP.NET Web API for each request. The preferred way to get this instance is to implement a custom IHttpControllerActivator and create the RouteLinker instance from there.

public IHttpController Create(
    HttpRequestMessage request,
    HttpControllerDescriptor controllerDescriptor,
    Type controllerType)
{
    var linker = new RouteLinker(request);

    // Use linker and other services to create the appropriate Controller.
    // If desired, a DI Container can be used for this task.
}

Such a custom IHttpControllerActivator can be registered in Global.asax like this:

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator),
    new MyCustomControllerActivator());

This approach enables the use of Dependency Injection (DI) because the request can be injected into the services which require it.

Without Dependency Injection

As an alternative to Dependency Injection (DI), the request can also be pulled directly from the ApiController instance. This requires that Controllers derive from ApiController. If this is the case, a RouteLinker instance can be created easily:

var linker = new RouteLinker(this.Request);

The example code includes a NoDIController class that demonstrates this approach.

From an API Controller

If you want to use Hyprlinkr directly from an ApiController, you can use extension methods to create links:

// Inside an ApiController
var uri = this.Url.GetLink<FooController>(a => a.GetById(1337));

This will create a URI like this:

http://localhost/api/foo/1337

assuming that the current host is http://localhost. Custom route dispatching

The default behavior for RouteLinker is:

  • If the method being linked to has a [Route] attribute with a route name defined, use that route. Note that you cannot link to a method with an unnamed [Route] attribute
  • Otherwise assume that there's only a single configured route, and that route is named "API Default"

This behavior is implemented by the DefaultRouteDispatcher class. If you require different dispatching behavior, you can implement a custom IRouteDispatcher and inject it into the RouteLinker instances. Nuget

Hyprlinkr is available via nuget Versioning

Hyprlinkr follows Semantic Versioning 2.0.0. Example code

The ExampleService project, included in the source code, provides a very simple example of how to wire and use Hyprlinkr. As an example, in HomeController.cs you can see that links are added to a model instance like this:

public HomeModel Get(string id)
{
    return new HomeModel
    {
        Name = id,
        Links = new[]
        {
            new AtomLinkModel
            {
                Href = this.linker.GetUri<HomeController>(r =>
                    r.Get(id)).ToString(),
                Rel = "self"
            },
            new AtomLinkModel
            {
                Href = this.linker.GetUri<HomeController>(r =>
                    r.Get()).ToString(),
                Rel = "http://sample.ploeh.dk/rels/home"
            }
        }
    };
}

This produces a representation equivalent to this:

<home xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns="http://www.ploeh.dk/hyprlinkr/sample/2012">
    <links>
        <link xmlns="http://www.w3.org/2005/Atom"
              href="http://localhost:6788/home/ploeh"
              rel="self"/>
        <link xmlns="http://www.w3.org/2005/Atom"
              href="http://localhost:6788/"
              rel="http://sample.ploeh.dk/rels/home"/>
    </links>
    <name>ploeh</name>
</home>

In order to run the sample application, open the Hyprlinkr.sln solution and set ExampleService as the startup project, then run the application by hitting F5 (or Ctrl+F5). Credits

The strongly typed Resource Linker idea was originally presented by José F. Romaniello.

hyprlinkr's People

Contributors

dlongest avatar hmigneron avatar joachiml avatar josephwoodward avatar matthewrichards avatar ploeh avatar vgrigoriu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hyprlinkr's Issues

Templates generation

Do you think that it is possible to generate link templates or do you have any suggestion about how to extend it to support them?

For example:

var uri = linker.GetUri<FooController>(r => r.GetById(linker.Template("myid")));

to generate

http://localhost/api/foo/{myid}

Or

var uri = linker.GetUri<FooController>(r => r.GetById(linker.Template));

to generate

http://localhost/api/foo/{id}

Provide overloads for GetUri that accept an IRouteDispatcher or a route name

Especially with multiple routes for nested resources it is necessary to use different route dispatchers.
The route dispatcher is only used in the call to GetUri, and thus an overload that accepts an IRouteDispatcher is possible.

Use case:

// uses default dispatcher or dispatcher that has been passed into the constructor:
model.Language =
    linker.GetUri<LanguagesController>(c => c.GetById(entity.Language.Id));

// uses the specific dispatcher for that action:
model.Comments = 
    linker.GetUri<PostsController>(c => c.GetCommentsOfPosts(entity.Id),
                                   new MyRouteDispatcher("Posts Routes"));
// uses the DefaultRouteDispatcher for the specified route:
model.Comments = 
    linker.GetUri<PostsController>(c => c.GetCommentsOfPosts(entity.Id), "Posts Routes");

Implementation is trivial and can be done by me, if you agree with this overload.

Support for attribute-based route names

I am using attribute routing in my controllers, using the [Route] attribute with route names, and I noticed that Hyprlinkr always assumes that there's a route named 'DefaultApi' to generate the Uris, which does not work with attribute routing.

Is that correct, or am I missing something?

Thank you

Reversal of link

Are there plans to implement the reversal of link generation?
Imagine, in a controller action that creates a new object, a link to the newly created object is returned, just like in the Post method here. Hyprlinkr could be used to create that link instead of the GetContactLocation method.

But now, lets assume that each contact has a list of related contacts. When you add a new contact, these related contacts would be supplied as URIs in the request. To be able to correctly link the new contact to the related contacts in the domain model, you would at least need to extract the IDs from the URIs.

Wouldn't it be nice to use Hyprlinkr to somehow get these related objects or their IDs?

What are your thoughts on this?

Support for complex type as parameter to GetUri

Is it possible to have Hyprlinkr support complex type parameters inside the MethodCallExpression passed to linker.GetUri?

The scenario I'm trying to accomplish is in trying to get the Uri of an action that accepts a complex type as the key.

I.e.

public Contact Get(ContactQuery query)
{
    var contact = this.repository.GetContact(query.Id, query.UserName);
    contact.Link = new Link()
    {
        Href = _linker.GetUri<ContactsController>(x => x.Get(query)).ToString(),
        Rel = "self",
        Title = contact.ToString()
    };
    return contact;
}

Where ContactQuery is defined as:

[FromUri]
public class ContactQuery
{
    public int Id { get; set; }
    public string UserName { get; set; }
}

When stepping into my CustomRouteDispatcher, I can see that the route linker has passed the routeValues with the type name as the value for the "query" key.

routeValues["query"]
    "WebAPI.Controllers.Models.ContactQuery"

I "think" this is because the GetValue implementation in RouteLinker only calls ToString()

private static object GetValue(MethodCallExpression methodCallExp,
        ParameterInfo p)
    {
        var arg = methodCallExp.Arguments[p.Position];
        var lambda = Expression.Lambda(arg);
        return lambda.Compile().DynamicInvoke().ToString();
    }

Ideally, the values of the ContactQuery object, (Id and UserName) need to be pulled out and added to the route values.

Is this possible with the current implementation or is there a way that the RouteLinker can be extended so that I can customise this behaviour?

Appreciate your help.

Joe.

Logo

Hyprlinkr should have a logo, to be used as icon for its NuGet package, etc.

A link to another controller's parameterless method includes current request's parameter

I've started using Hyperlinkr just a week or so ago, not long after I started working with Web Api 2.
I came across what looks like an issue to me, but it could also be that my expectation is wrong.

So, my problem is that while processing a request with a single Id parameter I try to get a link to a parameterless resource served by another controller and the resulting link includes the Id of the current request.
I see that the very same behaviour is exhibited by the HomeController in ExampleService.
E.g. the response for http://localhost:6788/custom/route/5 is

{
"links": 
[{
	"href": "http://localhost:6788/custom/route/5",
	"rel": "self"
}, {
	"href": "http://localhost:6788/home/5",
	"rel": "http://sample.ploeh.dk/rels/home"
}],
"name": "5"
}

The second "href" value "http://localhost:6788/home/5" corresponds to the expression Href = this.linker.GetUri<HomeController>(r => r.Get()).ToString().
I cannot see why it should end with /5.

Am I missing something?

Thanks,
Roman.

Error When Generating Route - AttributeRouting

Hi Guys.

I've been following the article here:

http://www.codedistillers.com/tja/2013/08/12/how-to-integrate-asp-net-webapi-attributerouting-with-hyprlinkr/#comment-4948

And am getting an error:

The route string returned by System.Web.Http.Routing.UrlHelper.Route(string, IDictionary) is null, which indicates an error. This can happen if the Action Method identified by the RouteLinker.GetUri method doesn’t have a matching route with the name “”, or if the route parameter names don’t match the method arguments.

Is that a common exception you've come across before?

Regards

RouteLinker produces wrong URI with action defined on abstract base class

Assume the following scenario:
You have an generic abstract class deriving from ApiController. This class implements the default actions for GetAll, GetById, Add, Update and Delete.
Now you have several controllers deriving from that base class, e.g.

public class SubjectsController : CrudControllerBase<SubjectModel>
{
}

When RouteLinker is asked for an URI for one of the actions of the base class, it returns an URI with the baseclass as controller, although that URI is not working. The correct URI would be to use the controller supplied as type argument.

linker.GetUri<SubjectController>(c => c.GetAll());

This produces http://<host>/api/crudbase´1 instead of http://<host>/api/subjects.

I think the problem is two-fold:

  1. DefaultRouteDispatcher sets the route value controller to the class that declares the action method. However, a new implementation of IRouteDispatcher doesn't solve that problem because the generic type argument passed to RouteLinker.GetUri<T> is not forwarded to IRouteDispatcher
  2. Simply not setting the controller in the implementation of IRouteDispatcher leads to an ArgumentNullException, because RouteLinker doesn't provide a fallback value in case the dispatcher didn't provide a controller.

I think the solution needs to be to forward the specified controller type to IRouteDispatcher.

I created two failing tests to better demonstrate my findings:
https://github.com/dhilgarth/Hyprlinkr/blob/bug/ControllerWithAbstractBaseClass/Hyprlinkr.UnitTest/RouteLinkerTests.cs#L212

How do I use hyprlinkr in a non-typesafe manner?

Working on a project, where controllers are being registered at startup time... Ie. I don't know which controllers actually exist at compiletime....

However, when using hyprlinkr I have to supply the controllertype to the GetUri method. Is there a non-typsafe way of calling GetUri ?

/Søren

Support for Async controller methods for WebAPI

While the following workaround works for MVC, AsyncController is not available on WebAPI, is there a workaround for it?

Uri actual = linker.GetUriAsync((AsyncController c) => c.Get(id)).Result;

Does not seem to be working with web api 2 properly ...

Hi,

I am using it in a web api 2 project along with the attribute routing. I have a function as below:

// GET /api/authors/1/books
[Route("~/api/authors/{authorId:int}/books")]
public IEnumerable GetByAuthor(int authorId) { ... }

When calling this function as:

var link=linker.GetUri(a=>a.GetByAuther(id)).ToString();

It returns as http://localhost/api/auther/1

regards,

rahman

Support for Relative Uris

First of all, thank you for your work.

Have you thought about the possibility of supporting relative Uri generation in addition to absolute ones?

If that is something that you would be OK with, I'm available to contribute.

Thanks

Improve logo

The Hyprlinkr logo doesn't look good in Visual Studio's Manage NuGet Packages dialog:

image

It'd be nice if this could be fixed.

NullReferenceException

ScalarRouteValueQuery throws a NullReferenceException on line 109 (var value = lambda.Compile().DynamicInvoke().ToString();) when you pass null for the value of one of the parameters. In my limited testing, removing the ToString got around the issue although I didn't look into why the ToString was there in the first place.

Version / Readme / Example application

A general question: Do you want me to update the version number when making changes and include that in the pull request? I think versioning is your responsibility, that's why I haven't done that so far.
What about the Readme? Currently, it doesn't reflect the fact that the default API route has been changed. Additionally it doesn't show an example for the ResourceLinkVerifier. Should I have changed the Readme along with the source code changes?
The example application also doesn't contain examples for the features I added. Should I have added them?

Example to create a link to a POST methods?

Hi Mark,
I would like to create a link to a method that receives POSTs (later I will be using the other verbs too).

I have an Action Method on my RoutingRuleController:

[HttpPost]
public ResourceResponse<RoutingRule> Add([FromBody] RoutingRule routingRule)
{
...
}

I then have the following Route declared:

            _routes.MapHttpRoute(
                name: "CreateItem",
                routeTemplate: "api/{controller}",
                defaults: new
                    {
                        action = "post"
                    },
                constraints: new
                    {
                        httpMethod = new HttpMethodConstraint(HttpMethod.Post)
                    }
                );

(ResourceResponse is our implementation of HAL compatible objects)

When I use hyprlinkr to generate a link to this method:

var href = _linker.GetUri<RoutingRuleController>(c => c.Add(new RoutingRule()));

it generates:

http://dogsmanager:9600/api/routingrule?routingRule=Dogs.Contract.Models.RoutingRule

when really it should be:

http://dogsmanager:9600/api/routingrule

(the documented naming convention in my HAL link relations indicate that this should be a POST of the RoutingRule resource, so that is how we communicate to the client the correct method to use).

In this case, any param that is decorated with [FromBody] should not be included in the generated Uri

Is the library only intended for linking to GET methods?

BTW, it also feels weird doing:

var href = _linker.GetUri<RoutingRuleController>(c => c.Add(new RoutingRule()));

But if I do:

var href = _linker.GetUri<RoutingRuleController>(c => c.Add(null));

I get NullRefException. Is HyprLinkr invoking the controller method?

Use Paket

I've been trialling porting Hyprlinkr to use Paket.

At present, there are 2 open issues that have material effect fsprojects/Paket#163 and fsprojects/Paket#161

(Side note: #164 should be fixed v soon and could waste time...)

However, even at this point, aside from the workarounds which should not be necessary for long, switching just involves the removal of explicit build versions from 2 lines in build.config and addition of an explicti ref to NuGet.CommandLine in the sln-level packages.config.

I'd be happy to do a PR if you want but I assume given how doing a paket convert-from-nuget a good intro to Paket and that the best time to do this kind of mucking about is when someone is adding something concrete to act as a ship vehicle I'm happy for this issue to be read, acked and closed.

Handler for Ploeh.Hyprlinkr.IResourceLinkParser was not found

I am trying to setup HyprLinkr in order to be injected using castle windsor , as stated here in this
question
however I get the following error:

{code}

Handler for Ploeh.Hyprlinkr.IResourceLinkParser was not found.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: Castle.MicroKernel.Handlers.HandlerException: Handler for Ploeh.Hyprlinkr.IResourceLinkParser was not found.

Source Error:

Line 29: }
Line 30:
Line 31: var controller = (IController) kernel.Resolve(controllerType) as Controller;
Line 32:
Line 33: if (controller != null)

Source File: c:\git\websites\TempSearch\app\TempSearch.Web\Infrastructure\Ioc\WindsorControllerFactory.cs Line: 31

Stack Trace:

[HandlerException: Handler for Ploeh.Hyprlinkr.IResourceLinkParser was not found.]
Castle.MicroKernel.Resolvers.DefaultDependencyResolver.TryGetHandlerFromKernel(DependencyModel dependency, CreationContext context) +315
Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveFromKernelByType(CreationContext context, ComponentModel model, DependencyModel dependency) +80

[DependencyResolverException: Missing dependency.
Component TempSearch.ApplicationServices.Data.Services.TempSearchService has a dependency on Ploeh.Hyprlinkr.IResourceLinkParser, which could not be resolved.
Make sure the dependency is correctly registered in the container as a service, or provided as inline argument.]
Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveFromKernelByType(CreationContext context, ComponentModel model, DependencyModel dependency) +538
Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) +38
Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) +430
Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) +52
Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) +30
Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) +27
Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, Boolean trackedExternally) +57
Castle.MicroKernel.Lifestyle.<>c__DisplayClass1.b__0(Action1 afterCreated) +29 Castle.MicroKernel.Lifestyle.Scoped.DefaultLifetimeScope.GetCachedInstance(ComponentModel model, ScopedInstanceActivationCallback createInstance) +68 Castle.MicroKernel.Lifestyle.ScopedLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) +149 Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden) +282 Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired) +35 Castle.MicroKernel.Resolvers.DefaultDependencyResolver.ResolveFromKernelByType(CreationContext context, ComponentModel model, DependencyModel dependency) +170 Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) +38 Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) +430 Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) +52 Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) +30 Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) +27 Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, Boolean trackedExternally) +57 Castle.MicroKernel.Lifestyle.<>c__DisplayClass1.<Resolve>b__0(Action1 afterCreated) +29
Castle.MicroKernel.Lifestyle.Scoped.DefaultLifetimeScope.GetCachedInstance(ComponentModel model, ScopedInstanceActivationCallback createInstance) +68
Castle.MicroKernel.Lifestyle.ScopedLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) +149
Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden) +282
Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired) +35
Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy) +154
Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy) +74
TempSearch.Web.Infrastructure.Ioc.WindsorControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) in c:\git\websites\TempSearch\app\TempSearch.Web\Infrastructure\Ioc\WindsorControllerFactory.cs:31
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +169
Castle.Proxies.Invocations.IControllerFactory_CreateController.InvokeMethodOnTarget() +155
Castle.DynamicProxy.AbstractInvocation.Proceed() +116
Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context) +71
Castle.DynamicProxy.AbstractInvocation.Proceed() +595
Castle.Proxies.IControllerFactoryProxy.CreateController(RequestContext requestContext, String controllerName) +193
System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +270
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +147
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +12288259
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

{code}

Cannot handle actions that return only Task

I have a controller action which has the following signature

public async Task Delete(int id);

it returns Task so that the webapi will return a 204 No Content by default. However the RouteLinker.GetUriAsync is type parameterized and expects the 2nd argument to be a parameterized Task.

errormessage

I think there should be a non generic version of the method that has the following signature:

public Task<Uri> GetUriAsync<T>(Expression<Func<T, Task>> method);

Wrong url parameters generation for controller actions returning statuses

When we use action definition with HttpRequestMessage parameter

public HttpResponseMessage Get(HttpRequestMessage request, int id)
{
}

this.Url.GetLink<StatusValuesController>(a => a.Get(request, key)); produce url like this

/apiv1/Values/3?request=Method%3A%20POST%2C%20RequestUri...

request parameter is not a part of routing and it souldn't be in generated url.

It only works fine if I pass null for request parameter

this.Url.GetLink<StatusValuesController>(a => a.Get(null, key));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.