Giter Club home page Giter Club logo

job-finder-go's Introduction

Go job finder


A REST API that allows registering as users and employers, where both account types have access to different endpoints and are allowed to perform different actions (e.g. only employers can create job offers, and only users can create job applications). Search functionality is implemented both with Postgres and Elasticsearch (depending on search complexity). Redis is used to perform tasks in the background such as sending verification or confirmation emails.


Built in Go 1.20

The app uses:


Getting started

  1. Clone the repository
  2. Go to the project's root directory
  3. Rename app.env.example to app.env and replace the values
  4. Install golang-migrate
  5. Run in your terminal:
    • docker-compose up to run the containers
    • make migrate_up to run migrations
    • make runserver load_data=true to run the HTTP server with sample jobs, employers, and companies loaded into both PostgreSQL and Elasticsearch. Set load_data to false if you do not want test data to be loaded.
  6. Now everything should be ready and server running on SERVER_ADDRESS specified in app.env

Testing

  1. Run the containers (docker-compose up)

  2. Run in your terminal:

    • make test to run all tests

    or

    • make test_coverage p={PATH} - to get the coverage in the HTML format - where {PATH} is the path to the target directory for which you want to generate test coverage. The {PATH} should be replaced with the actual path you want to use. For example ./internal/api

    or

    • use standard go test commands (e.g. go test -v ./internal/api)

Database

The database's schema and intricate details can be found on dedicated webpage, which provides a comprehensive overview of the data structure, tables, relationships, and other essential information. To explore the database further, please visit this dbdocs.io webpage Password: jobsearchsecret


API endpoints

This API provides a set of endpoints for managing:

  • users
  • employers
  • jobs
  • job applications

(and indirectly: user skills, job skills and verify emails tables)

After running the server, the Swagger documentation is available at http://localhost:8080/swagger/index.html. You can find there detailed information about the API endpoints, including their parameters, request and response formats, and examples. You can use the Swagger UI to test the API endpoints and see their responses in real-time.

The base path for all endpoints is /api/v1

so for example /api/v1/users/login

Here is a summary of the available endpoints and their functionality:

Users

  • POST /users: This endpoint creates a new user. The request body must contain the user details in JSON format. On success, the response has a 201 Created status code and returns the created user in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. If a user with the given email already exists, a 403 Forbidden status code is returned. In case of any other error, a 500 Internal Server Error status code is returned. After registering, a verification email is sent to the provided email address.

  • GET /users/send-verification-email: This endpoint sends an email to the user with a link that should be used to verify their email address. The request must contain the user’s email as a query parameter. On success, the response has a 200 OK status code and returns the result in JSON format. If the email is invalid, a 400 Bad Request status code is returned. If no user is found with the provided email, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /users/verify-email: This endpoint verifies a user’s email by providing a verify email ID and secret code that should be sent to the user in the verification email. The request body must contain the verify email ID and secret code as query parameters. On success, the response has a 200 OK status code and returns the verification result in JSON format. If the request query is invalid, a 400 Bad Request status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • POST /users/login: This endpoint logs in a user. The request body must contain the user credentials (email, password) in JSON format. On success, the response has a 200 OK status code and returns an access token and the authenticated user in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. If the password is incorrect, a 401 Unauthorized status code is returned. If user has not verified email, 403 Forbidden is returned. If a user with the given email does not exist, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /users: This endpoint retrieves the details of the logged-in user. On success, the response has a 200 OK status code and returns the user details in JSON format. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /users/employer-company-details/{email}: This endpoint retrieves the employer and company details. It does not require authentication. The response is in JSON format and has a 200 OK status code on success. If the email in the URI is invalid, a 400 Bad Request status code is returned. If the employer with the given email does not exist, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /users: This endpoint updates the details of the logged-in user. The request body must contain the updated user details in JSON format. On success, the response has a 200 OK status code and returns the updated user in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /users/password: This endpoint updates the password of the logged-in user. The request body must contain the old and new password in JSON format. On success, the response has a 200 OK status code and returns a success message. If the request body is invalid, a 400 Bad Request status code is returned. If the old password is incorrect or the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • DELETE /users: This endpoint deletes the logged-in user. On success, the response has a 204 No Content status code. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned.In case of any other error, a 500 Internal Server Error status code is returned.

