Giter Site home page Giter Site logo

davidfowl / todoapi Goto Github PK

View Code? Open in Web Editor NEW
2.7K 72.0 395.0 1.1 MB

Todo application with ASP.NET Core Blazor WASM, Minimal APIs and Authentication

License: MIT License

C# 89.38% Shell 0.14% HTML 7.50% CSS 2.99%
aspnetcore authentication dotnet-core jwt opentelemetry rest-api blazor webassembly cookies

todoapi's Introduction

Todo application with ASP.NET Core

CI

This is a Todo application that features:

  • Todo.Web - An ASP.NET Core hosted Blazor WASM front end application
  • TodoApi - An ASP.NET Core REST API backend using minimal APIs

image

It showcases:

  • Blazor WebAssembly
  • Minimal APIs
  • Using EntityFramework and SQLite for data access
  • OpenAPI
  • User management with ASP.NET Core Identity
  • Cookie authentication
  • JWT authentication
  • Proxying requests from the front end application server using YARP's IHttpForwarder
  • Rate Limiting
  • Writing integration tests for your REST API

Prerequisites

.NET

  1. Install .NET 7

Database

  1. Install the dotnet-ef tool: dotnet tool install dotnet-ef -g
  2. Navigate to the TodoApi folder.
    1. Run mkdir .db to create the local database folder.
    2. Run dotnet ef database update to create the database.
  3. Learn more about dotnet-ef

JWT

  1. To initialize the keys for JWT generation, run dotnet user-jwts in to TodoApi folder:

    dotnet user-jwts create
    

Running the application

To run the application, run both the Todo.Web/Server and TodoApi. Below are different ways to run both applications:

  • Visual Studio - Setup multiple startup projects by right clicking on the solution and selecting Properties. Select TodoApi and Todo.Web.Server as startup projects.

    image
  • Visual Studio Code - A compound launch definition is provided in the launch.json file, use the 'Run and Debug' view and select 'Web and API' and start that profile.

    image

  • Terminal/CLI - Open up 2 terminal windows, one in Todo.Web.Server and the other in TodoApi run:

    dotnet watch run -lp https
    

    This will run both applications with the https profile.

  • Tye - Install the global tool using the following command:

    dotnet tool install --global Microsoft.Tye --version 0.11.0-alpha.22111.1
    

    Run tye run in the repository root and navigate to the tye dashboard (usually http://localhost:8000) to see both applications running.

  • Docker Compose - Open your terminal, navigate to the root folder of this project and run the following commands:

    1. Build a docker image for the TodoApi directly from dotnet publish.

      dotnet publish ./TodoApi/TodoApi.csproj --os linux --arch x64 /t:PublishContainer -c Release
      
    2. Build a docker image for the Todo.Web.Server directly from dotnet publish.

      dotnet publish ./Todo.Web/Server/Todo.Web.Server.csproj --os linux --arch x64 /t:PublishContainer -c Release --self-contained true
      
    3. Generate certificate and configure local machine so we can start our apps with https support using docker compose.

      Windows using Linux containers

      set PASSWORD YourPasswordHere
      dotnet dev-certs https -ep ${HOME}/.aspnet/https/todoapps.pfx -p $PASSWORD --trust
      

      macOS or Linux

      export PASSWORD=YourPasswordHere
      dotnet dev-certs https -ep ~/.aspnet/https/todoapps.pfx -p $PASSWORD --trust
      
    4. Change these variables below in the docker-compose.yml file to match your https certificate and password.

      • ASPNETCORE_Kestrel__Certificates__Default__Password
      • ASPNETCORE_Kestrel__Certificates__Default__Path
    5. Run docker-compose up -d to spin up both apps todo-api and todo-web-server plus jaeger and prometheus.

    6. Navigate to the Todo Web app https://localhost:5003.

Optional

Using the API standalone

The Todo REST API can run standalone as well. You can run the TodoApi project and make requests to various endpoints using the Swagger UI (or a client of your choice):

image

Before executing any requests, you need to create a user and get an auth token.

  1. To create a new user, run the application and POST a JSON payload to /users endpoint:

    {
      "username": "myuser",
      "password": "<put a password here>"
    }
  2. To get a token for the above user run dotnet user-jwts to create a JWT token with the same user name specified above e.g:

    dotnet user-jwts create -n myuser
    
  3. You should be able to use this token to make authenticated requests to the todo endpoints.

  4. Learn more about user-jwts

Social authentication

In addition to username and password, social authentication providers can be configured to work with this todo application. By default it supports Github, Google, and Microsoft accounts.

Instructions for setting up each of these providers can be found at:

Once you obtain the client id and client secret, the configuration for these providers must be added with the following schema:

{
    "Authentication": {
        "Schemes": {
            "<scheme>": {
                "ClientId": "xxx",
                "ClientSecret": "xxxx"
            }
        }
    }
}

Or using environment variables:

Authentication__Schemes__<scheme>__ClientId=xxx
Authentication__Schemes__<scheme>__ClientSecret=xxx

Or using user secrets:

dotnet user-secrets set Authentication:Schemes:<scheme>:ClientId xxx
dotnet user-secrets set Authentication:Schemes:<scheme>:ClientSecret xxx

Other providers can be found here. These must be added to AuthenticationExtensions as well.

NOTE: Don't store client secrets in configuration!

Auth0

This sample has Auth0 configured as an OIDC server. It can be configured with the following schema:

{
  "Authentication": {
    "Schemes": {
      "Auth0": {
        "Audience": "<audience>",
        "Domain": "<domain>",
        "ClientId": "<client id>",
        "ClientSecret": "<client secret>"
      }
    }
  }
}

Learn more about the Auth0 .NET SDK here.

OpenTelemetry

TodoApi uses OpenTelemetry to collect logs, metrics and spans.

If you wish to view the collected telemetry, follow the steps below.

Metrics

  1. Run Prometheus with Docker:
docker run -d -p 9090:9090 --name prometheus -v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
  1. Open Prometheus in your browser
  2. Query the collected metrics

Spans

  1. Configure environment variable OTEL_EXPORTER_OTLP_ENDPOINT with the right endpoint URL to enable .AddOtlpExporter below builder.Services.AddOpenTelemetryTracing, in the TodoApi/OpenTelemetryExtensions.cs file
  2. Run Jaeger with Docker:
docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 -e COLLECTOR_OTLP_ENABLED=true -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 14250:14250 -p 14268:14268 -p 14269:14269 -p 9411:9411 jaegertracing/all-in-one:latest
  1. Open Jaeger in your browser
  2. View the collected spans

todoapi's People

Contributors

blundell89 avatar cleftheris avatar cwe1ss avatar daniilzaonegin avatar davidfowl avatar eltociear avatar erikej avatar ievangelist avatar imwandama avatar luizfds avatar nielspilgaard avatar purekrome avatar revazashvili avatar sadedil avatar simoncropp avatar stevesandersonms avatar timheuer avatar timothyg 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  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

todoapi's Issues

Cannot log in: "Signing key is not specified"

I create user via swagger UI, then try to log in via blazor website

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.InvalidOperationException: Signing key is not specified
         at TodoApi.TokenService..ctor(IAuthenticationConfigurationProvider authenticationConfigurationProvider) in C:\Users\jiri\repos\TodoApi\TodoApi\Authentication\TokenService.cs:line 51
         at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
         at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
         at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
         at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
         at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
         at lambda_method13(Closure, Object, HttpContext, Object)
         at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass89_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
         at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Identity endpoints and authorization

Hey!

I'm trying to get authorization working properly on this scenario using the new endpoints built in dotnet 8.

What I'm trying to achieve is to flow the roles and some custom claims so I can show/hide controls on the razor components.

So far I couldn't get this to work and there is an issue on github for samples with this scenario (mentioned on tbe docs).

Based on your dotnet 8 branch, I was trying to make something that can represent this example.

Could you give some guidance on this, please?

GRPC Support

Would be awesome to have gRPC as well as REST,

Allow "discussions" for this repo?

๐Ÿ‘‹๐Ÿป G'day again @davidfowl ๐Ÿ˜Ž

Would you consider allowing discussions on this repo please? as in, open up the GitHub "disucssions" section/tab?

I'm reading the codebase and I'm learning heaps ... but .. have questions about the design of some things here ... and I think "issues" aren't the best/right way to ask those?

Also, I don't really want to go and use StackOverflow where this is more about repo specific stuff (versus .. what does a for loop do, etc).

Yes? No?

Shared Project DTO

Shouldn't the TodoItem in the SharedClass in the Shared project be the DTO which is used by the WASM client, and API?

The API doesn't even reference the shared project, and it defines its own TodoItem DTO in TodoApi\Todos\Todo.cs. Curious your thoughts @davidfowl.

_Host in the Server project

Hey @davidfowl
This project is awesome and helped me to learn a lot from it.
I was walking through the code and I've noticed that, instead of the index.html you are using the _Host on the Server project.

Is there any reason for it?
I noticed that there's no "loading" in it for that reason. ๐Ÿ˜€

PS: I don't care about the loading. I'm interested on what's the reason behind it.

Client-side password validation is inaccurate

At the moment, client-side validation checks whether the password given when creating a user is between 6 and 32 characters, and fails if it is not.

However the password is required to contain at least:

  • 1 upper-case letter
  • 1 lower-case letter
  • 1 digit
  • 1 non-alphanumeric character

So client-side validation can pass without the password being valid.

I'm submitting a PR shortly to fix this.

Open Telemetry Exporters

Hi there ๐Ÿ‘‹

I spotted two TODOs in OpenTelemetryExtensions and thought I'd try setting it up, both code and docs - Would that be of interest? :)

Question about Seq / ES + Kib

Hi @davidfowl (and maybe @mehdihadeli ) - in #49 Serilog was added (yay!). What's the reason for also adding in Elaticsearch/Kibana?

Add Elasticsearch and Kibana for collecting logs

Is this in case the developer wishes to export the data to ES (and use Kib to search/review) instead of Seq? that's it? Because ES/Kib have hosted options around (think: a production release of TodoApi) but for localhost dev, use Seq? (I'm not suggesting this is the way to go .. but trying to see if this is the way suggested by this PR, etc).