Employers

  • POST /employers: This endpoint creates a new employer. The request body must contain the employer and company details in JSON format. On success, the response has a 201 Created status code and returns the created employer in JSON format. If the request body is invalid, a 400 status code is returned. If a company with the given name or an employer with the given email already exists, a 403 Forbidden status code is returned. In case of any other error, a 500 Internal Error status code is returned. After registering, a verification email is sent to the provided email address.

  • GET /employers/send-verification-email: This endpoint sends an email to the employer with a link that should be used to verify their email address. The request must contain the employer’s email as a query parameter. On success, the response has a 200 OK status code and returns the result in JSON format. If the email is invalid, a 400 Bad Request status code is returned. If no employer is found with the provided email, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /employers/verify-email: This endpoint verifies an employer’s email by providing a verify email ID and secret code that should be sent to the user in the verification email. The request body must contain the verify email ID and secret code as query parameters. On success, the response has a 200 OK status code and returns the verification result in JSON format. If the request query is invalid, a 400 Bad Request status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • POST /employers/login: This endpoint logs in an employer. The request body must contain the employer credentials (email, password) in JSON format. On success, the response has a 200 OK status code and returns an access token and the authenticated employer in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. If the password is incorrect, a 401 Unauthorized status code is returned. If the emails is not verified, a 403 Forbidden is returned. If an employer with the given email or a company with the given id does not exist, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /employers: This endpoint retrieves the details of the authenticated employer. The response is in JSON format and has a 200 OK status code on success. If the employer is not authorized (does not have an account or is a user, not employer), a 401 Unauthorized status code is returned. In case of an any other error, a 500 Internal Server Error status code is returned.

  • GET /employers/user-details/{email}: This endpoint retrieves the details of a user as an employer. The response is in JSON format and has a 200 OK status code on success. If the email in the URI is invalid, a 400 Bad Request status code is returned. If the employer is not authorized (does not have an account or is not an employer), a 401 Unauthorized status code is returned. If the user with the given email does not exist, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /employers: This endpoint updates the details of the authenticated employer. The request body must contain the updated employer details in JSON format. On success, the response has a 200 OK status code and returns the updated employer in JSON format. If the employer is not authorized (does not have an account or is a user, not employer), a 401 Unauthorized status code is returned.In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /employers/password: This endpoint updates the password of the logged-in employer. The request body must contain the old and new password in JSON format. On success, the response has a 200 OK status code and returns a success message. If the request body is invalid, a 400 Bad Request status code is returned. If the old password is incorrect or the employer is not authorized (does not have an account or is a user, not employer), a , a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • DELETE /employers: This endpoint deletes the logged-in employer. On success, the response has a 204 No Content status code. If the employer is not authorized (does not have an account or is a user, not employer), a 401 Unauthorized status code is returned.In case of any other error, a 500 Internal Server Error status code is returned.

Jobs

  • POST /jobs: This endpoint creates a new job. The request body must contain the job details in JSON format. On success, the response has a 201 Created status code and returns the created job in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /jobs/search: This endpoint searches for jobs with elasticsearch. The request must contain the page, page_size, and search parameters in the query. On success, the response has a 200 OK status code and returns an array of jobs that match the search query in JSON format. If the query is invalid, a 400 Bad Request status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /jobs: This endpoint filters and lists jobs based on the provided query parameters. The page and page_size query parameters are required and specify the page number and page size, respectively. The title, industry, job_location, salary_min, and salary_max query parameters are optional and can be used to filter the jobs by title, industry, location, and salary range, respectively. On success, the response has a 200 OK status code and returns a list of jobs in JSON format. If the query is invalid, a 400 status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /jobs/company: This endpoint lists jobs by company name, id, or part of the name. The page and page_size query parameters are required and specify the page number and page size, respectively. The id, name, and name_contains query parameters are optional (one of them has to be provided) and can be used to filter the jobs by company id, exact company name, or part of the company name, respectively. Only one of these three parameters is allowed in a single request. On success, the response has a 200 OK status code and returns a list of jobs in JSON format. If the query is invalid, a 400 Bad Request status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /jobs/{id}: This endpoint retrieves the details of the job with the given id. The id path parameter is required and specifies the id of the job to retrieve. On success, the response has a 200 OK status code and returns the job details in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the job with the given id is not found, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /jobs/{id}: This endpoint updates the job with the given id. The id path parameter is required and specifies the id of the job to update. The request body must contain the updated job details in JSON format. On success, the response has a 200 OK status code and returns the updated job in JSON format. In case of any error, a 500 Internal Server Error status code is returned.

  • DELETE /jobs/{id}: This endpoint deletes the job with the given id. The id path parameter is required and specifies the id of the job to delete. On success, the response has a 204 No Content status code. In case the job is not found, returns 404 Not Found, in case of any other error, a 500 Internal Server Error status code is returned.