Cheers!

(Context: i really like serilog and am thinking of posting an amendment PR, after raising a separate issue)

The first run of the application: errors

I have built the app and run it in VS2022.
In Swagger window todos->Get->Execute, next I am here
app.MapGet("/todos", async (TodoDbContext db) =>
{
return await db.Todos.ToListAsync();
});
and next it gives me:

Error:Response bodyDownloadMicrosoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: Todos'.    at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)    at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements(Stopwatch timer)+MoveNext()    at Microsoft.Data.Sqlite.SqliteCommand.GetStatements(Stopwatch timer)+MoveNext()    at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()    at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)    at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)    at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()    at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)    at Program.<>c.<<<Main>$>b__0_3>d.MoveNext() in D:\MyProjects3\NET201\CommunityStandUpMinimalAPI-main\TodoApi\Program.cs:line 26 --- End of stack trace from previous location ---    at Microsoft.AspNetCore.Http.RequestDelegateFactory.<ExecuteTask>g__ExecuteAwaited\|58_0[T](Task`1 task, HttpContext httpContext)    at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask\|6_0(Endpoint endpoint, Task requestTask, ILogger logger)    at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)    at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)  HEADERS ======= Accept: application/json Host: localhost:5001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 OPR/85.0.4341.75 :method: GET Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cookie: sid=Fe26.2**0e7057f424d469b6ea16ff90957e6dc2d70830c9aa925f16cb439df220eb3bd0*k74iWAiiAIoqmx5AEUpukg*4Qp5f2ZkR9l0UXtTYaWXNA8l5EOT_voCp9XAG6oGzJJB27X7G1KVgTbAn-sDRvveKx9kCatHrpVYNxAUY6pHXwRznGnivGLetzIH_y5ukMzbkiRRkUs57Zht0X8MnqZu5B2EgP4TbzIQK6qZ9wpPHn43mNy_V-bu4RKLyn_vtocjasxMXZi3JCUkQFSjZPcwLt-WnokcjEounHjCHDHxH4t2rA3Mi5AwQ4JMHGT06D4**b4d47849efee7e4389a46c9230e332dd71263ace40b34b4ca54287c15d229ecb*g3CbJtM-9dpX14Hx4fBaqYTC4QLjKyKzD8OGewgrB_8,.AspNetCore.Antiforgery.UStqrS1Nq_4=CfDJ8EdynHnD-bNEiXuaekSyOeVEMUTE7Krfm1YS_g4ZWHSZAoMEq3M-QdpcA5v89Hum3NSBjsb2Jf2frTdgTylRdvOn8W4SQespuzs508O4Jc-01WSfoHCZEqvdelUl3FfwieUbT0kdfu-31JQB2A5YgC4 Referer: https://localhost:5001/swagger/index.html sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Opera";v="85" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" sec-fetch-site: same-origin sec-fetch-mode: cors sec-fetch-dest: empty  Response headers
--

```----------

What is the preason of the error? how to fix it?

Serilog is better when the settings are via config sources

๐Ÿ‘‹๐Ÿป G'day @davidfowl

So now that Serilog has been merged (ref: #49) I was hoping you might consider another Serilog PR which now removes any hardcoding of serilog settings and instead replacing them with the settings being defined via configuration sources.

Serilog has it's own special Serilog Configuration nuget which it then knows how to define some serilog settings via .NET configuration (file/env vars/etc):

image

The obvious example here is via the appsettings.json, given a specific "section". This extends to env vars so it works really nicely with Azure App Services or Docker Containers.

Can even use "Secrets" if you really need to -> think, API/License keys fr for the logging sink which is in the cloud.

Why do this?

This means anyone can easily change/setup their "sinks" and/or their logging "levels" at any time, without requiring any new build/deploys. For example, something weird is going on, you could just edit the azure app settings "env vars"/configuration settings and mod the logging level for a specific class or just in general (i.e. all logging is now Debug, not Info) .. etc.

Would you be interested in this?

Deploy to *somewhere*

You mentioned on Twitter that it'd be interesting to showcase deployment to somewhere.

I'll gladly take a stab at setting it up on Azure, given I can find cheap hosting options.

Would that be of interest? ๐Ÿ˜ƒ

Docker Integration

Hi David, loved the standup about the minimal web api. It was really good.

How can you take the minimal webapi and put and run it in a Docker container? I tried it but get an error

#16 1.573 Microsoft (R) Build Engine version 17.0.0-preview-21378-03+d592862ed for .NET
#16 1.573 Copyright (C) Microsoft Corporation. All rights reserved.
#16 1.573
#16 3.747 Determining projects to restore...
#16 4.436 All projects are up-to-date for restore.
#16 4.740 You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
#16 10.34 CSC : error CS5001: Program does not contain a static 'Main' method suitable for an entry point [/src/tradehelperapi/TradeHelper.Api.csproj]
#16 11.24
#16 11.24 Build FAILED.
#16 11.24
#16 11.24 CSC : error CS5001: Program does not contain a static 'Main' method suitable for an entry point [/src/tradehelperapi/TradeHelper.Api.csproj]
#16 11.24 0 Warning(s)
#16 11.24 1 Error(s)
#16 11.24
#16 11.24 Time Elapsed 00:00:09.39

Below is my Docker FIle

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["TradeHelper.Api/TradeHelper.Api.csproj", "tradehelperapi/"]
RUN dotnet restore "tradehelperapi/TradeHelper.Api.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "tradehelperapi/TradeHelper.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "tradehelperapi/TradeHelper.Api.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TradeHelper.Api.dll"]

dotnet ef command fails

Attempting to follow the getting started instructions on linux (Ubuntu 2204). dotnet EF command is reported as being installed but not working correctly:

โžœ  TodoApi git:(main) dotnet --version
7.0.100
โžœ  TodoApi git:(main) dotnet tool install dotnet-ef -g
Tool 'dotnet-ef' is already installed.
โžœ  TodoApi git:(main) dotnet ef
Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET program, but dotnet-ef does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.
โžœ  TodoApi git:(main)

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.