Job Applications

  • POST /job-applications: This endpoint creates a new job application. Only users can access this endpoint. The request must contain the CV file, job ID, and optionally message for the employer in multipart/form-data format. On success, the response has a 200 OK status code and returns the created job application details in JSON format. If the request body is invalid, a 400 Bad Request status code is returned. If the user is not authorized to access this endpoint, a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /job-applications/employer/{id}: This endpoint retrieves the details of the job application for an employer with the given id. The id path parameter is required and specifies the id of the job application to retrieve. On success, the response has a 200 OK status code and returns the job application details in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the employer is not authorized (does not have an account or is a user, not employer), a 401 Unauthorized status code is returned. If the employer is not part of the company that created the job this application is for, a 403 Forbidden status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /job-applications/employer/{id}/status: This endpoint changes the status of the job application with the given id. The id path parameter is required and specifies the id of the job application to update. The new_status body parameter is required and specifies the new status of the job application. On success, the response has a 200 OK status code and returns the updated job application details in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is a user, not employer), a 401 Unauthorized status code is returned. If the employer is not part of the company that created the job this application is for, a 403 Forbidden status code is returned. If the job application with the given id is not found, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /job-applications/employer: This endpoint lists the job applications for a job with a given ID. Only employers can access this endpoint. The results are paginated based on the page and page_size query parameters, which are both required. The sort query parameter is optional and can be used to sort the results by date in ascending or descending order. The status query parameter is also optional and can be used to filter the results by status ('Applied', 'Seen', 'Interviewing', 'Offered', 'Rejected'). On success, the response has a 200 OK status code and returns a list of job applications in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is not an employer), a 401 Unauthorized status code is returned. If the job does not exist, a 404 Not Found status is returned, and if the employer is not the owner of the job, 403 Forbidden is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /job-applications/user: This endpoint lists the job applications that the authenticated user created. The results are paginated based on the page and page_size query parameters, which are both required. The sort query parameter is optional and can be used to sort the results by date in ascending or descending order. The status query parameter is also optional and can be used to filter the results by status (‘Applied’, ‘Seen’, ‘Interviewing’, ‘Offered’, ‘Rejected’). On success, the response has a 200 OK status code and returns a list of job applications in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • GET /job-applications/user/{id}: This endpoint retrieves the details of the job application for a user. The id path parameter is required and specifies the id of the job application to retrieve. On success, the response has a 200 OK status code and returns the job application details in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is an employer, not user) , a 401 Unauthorized status code is returned. If the user is not the creator of this job application, a 403 Forbidden status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • PATCH /job-applications/user/{id}: This endpoint updates the details of the job application for a user. The id path parameter is required and specifies the id of the job application to update. The cv formData parameter is optional and specifies the CV file (.pdf) to update. The cv_provided formData parameter is required and specifies whether a CV file was provided. The message formData parameter is optional and specifies the message for the employer to update. On success, the response has a 200 OK status code and returns the updated job application details in JSON format. If the request query is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. If the user is not the creator of this job application, a 403 Forbidden status code is returned. If the job application with the given id is not found, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

  • DELETE /job-applications/user/{id}: This endpoint deletes the job application for a user. The id path parameter is required and specifies the id of the job application to delete. On success, the response has a 204 No Content status code. If the provided id is invalid, a 400 Bad Request code is returned. If the user is not authorized (does not have an account or is an employer, not user), a 401 Unauthorized status code is returned. If the user is not the creator of this job application, a 403 Forbidden status code is returned. If the job application with the given id is not found, a 404 Not Found status code is returned. In case of any other error, a 500 Internal Server Error status code is returned.

job-finder-go's People

Contributors

aalug avatar

Stargazers

 avatar

Watchers

 avatar  avatar

job-finder-go's Issues

Add update employer API

Add update employer API.
It should allow authenticated employers to update their account and company details.
Employers should be able to update all data except the password. It will be handled with a different endpoint.
Test the function.

Add get employer API

Add get employer API.
It should return information about the logged-in employer and it's company.
Test the function.

Add delete user API

Add delete user API.
It should allow users to delete their accounts.
First, delete all user skills, then delete the user that has made the request.

Add list jobs by company API

Add list jobs by company API.
Create a function to handle GET requests that returns a list of jobs created by a specific company.
Query params:

  • page (page number)
  • page_size (number of items per page)

and either:

  • id (company id)

or

  • name (company name)

or

  • name_contains (part of the company name)

The function should allow only one of those parameters and based on which one was provided call the appropriate database function.

Enhancing Job Creation Process with Elasticsearch Indexing

Enhancing Job Creation Process with Elasticsearch Indexing
Add functionality to createJob function for it to create jobs index afret new job is created.
To accomplish this, new esearch function will be required. It should create just one index for just one job.
Update function tests.

Restructure the project

Restructure the project.
Change the structure of the project to use the standard go project structure (cmd, internal, pkg).

Move:

  • api
  • db
  • esearch
  • config (create from config.go file from utils to allow utils to go to the pkg)

packages to the internal folder.

Move:

  • utils
  • token
  • validation

packages to the pkg folder.

Move the main.go file to cmd folder.

Update all imports and fix all bugs that were caused but these changes.

Add delete job API

Add delete job API.
Create a function to handle deleting a job posting.
The function should check if the employer making the request is the owner of the job - if not, 401 status should be returned.
Test the function.

Add delete employer API

Add delete employer API.
Add a function to handle DELETE requests and delete the employer's company and the employer itself.
Test the function.

Create SQL store and add transactions to handle multiple job and user skills

Create SQL store and add transactions to handle multiple job and user skills.
These functions should accept as arguments slices of data required to create a job skill and user skill, and using existing functions to create skills, create all of them.
Using sqlc add functions to delete multiple job and user skills and to delete all skills of a specific job.

Add get job application for user API

Add get job application for user API.
It should handle GET requests and return data specified for the user (already exists specific database db function) if the user is authenticated and is the applicant/ owner of the application.
For now, the cv will be in []byte format, later file server will be created and the cv hosted there.
Test the function.

Add search jobs API

Add search jobs API.
Create a function to handle GET requests with query parameters:

  • page (page number)
  • page_size (number of jobs per page)
  • search (search query that will be passed to the esearch.SearchJobs function)

Validate the query (all 3 parameters should be required).
Call the esearch.SearchJobs function with provided data.
Return received jobs in JSON format.

Add auth middleware

Add auth middleware that to protect routes.
It should check if the user is authenticated and if not - restrict from calling an endpoint.

Add create employer API

Add create employer API.
Create a function to handle POST requests to create an employer.
To create an employer, a company ID is required, so the request should contain information for both of those objects, and the function should create them both.

Add get job application for employer API

Add get job application for employer API.
It should handle GET requests and return data specified for the employer (already exists specific database function) if the employer is authenticated and is part of the company that owns this job posting (employer.CompanyID == companyID, where companyID was got by another db function that gets companyID by JobID)
For now, the cv will be in []byte format, later file server will be created and the cv hosted there.
Test the function.

Add get user API

Add get user API.
This is basic and quite uncomplicated function but its needed for example for getting profile details before updating.
Test the function.

Add update user API

Add update user API.
It should allow authenticated users to update their account details.
Users should be able to update all data except the password. It will be handled with a different endpoint.
Test the function.

Create function to search jobs using Elasticsearch

Create a function to search for jobs using Elasticsearch.

The function should take two parameters:

  • context
  • query string

It should perform elasticsearch search to get jobs with the same or similar:

  • title
  • description
  • requirements
  • skills
  • location

It should return a slice of jobs which later will be used to handle API requests.

Create job applications table and CRUD functions

Create job applications table and functions for handling CRUD operations.
This table should have job_id, user_id, message, and cv fields.
Every user should be allowed to create just one application for one job - create a unique constraint.
Using the sqlc generate functions to create, update, delete, get, and list jobs for employers and users (different details should be returned)
Test all functions.

Add automatic indexing of jobs

Add automatic indexing of jobs after job is created or updated.
Right now, indexes are created by calling one function that loads all jobs from the database and creates indexes. That is not very efficient. Create a function to index jobs after creation or update of a job object.
Add it to functions that handle API calls.

Add filter and list jobs API

Add filter and list jobs API.
Create a new SQL function to allow users to filter jobs by location, title, industry, and salary range.
It should all be done in one go.
Create a function to handle GET requests with query parameters (filters, page number, and page size).
Test the function.

Create CRUD for user_skills table

Generate functions for CRUD operations with sqlc for the user_skills table.
Test functions.
Update the job_test file, and test ListJobsMatchingUserSkills function (it required job_skills and user_skills to test it)

Add restrictions to deleting job skills

Add restrictions to deleting job skills.
Add to functions that delete job skills a check that will allow deleting of job skills only if the employer making the request is the author of these skills.

Modify CORS middleware

Modify CORS middleware to accept authorization headers.
The rest of the CORS config should remain the same.

Implement hashing passwords

Implement hashing passwords with bcrypt.
Create functions to:

  • hash password
  • check password (compare string passed as a password in a POST request to the hashed value in the database)

Add update user password API

Add update user password API.
Create a function to handle changing passwords.
The request body should contain:

  • old password
  • new password

The function has to check if the old password from the request body is the same as user.HashedPassword,
if it is, then new password should be hashed and set as as new password.

Add get job details API

Add get job details API.
Make changes to the GetJob query (function generated by sqlc) to select not only the job but also company and employer informations. This endpoint should receive in the url an id of a job and get all needed details.
This function should not return job skills - this sould be handled by another function to allow client to get paginated job skills.

Add list jobs by matching user skills API

Add list jobs by matching user skills API.
Create a function to handle GET requests with query parameters (page number and page size) that for authenticated users will return array of jobs that match their skills.
Test the function.

Setup elasticsearch

Setup elasticsearch, create:

  • elasticsearch docker container
  • function to load data from the database
  • function to connect to the elasticsearch server

Add create job API

The API should accept the job details and a list of required skills in the request.
Upon receiving the request, the job will be created in the database. Upon successful creation of the job, the necessary skills will be created and assigned to the newly created job.
Test the functionality of this API.

Add db init schema

Write an initial database schema in Postgres.
Use golang-migrate to run migrations.
This schema should contain tables such as:

  • users
  • jobs
  • companies
  • job_skills
  • user_skills

Add employers table

Create a new table called employers with columns such as:

  • id,
  • company_id,
  • full_name,
  • email,
  • hashed_password.

The company_id column would be a foreign key referencing the id column in the companies table. This would allow to associate an employer with a company.

Then add functionality to allow these employers to create jobs and job skills. This could involve inserting rows into the jobs and job_skills tables, respectively.

Implement user login

Implement user login:

  • create functions to create and validate a token
  • create an API to handle POST requests to login user
    The function should validate the input data, check password correctness, and get and return user details alongside the access token.

Add update job posting API

Add update job posting API.
Create a function to handle PATCH requests that updates job and job skills.
There should be validation that will allow only job owners to make changes in a job and check the validity of the request body (similarly to the function that creates the job).

Fix email validation

Fix validation.ValidateEmail function. For some reqson it says that email without a top-level domain (e.g. .com) is valid (e.g. test@example)
Test the function.

Add create job application API

Add create job application API.
It should handle receiving:

  • message (string, optional)
  • job_id (int32, required)
  • cv (multipart.File, required)

It should validate received data and if everything is valid, create db.JobApplication with default status - Applied.
Test the function.

Add update employer password API

Add update employer password API.
Create a function to handle changing employer passwords.
The request body should contain:

  • old password
  • new password

The function has to check if the old password from the request body is the same as employer.HashedPassword,
if it is, then new password should be hashed and set as as new password.

Handle job application unique constraint violation (userID, jobID)

Handle job application unique constraint violation (userID, jobID).
There is a unique constraint in the database not to allow creating job applications where the job_id and user_id pair already exist.
Add a check for this case in the createJobApplication handler.
Test this new functionality.

Add login employer API

Add login employer API.
It will look almost like login user API - the basic principle is the same (get employer, check the password, return details)

Add create user API

Add create user API.
It should handle POST requests and create users.
The function should validate data, hash the password, create a user, and create user_skills for the user.
Mock the store and test the function.

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.